Compare commits
No commits in common. "master" and "power_handler" have entirely different histories.
master
...
power_hand
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,5 +2,4 @@
|
||||
|
||||
/.idea/*
|
||||
!/.idea/runConfigurations
|
||||
output.log
|
||||
|
||||
|
2
.idea/runConfigurations/Cross_Remote_Debug.xml
generated
2
.idea/runConfigurations/Cross_Remote_Debug.xml
generated
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Cross Remote Debug" type="com.jetbrains.cidr.remote.gdbserver.type" factoryName="com.jetbrains.cidr.remote.gdbserver.factory" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="eurosim-obsw" TARGET_NAME="Cross" CONFIG_NAME="Cross" version="1" RUN_PATH="$PROJECT_DIR$/target/armv7-unknown-linux-gnueabihf/debug/eurosim-obsw">
|
||||
<custom-gdb-server version="1" gdb-connect="192.168.1.116:1234" executable="" warmup-ms="0" download-type="ALWAYS" sshConfigName="koesterl@192.168.1.116:22 password" uploadFile="/tmp/CLion/debug/eurosim-obsw" defaultGdbServerArgs=":1234 /tmp/CLion/debug/eurosim-obsw">
|
||||
<custom-gdb-server version="1" gdb-connect="obc.local:1234" executable="" warmup-ms="0" download-type="ALWAYS" sshConfigName="koesterl@obc.local:22 password" uploadFile="/tmp/CLion/debug/eurosim-obsw" defaultGdbServerArgs=":1234 /tmp/CLion/debug/eurosim-obsw">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
</custom-gdb-server>
|
||||
<method v="2">
|
||||
|
65
Cargo.lock
generated
65
Cargo.lock
generated
@ -288,7 +288,6 @@ dependencies = [
|
||||
name = "eurosim-obsw"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"embedded-can",
|
||||
"fern",
|
||||
@ -297,7 +296,6 @@ dependencies = [
|
||||
"num",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"num_enum",
|
||||
"satrs-core",
|
||||
"satrs-mib",
|
||||
"serde",
|
||||
@ -316,12 +314,6 @@ dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.1"
|
||||
@ -376,16 +368,6 @@ dependencies = [
|
||||
"cxx-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
@ -518,15 +500,6 @@ version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
||||
|
||||
[[package]]
|
||||
name = "nom8"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.0"
|
||||
@ -639,7 +612,6 @@ version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
@ -676,16 +648,6 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.47"
|
||||
@ -734,7 +696,6 @@ checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
|
||||
[[package]]
|
||||
name = "satrs-core"
|
||||
version = "0.1.0-alpha.0"
|
||||
source = "git+https://egit.irs.uni-stuttgart.de/rust/sat-rs.git?rev=c265e4c271#c265e4c2714b793c3853607c172d444467344aec"
|
||||
dependencies = [
|
||||
"bus",
|
||||
"crossbeam-channel",
|
||||
@ -742,9 +703,8 @@ dependencies = [
|
||||
"downcast-rs",
|
||||
"dyn-clone",
|
||||
"embed-doc-image",
|
||||
"hashbrown 0.13.1",
|
||||
"hashbrown",
|
||||
"num-traits",
|
||||
"num_enum",
|
||||
"paste",
|
||||
"serde",
|
||||
"spacepackets",
|
||||
@ -753,7 +713,6 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "satrs-mib"
|
||||
version = "0.1.0"
|
||||
source = "git+https://egit.irs.uni-stuttgart.de/rust/sat-rs.git?rev=c265e4c271#c265e4c2714b793c3853607c172d444467344aec"
|
||||
dependencies = [
|
||||
"csv",
|
||||
"satrs-core",
|
||||
@ -765,7 +724,6 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "satrs-mib-codegen"
|
||||
version = "0.1.0"
|
||||
source = "git+https://egit.irs.uni-stuttgart.de/rust/sat-rs.git?rev=c265e4c271#c265e4c2714b793c3853607c172d444467344aec"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -854,9 +812,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "spacepackets"
|
||||
version = "0.5.4"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9313bf066de3ae704ea83584fc65b62434249efe57ae2dcde3e2cffe4ba62648"
|
||||
checksum = "81541fd89a5bc02845a849895d6ed1721235b3eac26fc77010f0a05f53bc4e8a"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crc",
|
||||
@ -926,23 +884,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"nom8",
|
||||
"toml_datetime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.5"
|
||||
|
12
Cargo.toml
12
Cargo.toml
@ -1,12 +1,12 @@
|
||||
[package]
|
||||
name = "eurosim-obsw"
|
||||
version = "0.1.0"
|
||||
edition = "2023"
|
||||
edition = "2021"
|
||||
authors = ["Linus Köster <linus@koester-im-web.de>", "Robin Müller <muellerr@irs.uni-stuttgart.de>"]
|
||||
description = "EuroSim OBSW Implementation"
|
||||
homepage = "https://egit.irs.uni-stuttgart.de/rust/eurosim-obsw"
|
||||
repository = "https://egit.irs.uni-stuttgart.de/rust/eurosim-obsw"
|
||||
license = "Apache-2.0"
|
||||
# license = "Apache-2.0"
|
||||
categories = ["aerospace", "hardware-support", "embedded"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -26,8 +26,6 @@ strum_macros = "0.24"
|
||||
num = "0.4"
|
||||
num-derive = "0.3"
|
||||
num-traits = "0.2"
|
||||
byteorder = "1.4"
|
||||
num_enum = "0.5"
|
||||
|
||||
[dependencies.socketcan]
|
||||
git = "https://github.com/socketcan-rs/socketcan-rs.git"
|
||||
@ -39,12 +37,10 @@ optional = true
|
||||
#path = "../satrs-launchpad/spacepackets"
|
||||
|
||||
[dependencies.satrs-core]
|
||||
git = "https://egit.irs.uni-stuttgart.de/rust/sat-rs.git"
|
||||
rev = "c265e4c271"
|
||||
path = "../satrs-launchpad/satrs-core"
|
||||
|
||||
[dependencies.satrs-mib]
|
||||
git = "https://egit.irs.uni-stuttgart.de/rust/sat-rs.git"
|
||||
rev = "c265e4c271"
|
||||
path = "../satrs-launchpad/satrs-mib"
|
||||
|
||||
[features]
|
||||
default = ["can"]
|
||||
|
201
LICENSE-APACHE
201
LICENSE-APACHE
@ -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
2
NOTICE
@ -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.
|
@ -7,9 +7,6 @@ import sys
|
||||
import time
|
||||
from typing import Optional
|
||||
import datetime
|
||||
import json
|
||||
import pprint
|
||||
import struct
|
||||
|
||||
import tmtccmd
|
||||
from spacepackets.ecss import PusTelemetry, PusTelecommand, PusVerificator
|
||||
@ -18,7 +15,7 @@ from spacepackets.ecss.pus_1_verification import UnpackParams, Service1Tm
|
||||
from spacepackets.ccsds.time import CdsShortTimestamp
|
||||
|
||||
from tmtccmd import CcsdsTmtcBackend, TcHandlerBase, ProcedureParamsWrapper
|
||||
from tmtccmd.tc.pus_3_fsfw_hk import generate_one_hk_command, make_sid, create_enable_periodic_hk_command, create_disable_periodic_hk_command
|
||||
from tmtccmd.tc.pus_3_fsfw_hk import generate_one_hk_command, make_sid
|
||||
from tmtccmd.tc.pus_11_tc_sched import create_time_tagged_cmd
|
||||
from tmtccmd.core.base import BackendRequest
|
||||
from tmtccmd.pus import VerificationWrapper
|
||||
@ -57,7 +54,7 @@ from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
EXAMPLE_PUS_APID = 0x50
|
||||
EXAMPLE_PUS_APID = 0x02
|
||||
|
||||
|
||||
class SatRsConfigHook(HookBase):
|
||||
@ -97,8 +94,6 @@ class SatRsConfigHook(HookBase):
|
||||
)
|
||||
srv_3 = OpCodeEntry()
|
||||
srv_3.add(HkOpCodes.GENERATE_ONE_SHOT, "Generate AOCS one shot HK")
|
||||
srv_3.add(HkOpCodes.ENABLE_PERIODIC, "Enable Periodic AOCS HK")
|
||||
srv_3.add(HkOpCodes.DISABLE_PERIODIC, "Disable Periodic AOCS HK")
|
||||
defs.add_service(
|
||||
name=CoreServiceList.SERVICE_3,
|
||||
info="PUS Service 3 Housekeeping",
|
||||
@ -115,21 +110,11 @@ class SatRsConfigHook(HookBase):
|
||||
|
||||
srv_11 = OpCodeEntry()
|
||||
srv_11.add("0", "Scheduled TC Test")
|
||||
srv_11.add("1", "Scheduled Camera Request TC")
|
||||
defs.add_service(
|
||||
name=CoreServiceList.SERVICE_11,
|
||||
info="PUS Service 11 TC Scheduling",
|
||||
op_code_entry=srv_11,
|
||||
)
|
||||
|
||||
srv_200 = OpCodeEntry()
|
||||
srv_200.add("0", "AOCS Mode Idle")
|
||||
srv_200.add("1", "AOCS Mode On")
|
||||
defs.add_service(
|
||||
name = CoreServiceList.SERVICE_200,
|
||||
info="PUS Custom Service 200 Mode",
|
||||
op_code_entry=srv_200,
|
||||
)
|
||||
return defs
|
||||
|
||||
def perform_mode_operation(self, tmtc_backend: CcsdsTmtcBackend, mode: int):
|
||||
@ -166,7 +151,6 @@ class PusHandler(SpecificApidHandlerBase):
|
||||
service = tm_packet.service
|
||||
dedicated_handler = False
|
||||
if service == 1:
|
||||
_LOGGER.info(packet.hex(sep=","))
|
||||
tm_packet = Service1Tm.unpack(
|
||||
data=packet, params=UnpackParams(CdsShortTimestamp.empty(), 1, 2)
|
||||
)
|
||||
@ -184,28 +168,17 @@ class PusHandler(SpecificApidHandlerBase):
|
||||
self.verif_wrapper.log_to_file(tm_packet, res)
|
||||
dedicated_handler = True
|
||||
if service == 3:
|
||||
# _LOGGER.info("No handling for HK packets implemented")
|
||||
# _LOGGER.info(f"Raw packet: 0x[{packet.hex(sep=',')}]")
|
||||
_LOGGER.info("No handling for HK packets implemented")
|
||||
_LOGGER.info(f"Raw packet: 0x[{packet.hex(sep=',')}]")
|
||||
pus_tm = PusTelemetry.unpack(packet, time_reader=CdsShortTimestamp.empty())
|
||||
if pus_tm.subservice == 25:
|
||||
if len(pus_tm.source_data) < 8:
|
||||
raise ValueError("No addressable ID in HK packet")
|
||||
#json_str = str(pus_tm.source_data[8:].decode('utf8'))
|
||||
#json_object = json.loads(json_str)
|
||||
#pprint.pprint(json_object)
|
||||
print(pus_tm.tm_data.hex())
|
||||
i = 8
|
||||
print(struct.unpack('d', pus_tm.tm_data[8:16]))
|
||||
|
||||
while i < len(pus_tm.tm_data):
|
||||
print(pus_tm.tm_data[i:i+8].hex())
|
||||
print(struct.unpack('d', pus_tm.tm_data[i:i+8]))
|
||||
i += 8
|
||||
json_str = pus_tm.source_data[8:]
|
||||
dedicated_handler = True
|
||||
if service == 5:
|
||||
tm_packet = Service5Tm.unpack(packet, time_reader=CdsShortTimestamp.empty())
|
||||
if service == 17:
|
||||
_LOGGER.info(packet.hex(sep=","))
|
||||
tm_packet = Service17Tm.unpack(
|
||||
packet, time_reader=CdsShortTimestamp.empty()
|
||||
)
|
||||
@ -245,16 +218,10 @@ def read_addressable_id(data: bytes) -> tuple[int, int]:
|
||||
return (target_id, set_id)
|
||||
|
||||
|
||||
class CustomServiceList(enum.StrEnum):
|
||||
ACS = "acs"
|
||||
|
||||
class RequestTargetId(enum.IntEnum):
|
||||
ACS = 1
|
||||
PLD = 2
|
||||
|
||||
class RequestuniqueId(enum.IntEnum):
|
||||
MGM_VOLTAGE_1 = 1
|
||||
|
||||
|
||||
class AcsHkIds(enum.IntEnum):
|
||||
MGM_SET = 1
|
||||
@ -262,19 +229,12 @@ class AcsHkIds(enum.IntEnum):
|
||||
|
||||
class HkOpCodes:
|
||||
GENERATE_ONE_SHOT = ["0", "oneshot"]
|
||||
ENABLE_PERIODIC = ["1", "enable periodic"]
|
||||
DISABLE_PERIODIC = ["2", "disable periodic"]
|
||||
|
||||
|
||||
|
||||
def make_target_id(target_id: int) -> bytes:
|
||||
byte_string = bytearray(struct.pack("!I", target_id))
|
||||
return byte_string
|
||||
|
||||
def make_mode_submode(mode: int, submode: int) -> bytes:
|
||||
byte_string = bytearray(struct.pack("!I", mode))
|
||||
byte_string.extend(struct.pack("!I", submode))
|
||||
return byte_string
|
||||
|
||||
class TcHandler(TcHandlerBase):
|
||||
def __init__(
|
||||
@ -300,7 +260,6 @@ class TcHandler(TcHandlerBase):
|
||||
pus_tc_wrapper = entry_helper.to_pus_tc_entry()
|
||||
raw_tc = pus_tc_wrapper.pus_tc.pack()
|
||||
_LOGGER.info(f"Sending {pus_tc_wrapper.pus_tc}")
|
||||
_LOGGER.info(f"raw data: {pus_tc_wrapper.pus_tc.app_data}")
|
||||
send_params.com_if.send(raw_tc)
|
||||
elif entry_helper.entry_type == TcQueueEntryType.LOG:
|
||||
log_entry = entry_helper.to_log_entry()
|
||||
@ -321,77 +280,37 @@ class TcHandler(TcHandlerBase):
|
||||
def_proc = helper.to_def_procedure()
|
||||
service = def_proc.service
|
||||
op_code = def_proc.op_code
|
||||
if service == CoreServiceList.SERVICE_200:
|
||||
q.add_log_cmd("Sending PUS Mode Request telecommand")
|
||||
if op_code == "0":
|
||||
tc = PusTelecommand(service=200, subservice=1, app_data=make_mode_submode(0,0), apid=0x50)
|
||||
return q.add_pus_tc(tc)
|
||||
if op_code == "1":
|
||||
tc = PusTelecommand(service=200, subservice=1, app_data=make_mode_submode(1,0), apid=0x50)
|
||||
return q.add_pus_tc(tc)
|
||||
|
||||
if (
|
||||
service == CoreServiceList.SERVICE_17
|
||||
or service == CoreServiceList.SERVICE_17_ALT
|
||||
):
|
||||
q.add_log_cmd("Sending PUS ping telecommand")
|
||||
tc = PusTelecommand(service=17, subservice=1)
|
||||
_LOGGER.info(tc.pack().hex(sep=","))
|
||||
return q.add_pus_tc(PusTelecommand(service=17, subservice=1))
|
||||
if service == CustomServiceList.ACS:
|
||||
if op_code == "set_mode":
|
||||
q.add_log_cmd()
|
||||
q.add_pus_tc()
|
||||
if service == CoreServiceList.SERVICE_11:
|
||||
if op_code == "0":
|
||||
q.add_log_cmd("Sending PUS scheduled TC telecommand")
|
||||
crt_time = CdsShortTimestamp.from_now()
|
||||
time_stamp = crt_time + datetime.timedelta(seconds=10)
|
||||
time_stamp = time_stamp.pack()
|
||||
return q.add_pus_tc(
|
||||
create_time_tagged_cmd(
|
||||
time_stamp,
|
||||
PusTelecommand(service=17, subservice=1),
|
||||
apid=EXAMPLE_PUS_APID,
|
||||
)
|
||||
)
|
||||
if op_code == "1":
|
||||
q.add_log_cmd("Sending PUS scheduled TC telecommand")
|
||||
crt_time = CdsShortTimestamp.from_now()
|
||||
time_stamp = crt_time + datetime.timedelta(seconds=10)
|
||||
time_stamp = time_stamp.pack()
|
||||
return q.add_pus_tc(
|
||||
create_time_tagged_cmd(
|
||||
time_stamp,
|
||||
PusTelecommand(service=8, subservice=1, app_data=make_target_id(RequestTargetId.PLD)),
|
||||
apid=EXAMPLE_PUS_APID,
|
||||
)
|
||||
q.add_log_cmd("Sending PUS scheduled TC telecommand")
|
||||
crt_time = CdsShortTimestamp.from_now()
|
||||
time_stamp = crt_time + datetime.timedelta(seconds=10)
|
||||
time_stamp = time_stamp.pack()
|
||||
return q.add_pus_tc(
|
||||
create_time_tagged_cmd(
|
||||
time_stamp,
|
||||
PusTelecommand(service=17, subservice=1),
|
||||
apid=EXAMPLE_PUS_APID,
|
||||
)
|
||||
)
|
||||
if service == CoreServiceList.SERVICE_8:
|
||||
q.add_log_cmd("Sending PUS action request telecommand")
|
||||
return q.add_pus_tc(
|
||||
PusTelecommand(service=8, subservice=1, app_data=make_target_id(RequestTargetId.PLD), apid=0x030)
|
||||
PusTelecommand(service=8, subservice=1, app_data=make_target_id(RequestTargetId.PLD))
|
||||
)
|
||||
if service == CoreServiceList.SERVICE_3:
|
||||
if op_code in HkOpCodes.GENERATE_ONE_SHOT:
|
||||
q.add_log_cmd("Sending HK one shot request")
|
||||
tc = generate_one_hk_command(make_addressable_id(RequestuniqueId.MGM_VOLTAGE_1, AcsHkIds.MGM_SET))
|
||||
q.add_log_cmd(tc)
|
||||
q.add_pus_tc(
|
||||
generate_one_hk_command(
|
||||
make_addressable_id(RequestTargetId.ACS, AcsHkIds.MGM_SET)
|
||||
)
|
||||
)
|
||||
if op_code in HkOpCodes.ENABLE_PERIODIC:
|
||||
q.add_log_cmd("Sending periodic HK request")
|
||||
tc = create_enable_periodic_hk_command(False, make_addressable_id(RequestTargetId.ACS, AcsHkIds.MGM_SET))
|
||||
q.add_log_cmd(tc)
|
||||
q.add_pus_tc(tc)
|
||||
if op_code in HkOpCodes.DISABLE_PERIODIC:
|
||||
q.add_log_cmd("Sending periodic HK request")
|
||||
tc = create_disable_periodic_hk_command(False, make_addressable_id(RequestTargetId.ACS, AcsHkIds.MGM_SET))
|
||||
q.add_log_cmd(tc)
|
||||
q.add_pus_tc(tc)
|
||||
pass
|
||||
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
{
|
||||
"com_if": "udp",
|
||||
"tcpip_udp_ip_addr": "192.168.1.116",
|
||||
"tcpip_udp_ip_addr_pc": "192.168.56.1",
|
||||
"tcpip_udp_ip_addr": "169.254.7.6",
|
||||
"tcpip_udp_port": 7301,
|
||||
"tcpip_udp_recv_max_size": 1500
|
||||
}
|
975
src/aocs.rs
975
src/aocs.rs
@ -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() {}
|
||||
|
144
src/can.rs
144
src/can.rs
@ -1,21 +1,31 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use crate::pcdu::DeviceState;
|
||||
|
||||
use crate::can_ids::{
|
||||
can_id_to_message_id, message_id_to_can_id, DeviceId, MessageId, MessageModel,
|
||||
SenderReceiverApid, SenderReceiverThread, ThreadId,
|
||||
can_id_to_package_id, package_id_to_can_id, value_to_package_id, DeviceId, PackageId,
|
||||
PackageModel, SenderReceiverThread, ThreadId,
|
||||
};
|
||||
use embedded_can::{self, Frame};
|
||||
use log::{debug, warn};
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json;
|
||||
use socketcan::{errors, frame, socket, CanFrame, Socket};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::c_void;
|
||||
use std::io;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use std::mem::size_of;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
pub struct CanRxHandler {
|
||||
interface: &'static str,
|
||||
socket: socket::CanSocket,
|
||||
//frame_id_to_sender_id: HashMap<embedded_can::Id, u32>, // double hash map: frame id -> receiver id -> sender handle
|
||||
can_senders: HashMap<u16, Sender<MessageModel>>,
|
||||
can_senders: HashMap<ThreadId, Sender<PackageModel>>,
|
||||
//dismissed_ids: Vec<embedded_can::Id>,
|
||||
message_map: HashMap<MessageId, SenderReceiverApid>,
|
||||
package_map: HashMap<PackageId, SenderReceiverThread>,
|
||||
//packet_id_to_sender_id: HashMap<PackageId, ThreadId>,
|
||||
}
|
||||
|
||||
@ -23,8 +33,8 @@ impl CanRxHandler {
|
||||
pub fn new_socket(
|
||||
interface: &'static str,
|
||||
//frame_id_to_sender_id: HashMap<embedded_can::Id, u32>,
|
||||
can_senders: HashMap<u16, Sender<MessageModel>>,
|
||||
message_map: HashMap<MessageId, SenderReceiverApid>,
|
||||
can_senders: HashMap<ThreadId, Sender<PackageModel>>,
|
||||
package_map: HashMap<PackageId, SenderReceiverThread>,
|
||||
) -> Result<CanRxHandler, ()> {
|
||||
let socket = socket::CanSocket::open(&interface);
|
||||
if let Ok(socket) = socket {
|
||||
@ -32,18 +42,28 @@ impl CanRxHandler {
|
||||
interface,
|
||||
socket,
|
||||
can_senders,
|
||||
message_map,
|
||||
package_map,
|
||||
})
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_incoming(&mut self) {
|
||||
if let Some(frame) = self.rx_socket() {
|
||||
self.forward_frame(frame);
|
||||
/*
|
||||
pub fn new_socket_with_filter(
|
||||
interface: &'static str,
|
||||
can_id_to_sender_id: HashMap<embedded_can::Id, u32>,
|
||||
can_senders: HashMap<u32, Sender<Vec<u8>>>,
|
||||
can_filters: &[socket::CanFilter],
|
||||
) -> Result<CanRxHandler, ()> {
|
||||
let can_wrapper = Self::new_socket(interface, can_id_to_sender_id, can_senders)?;
|
||||
let filter_result = can_wrapper.socket.set_filters(can_filters);
|
||||
if let Err(e) = filter_result {
|
||||
warn!("Can Bus set filter error: {}", e);
|
||||
}
|
||||
Ok(can_wrapper)
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn read_frame(&self) -> io::Result<frame::CanFrame> {
|
||||
let frame = self.socket.read_frame();
|
||||
@ -55,97 +75,51 @@ impl CanRxHandler {
|
||||
|
||||
pub fn rx_socket(&self) -> Option<CanFrame> {
|
||||
let frame = self.socket.read_frame().ok()?;
|
||||
debug!("Can Frame read: {:?}.", frame);
|
||||
info!("Can Frame read: {:?}.", frame);
|
||||
return Some(frame);
|
||||
/*
|
||||
if let Ok(frame) = frame {
|
||||
println!("Frame received: {:?}", frame);
|
||||
return Some(frame);
|
||||
}
|
||||
None
|
||||
*/
|
||||
}
|
||||
|
||||
pub fn forward_frame(&self, frame: CanFrame) {
|
||||
let frame_id = can_id_to_message_id(frame.id());
|
||||
debug!("Frame forwarding with id: {:?}", frame_id);
|
||||
let frame_id = can_id_to_package_id(frame.id());
|
||||
info!("Frame forwarding with id: {:?}", frame_id);
|
||||
if let Some(frame_id) = frame_id {
|
||||
if self.message_map.contains_key(&frame_id) {
|
||||
let value = self.message_map.get(&frame_id).unwrap();
|
||||
if self.package_map.contains_key(&frame_id) {
|
||||
let value = self.package_map.get(&frame_id).unwrap();
|
||||
if value.get_sender() != DeviceId::OBC {
|
||||
let message_sender = self.can_senders.get(&value.get_apid()).unwrap();
|
||||
let message_sender = self.can_senders.get(&value.get_thread()).unwrap();
|
||||
let data = frame.data();
|
||||
let message =
|
||||
MessageModel::new(frame_id, data).expect("Error generating message.");
|
||||
PackageModel::new(frame_id, data).expect("Error generating message.");
|
||||
message_sender.send(message).expect(&*format!(
|
||||
"Failure sending can bus frame to thread{:?}, frame id {:?}",
|
||||
value.get_apid(),
|
||||
value.get_thread(),
|
||||
frame_id
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn set_filter(&self, filters: &[socket::CanFilter]) -> io::Result<()> {
|
||||
info!("Setting filter with filter {:?}", filters);
|
||||
let result = self.socket.set_filters(filters);
|
||||
if let Err(e) = result {
|
||||
warn!("Can bus socket filter set error: {}", e);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
pub struct CanTxHandler {
|
||||
interface: &'static str,
|
||||
socket: socket::CanSocket,
|
||||
message_map: HashMap<MessageId, SenderReceiverApid>,
|
||||
message_receiver: Receiver<MessageModel>,
|
||||
}
|
||||
|
||||
impl CanTxHandler {
|
||||
pub fn new_socket(
|
||||
interface: &'static str,
|
||||
message_map: HashMap<MessageId, SenderReceiverApid>,
|
||||
message_receiver: Receiver<MessageModel>,
|
||||
) -> Result<CanTxHandler, ()> {
|
||||
let socket = socket::CanSocket::open(&interface);
|
||||
|
||||
if let Ok(socket) = socket {
|
||||
socket.filter_drop_all().unwrap(); // tx nodes cannot receive data
|
||||
Ok(CanTxHandler {
|
||||
interface,
|
||||
socket,
|
||||
message_map,
|
||||
message_receiver,
|
||||
})
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_incoming(&mut self) {
|
||||
if let Ok(message) = self.message_receiver.recv() {
|
||||
self.tx_socket(message.message_id(), message.data());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tx_socket(&self, message_id: MessageId, data: &[u8]) {
|
||||
if self.message_map.contains_key(&message_id) {
|
||||
let value = self.message_map.get(&message_id).unwrap();
|
||||
if value.get_sender() == DeviceId::OBC {
|
||||
if data.len() <= 8 {
|
||||
let frame_id = message_id_to_can_id(&message_id);
|
||||
let frame = CanFrame::new(frame_id, data);
|
||||
if let Some(frame) = frame {
|
||||
self.socket
|
||||
.write_frame(&frame)
|
||||
.expect("Error writing frame.");
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"Message dismissed, data length ({:?}) exceeds 8 bytes",
|
||||
data.len()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"Message dismissed, wrong sender id: {:?}",
|
||||
value.get_sender()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
warn!("Message dismissed, wrong package id: {:?}", message_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*pub struct CanTxHandler {
|
||||
interface: &'static str,
|
||||
socket: socket::CanSocket,
|
||||
thread_id: ThreadId,
|
||||
@ -239,8 +213,6 @@ impl CanTxHandler {
|
||||
*/
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
pub fn open_socket(interface: &str) -> Result<socket::CanSocket, errors::CanSocketOpenError> {
|
||||
let socket = socket::CanSocket::open(&interface);
|
||||
return socket;
|
||||
|
196
src/can_ids.rs
196
src/can_ids.rs
@ -2,7 +2,6 @@ use embedded_can::{Id, StandardId};
|
||||
use log::warn;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::tmtc::{CSS_APID, GPS_APID, MGM_APID, MGT_APID, PLD_APID, PWR_APID, RWL_APID, STR_APID};
|
||||
pub use num_derive::{FromPrimitive, ToPrimitive};
|
||||
pub use num_traits::{FromPrimitive, ToPrimitive};
|
||||
pub use strum::IntoEnumIterator; // 0.17.1
|
||||
@ -17,7 +16,7 @@ pub enum ThreadId {
|
||||
}
|
||||
|
||||
#[derive(Debug, EnumIter, Eq, Hash, PartialEq, Copy, Clone, FromPrimitive)]
|
||||
pub enum MessageId {
|
||||
pub enum PackageId {
|
||||
PCDUStatusRequest = 10,
|
||||
DevicePowerOnRequest = 11,
|
||||
DevicePowerOffRequest = 12,
|
||||
@ -47,7 +46,6 @@ pub enum MessageId {
|
||||
AOCSDataRequestSunSensor5 = 49,
|
||||
AOCSDataRequestSunSensor6 = 50,
|
||||
AOCSDataRequestStarTracker = 51,
|
||||
AOCSDataRequestGPS = 55,
|
||||
AOCSDataMGM1 = 61,
|
||||
AOCSDataMGM2 = 62,
|
||||
AOCSDataMGM3 = 63,
|
||||
@ -58,13 +56,7 @@ pub enum MessageId {
|
||||
AOCSDataSunSensor4 = 68,
|
||||
AOCSDataSunSensor5 = 69,
|
||||
AOCSDataSunSensor6 = 70,
|
||||
AOCSDataStarTracker1 = 71,
|
||||
AOCSDataStarTracker2 = 72,
|
||||
AOCSDataStarTracker3 = 73,
|
||||
AOCSDataStarTracker4 = 74,
|
||||
AOCSDataGPSLatitude = 81,
|
||||
AOCSDataGPSLongitude = 82,
|
||||
AOCSDataGPSAltitude = 83,
|
||||
AOCSDataStarTracker = 71,
|
||||
CameraImageRequest = 101,
|
||||
CameraImageRequestConfirmation = 102,
|
||||
CameraImageExecutionStart = 103,
|
||||
@ -96,7 +88,6 @@ pub enum DeviceId {
|
||||
RWL4 = 21,
|
||||
Camera = 22,
|
||||
All = 23,
|
||||
GPS = 24,
|
||||
}
|
||||
|
||||
impl TryFrom<u16> for DeviceId {
|
||||
@ -104,56 +95,55 @@ impl TryFrom<u16> for DeviceId {
|
||||
|
||||
fn try_from(v: u16) -> Result<Self, Self::Error> {
|
||||
match v {
|
||||
x if x == DeviceId::OBC as u16 => Ok(DeviceId::OBC),
|
||||
x if x == DeviceId::PCDU as u16 => Ok(DeviceId::PCDU),
|
||||
x if x == DeviceId::MGM1 as u16 => Ok(DeviceId::MGM1),
|
||||
x if x == DeviceId::MGM2 as u16 => Ok(DeviceId::MGM2),
|
||||
x if x == DeviceId::MGM3 as u16 => Ok(DeviceId::MGM3),
|
||||
x if x == DeviceId::MGM4 as u16 => Ok(DeviceId::MGM4),
|
||||
x if x == DeviceId::SunSensor1 as u16 => Ok(DeviceId::SunSensor1),
|
||||
x if x == DeviceId::SunSensor2 as u16 => Ok(DeviceId::SunSensor2),
|
||||
x if x == DeviceId::SunSensor3 as u16 => Ok(DeviceId::SunSensor3),
|
||||
x if x == DeviceId::SunSensor4 as u16 => Ok(DeviceId::SunSensor4),
|
||||
x if x == DeviceId::SunSensor5 as u16 => Ok(DeviceId::SunSensor5),
|
||||
x if x == DeviceId::SunSensor6 as u16 => Ok(DeviceId::SunSensor6),
|
||||
x if x == DeviceId::StarTracker as u16 => Ok(DeviceId::StarTracker),
|
||||
x if x == DeviceId::MGT1 as u16 => Ok(DeviceId::MGT1),
|
||||
x if x == DeviceId::MGT2 as u16 => Ok(DeviceId::MGT2),
|
||||
x if x == DeviceId::MGT3 as u16 => Ok(DeviceId::MGT3),
|
||||
x if x == DeviceId::MGT4 as u16 => Ok(DeviceId::MGT4),
|
||||
x if x == DeviceId::RWL1 as u16 => Ok(DeviceId::RWL1),
|
||||
x if x == DeviceId::RWL2 as u16 => Ok(DeviceId::RWL2),
|
||||
x if x == DeviceId::RWL3 as u16 => Ok(DeviceId::RWL3),
|
||||
x if x == DeviceId::RWL4 as u16 => Ok(DeviceId::RWL4),
|
||||
x if x == DeviceId::Camera as u16 => Ok(DeviceId::Camera),
|
||||
x if x == DeviceId::All as u16 => Ok(DeviceId::All),
|
||||
x if x == DeviceId::GPS as u16 => Ok(DeviceId::GPS),
|
||||
x if x==DeviceId::OBC as u16 => Ok(DeviceId::OBC),
|
||||
x if x==DeviceId::PCDU as u16 => Ok(DeviceId::PCDU),
|
||||
x if x==DeviceId::MGM1 as u16 => Ok(DeviceId::MGM1),
|
||||
x if x==DeviceId::MGM2 as u16 => Ok(DeviceId::MGM2),
|
||||
x if x==DeviceId::MGM3 as u16 => Ok(DeviceId::MGM3),
|
||||
x if x==DeviceId::MGM4 as u16 => Ok(DeviceId::MGM4),
|
||||
x if x==DeviceId::SunSensor1 as u16 => Ok(DeviceId::SunSensor1),
|
||||
x if x==DeviceId::SunSensor2 as u16 => Ok(DeviceId::SunSensor2),
|
||||
x if x==DeviceId::SunSensor3 as u16 => Ok(DeviceId::SunSensor3),
|
||||
x if x==DeviceId::SunSensor4 as u16 => Ok(DeviceId::SunSensor4),
|
||||
x if x==DeviceId::SunSensor5 as u16 => Ok(DeviceId::SunSensor5),
|
||||
x if x==DeviceId::SunSensor6 as u16 => Ok(DeviceId::SunSensor6),
|
||||
x if x==DeviceId::StarTracker as u16 => Ok(DeviceId::StarTracker),
|
||||
x if x==DeviceId::MGT1 as u16 => Ok(DeviceId::MGT1),
|
||||
x if x==DeviceId::MGT2 as u16 => Ok(DeviceId::MGT2),
|
||||
x if x==DeviceId::MGT3 as u16 => Ok(DeviceId::MGT3),
|
||||
x if x==DeviceId::MGT4 as u16 => Ok(DeviceId::MGT4),
|
||||
x if x==DeviceId::RWL1 as u16 => Ok(DeviceId::RWL1),
|
||||
x if x==DeviceId::RWL2 as u16 => Ok(DeviceId::RWL2),
|
||||
x if x==DeviceId::RWL3 as u16 => Ok(DeviceId::RWL3),
|
||||
x if x==DeviceId::RWL4 as u16 => Ok(DeviceId::RWL4),
|
||||
x if x==DeviceId::Camera as u16 => Ok(DeviceId::Camera),
|
||||
x if x==DeviceId::All as u16 => Ok(DeviceId::All),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MessageModel {
|
||||
message_id: MessageId,
|
||||
pub struct PackageModel {
|
||||
package_id: PackageId,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl MessageModel {
|
||||
pub fn new(message_id: MessageId, data: &[u8]) -> Result<MessageModel, ()> {
|
||||
impl PackageModel {
|
||||
pub fn new(package_id: PackageId, data: &[u8]) -> Result<PackageModel, ()> {
|
||||
if data.len() > 8 {
|
||||
warn!("Data exceeds maximum length.");
|
||||
return Err(());
|
||||
}
|
||||
let vec = Vec::from(data);
|
||||
return Ok(MessageModel {
|
||||
message_id,
|
||||
return Ok(PackageModel {
|
||||
package_id,
|
||||
data: vec,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn message_id(&self) -> MessageId {
|
||||
self.message_id
|
||||
pub fn package_id(&self) -> PackageId {
|
||||
self.package_id
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &Vec<u8> {
|
||||
@ -161,7 +151,6 @@ impl MessageModel {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO delete!!
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct SenderReceiverThread {
|
||||
sender: DeviceId,
|
||||
@ -189,8 +178,8 @@ impl SenderReceiverThread {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_message_id_to_threads() -> HashMap<MessageId, SenderReceiverThread> {
|
||||
let mut message_map: HashMap<MessageId, SenderReceiverThread> = HashMap::new();
|
||||
pub fn load_package_ids() -> HashMap<PackageId, SenderReceiverThread> {
|
||||
let mut package_map: HashMap<PackageId, SenderReceiverThread> = HashMap::new();
|
||||
|
||||
let properties = vec![
|
||||
SenderReceiverThread::new(DeviceId::OBC, DeviceId::PCDU, ThreadId::PowerThread),
|
||||
@ -222,7 +211,6 @@ pub fn load_message_id_to_threads() -> HashMap<MessageId, SenderReceiverThread>
|
||||
SenderReceiverThread::new(DeviceId::OBC, DeviceId::SunSensor5, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::OBC, DeviceId::SunSensor6, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::OBC, DeviceId::StarTracker, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::OBC, DeviceId::GPS, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::MGM1, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::MGM2, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::MGM3, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
@ -234,12 +222,6 @@ pub fn load_message_id_to_threads() -> HashMap<MessageId, SenderReceiverThread>
|
||||
SenderReceiverThread::new(DeviceId::SunSensor5, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::SunSensor6, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::StarTracker, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::StarTracker, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::StarTracker, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::StarTracker, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::GPS, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::GPS, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::GPS, DeviceId::OBC, ThreadId::AOCSThread),
|
||||
SenderReceiverThread::new(DeviceId::OBC, DeviceId::Camera, ThreadId::PLDThread),
|
||||
SenderReceiverThread::new(DeviceId::Camera, DeviceId::OBC, ThreadId::PLDThread),
|
||||
SenderReceiverThread::new(DeviceId::Camera, DeviceId::OBC, ThreadId::PLDThread),
|
||||
@ -247,107 +229,13 @@ pub fn load_message_id_to_threads() -> HashMap<MessageId, SenderReceiverThread>
|
||||
];
|
||||
|
||||
let mut i = 0;
|
||||
for id in MessageId::iter() {
|
||||
for id in PackageId::iter() {
|
||||
let value = properties.get(i).unwrap();
|
||||
message_map.insert(id, *value);
|
||||
package_map.insert(id, *value);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return message_map;
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct SenderReceiverApid {
|
||||
sender: DeviceId,
|
||||
receiver: DeviceId,
|
||||
apid: u16,
|
||||
}
|
||||
|
||||
impl SenderReceiverApid {
|
||||
pub fn new(sender: DeviceId, receiver: DeviceId, apid: u16) -> Self {
|
||||
Self {
|
||||
sender,
|
||||
receiver,
|
||||
apid,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_sender(&self) -> DeviceId {
|
||||
self.sender
|
||||
}
|
||||
pub fn get_receiver(&self) -> DeviceId {
|
||||
self.receiver
|
||||
}
|
||||
pub fn get_apid(&self) -> u16 {
|
||||
self.apid
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_message_id_to_apids() -> HashMap<MessageId, SenderReceiverApid> {
|
||||
let mut message_map: HashMap<MessageId, SenderReceiverApid> = HashMap::new();
|
||||
|
||||
let properties = vec![
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::PCDU, PWR_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::PCDU, PWR_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::PCDU, PWR_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::PCDU, PWR_APID),
|
||||
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
|
||||
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
|
||||
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
|
||||
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
|
||||
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
|
||||
SenderReceiverApid::new(DeviceId::PCDU, DeviceId::OBC, PWR_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGT1, MGT_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGT2, MGT_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGT3, MGT_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGT4, MGT_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::RWL1, RWL_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::RWL2, RWL_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::RWL3, RWL_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::RWL4, RWL_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGM1, MGM_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGM2, MGM_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGM3, MGM_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::MGM4, MGM_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor1, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor2, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor3, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor4, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor5, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::SunSensor6, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::StarTracker, STR_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::GPS, GPS_APID),
|
||||
SenderReceiverApid::new(DeviceId::MGM1, DeviceId::OBC, MGM_APID),
|
||||
SenderReceiverApid::new(DeviceId::MGM2, DeviceId::OBC, MGM_APID),
|
||||
SenderReceiverApid::new(DeviceId::MGM3, DeviceId::OBC, MGM_APID),
|
||||
SenderReceiverApid::new(DeviceId::MGM4, DeviceId::OBC, MGM_APID),
|
||||
SenderReceiverApid::new(DeviceId::SunSensor1, DeviceId::OBC, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::SunSensor2, DeviceId::OBC, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::SunSensor3, DeviceId::OBC, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::SunSensor4, DeviceId::OBC, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::SunSensor5, DeviceId::OBC, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::SunSensor6, DeviceId::OBC, CSS_APID),
|
||||
SenderReceiverApid::new(DeviceId::StarTracker, DeviceId::OBC, STR_APID),
|
||||
SenderReceiverApid::new(DeviceId::StarTracker, DeviceId::OBC, STR_APID),
|
||||
SenderReceiverApid::new(DeviceId::StarTracker, DeviceId::OBC, STR_APID),
|
||||
SenderReceiverApid::new(DeviceId::StarTracker, DeviceId::OBC, STR_APID),
|
||||
SenderReceiverApid::new(DeviceId::GPS, DeviceId::OBC, GPS_APID),
|
||||
SenderReceiverApid::new(DeviceId::GPS, DeviceId::OBC, GPS_APID),
|
||||
SenderReceiverApid::new(DeviceId::GPS, DeviceId::OBC, GPS_APID),
|
||||
SenderReceiverApid::new(DeviceId::OBC, DeviceId::Camera, PLD_APID),
|
||||
SenderReceiverApid::new(DeviceId::Camera, DeviceId::OBC, PLD_APID),
|
||||
SenderReceiverApid::new(DeviceId::Camera, DeviceId::OBC, PLD_APID),
|
||||
SenderReceiverApid::new(DeviceId::Camera, DeviceId::OBC, PLD_APID),
|
||||
];
|
||||
|
||||
let mut i = 0;
|
||||
for id in MessageId::iter() {
|
||||
let value = properties.get(i).unwrap();
|
||||
message_map.insert(id, *value);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return message_map;
|
||||
return package_map;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -384,10 +272,10 @@ pub fn load_device_ids() {
|
||||
*/
|
||||
|
||||
//TODO: change ids from u32 to embeddedcan ids
|
||||
pub fn message_id_to_value(packageid: &MessageId) -> u32 {
|
||||
pub fn package_id_to_value(packageid: &PackageId) -> u32 {
|
||||
*packageid as u32
|
||||
}
|
||||
pub fn message_id_to_can_id(packageid: &MessageId) -> Id {
|
||||
pub fn package_id_to_can_id(packageid: &PackageId) -> Id {
|
||||
let x = *packageid as u16;
|
||||
Id::Standard(StandardId::new(x).unwrap())
|
||||
}
|
||||
@ -396,12 +284,12 @@ pub fn device_id_to_value(deviceid: &DeviceId) -> u32 {
|
||||
*deviceid as u32
|
||||
}
|
||||
|
||||
pub fn value_to_message_id(value: u32) -> Option<MessageId> {
|
||||
pub fn value_to_package_id(value: u32) -> Option<PackageId> {
|
||||
let element = FromPrimitive::from_u32(value);
|
||||
return element;
|
||||
}
|
||||
|
||||
pub fn can_id_to_message_id(value: Id) -> Option<MessageId> {
|
||||
pub fn can_id_to_package_id(value: Id) -> Option<PackageId> {
|
||||
let buf = match value {
|
||||
Id::Standard(id) => id.as_raw() as u32,
|
||||
Id::Extended(id) => id.as_raw(),
|
||||
|
24
src/ccsds.rs
24
src/ccsds.rs
@ -1,8 +1,4 @@
|
||||
use crate::tmtc::{
|
||||
MpscStoreAndSendError, PusTcSource, AOCS_APID, AOCS_HK_APID, CSS_APID, MGM_APID, MGT_APID,
|
||||
PLD_APID, PUS_APID, PWR_APID, RWL_APID, STR_APID,
|
||||
};
|
||||
use log::warn;
|
||||
use crate::tmtc::{MpscStoreAndSendError, PusTcSource, PUS_APID};
|
||||
use satrs_core::spacepackets::{CcsdsPacket, SpHeader};
|
||||
use satrs_core::tmtc::{CcsdsPacketHandler, ReceivesCcsdsTc};
|
||||
|
||||
@ -14,18 +10,7 @@ impl CcsdsPacketHandler for CcsdsReceiver {
|
||||
type Error = MpscStoreAndSendError;
|
||||
|
||||
fn valid_apids(&self) -> &'static [u16] {
|
||||
&[
|
||||
PUS_APID,
|
||||
PLD_APID,
|
||||
PWR_APID,
|
||||
AOCS_APID,
|
||||
AOCS_HK_APID,
|
||||
MGM_APID,
|
||||
CSS_APID,
|
||||
STR_APID,
|
||||
MGT_APID,
|
||||
RWL_APID,
|
||||
]
|
||||
&[PUS_APID]
|
||||
}
|
||||
|
||||
fn handle_known_apid(
|
||||
@ -35,9 +20,8 @@ impl CcsdsPacketHandler for CcsdsReceiver {
|
||||
) -> Result<(), Self::Error> {
|
||||
if sp_header.apid() == PUS_APID {
|
||||
return self.tc_source.pass_ccsds(sp_header, tc_raw);
|
||||
} else {
|
||||
return self.tc_source.pass_ccsds(sp_header, tc_raw);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_unknown_apid(
|
||||
@ -45,7 +29,7 @@ impl CcsdsPacketHandler for CcsdsReceiver {
|
||||
sp_header: &SpHeader,
|
||||
_tc_raw: &[u8],
|
||||
) -> Result<(), Self::Error> {
|
||||
warn!("Unknown APID 0x{:x?} detected", sp_header.apid());
|
||||
println!("Unknown APID 0x{:x?} detected", sp_header.apid());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
158
src/helpers.rs
158
src/helpers.rs
@ -1,158 +0,0 @@
|
||||
use crate::requests::{Request, RequestWithToken};
|
||||
use crate::tmtc::TmStore;
|
||||
use eurosim_obsw::tmtc_err;
|
||||
use satrs_core::mode::ModeAndSubmode;
|
||||
use satrs_core::pool::StoreAddr;
|
||||
use satrs_core::pus::mode::Subservice::TmModeReply;
|
||||
use satrs_core::pus::verification::{
|
||||
FailParams, TcStateStarted, VerificationReporterWithSender, VerificationToken,
|
||||
};
|
||||
use satrs_core::pus::MpscPusInStoreSendError;
|
||||
use satrs_core::seq_count::{SeqCountProviderSyncClonable, SequenceCountProviderCore};
|
||||
use satrs_core::spacepackets::time::cds::TimeProvider;
|
||||
use satrs_core::spacepackets::time::TimeWriter;
|
||||
use satrs_core::spacepackets::tm::{PusTm, PusTmSecondaryHeader};
|
||||
use satrs_core::spacepackets::SpHeader;
|
||||
use std::sync::mpsc::Sender;
|
||||
use log::info;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VerifHelper {
|
||||
verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>,
|
||||
time_stamp_buf: [u8; 7],
|
||||
}
|
||||
|
||||
impl VerifHelper {
|
||||
pub fn new(verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>) -> Self {
|
||||
Self {
|
||||
verif_reporter,
|
||||
time_stamp_buf: [0; 7],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_and_unwrap(
|
||||
&mut self,
|
||||
request_with_token: RequestWithToken,
|
||||
) -> Result<(Request, Option<VerificationToken<TcStateStarted>>), ()> {
|
||||
match request_with_token.1 {
|
||||
None => Ok((request_with_token.0, None)),
|
||||
Some(token) => {
|
||||
self.update_time_stamp();
|
||||
if let Ok(start_token) = self //implement this for verification
|
||||
.verif_reporter
|
||||
.start_success(token, Some(&self.time_stamp_buf))
|
||||
{
|
||||
return Ok((request_with_token.0, Some(start_token)));
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_failure(&mut self, request_with_token: RequestWithToken) -> Result<(), ()> {
|
||||
if let Some(token) = request_with_token.1 {
|
||||
self.update_time_stamp();
|
||||
if let Ok(()) = self.verif_reporter.start_failure(
|
||||
token,
|
||||
FailParams::new(
|
||||
Some(&mut self.time_stamp_buf),
|
||||
&tmtc_err::INVALID_PUS_SUBSERVICE,
|
||||
None,
|
||||
),
|
||||
) {
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn completion(&mut self, start_token: VerificationToken<TcStateStarted>) -> Result<(), ()> {
|
||||
self.update_time_stamp();
|
||||
if let Ok(()) = self
|
||||
.verif_reporter
|
||||
.completion_success(start_token, Some(&self.time_stamp_buf))
|
||||
{
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn completion_failure(
|
||||
&mut self,
|
||||
start_token: VerificationToken<TcStateStarted>,
|
||||
) -> Result<(), ()> {
|
||||
self.update_time_stamp();
|
||||
if let Ok(()) = self.verif_reporter.completion_failure(
|
||||
start_token,
|
||||
FailParams::new(
|
||||
Some(&mut self.time_stamp_buf),
|
||||
&tmtc_err::INVALID_PUS_SUBSERVICE,
|
||||
None,
|
||||
),
|
||||
) {
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
fn update_time_stamp(&mut self) {
|
||||
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut self.time_stamp_buf).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ModeHelper {
|
||||
apid: u16,
|
||||
seq_count_provider: SeqCountProviderSyncClonable,
|
||||
tm_store: TmStore,
|
||||
tm_funnel_tx: Sender<StoreAddr>,
|
||||
buf: [u8; 6],
|
||||
time_stamp_buf: [u8; 7],
|
||||
}
|
||||
|
||||
impl ModeHelper {
|
||||
pub fn new(
|
||||
apid: u16,
|
||||
seq_count_provider: SeqCountProviderSyncClonable,
|
||||
tm_store: TmStore,
|
||||
tm_funnel_tx: Sender<StoreAddr>,
|
||||
) -> Self {
|
||||
Self {
|
||||
apid,
|
||||
seq_count_provider,
|
||||
tm_store,
|
||||
tm_funnel_tx,
|
||||
buf: [0; 6],
|
||||
time_stamp_buf: [0; 7],
|
||||
}
|
||||
}
|
||||
|
||||
fn update_time_stamp(&mut self) {
|
||||
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut self.time_stamp_buf).unwrap();
|
||||
}
|
||||
|
||||
pub fn make_and_send_mode_reply(
|
||||
&mut self,
|
||||
mode_submode: ModeAndSubmode,
|
||||
) -> Result<(), std::sync::mpsc::SendError<StoreAddr>> {
|
||||
info!("mode reply generated from apid {}", self.apid);
|
||||
self.update_time_stamp();
|
||||
let mut sp_header =
|
||||
SpHeader::tm_unseg(self.apid, self.seq_count_provider.get_and_increment(), 0).unwrap();
|
||||
self.buf[0..4].copy_from_slice(&mode_submode.mode().to_be_bytes());
|
||||
self.buf[4..6].copy_from_slice(&mode_submode.submode().to_be_bytes());
|
||||
let len = 6;
|
||||
let data = self.buf[0..len].to_vec();
|
||||
let tm_sec_header =
|
||||
PusTmSecondaryHeader::new_simple(200, TmModeReply as u8, &self.time_stamp_buf);
|
||||
let tm = PusTm::new(&mut sp_header, tm_sec_header, Some(&self.buf[0..len]), true);
|
||||
let addr = self.tm_store.add_pus_tm(&tm);
|
||||
self.tm_funnel_tx.send(addr)
|
||||
}
|
||||
}
|
425
src/hk.rs
425
src/hk.rs
@ -1,421 +1,16 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::hk::AocsDataType::FloatValue;
|
||||
use crate::requests::Request;
|
||||
use crate::requests::RequestWithToken;
|
||||
use crate::tmtc::{TmStore, AOCS_HK_APID};
|
||||
use byteorder::{BigEndian, ByteOrder, LittleEndian};
|
||||
use chrono::Duration;
|
||||
use eurosim_obsw::hk_err;
|
||||
use log::debug;
|
||||
use satrs_core::hk::{HkRequest, UniqueId};
|
||||
use satrs_core::pool::StoreAddr;
|
||||
use satrs_core::pus::hk::Subservice;
|
||||
use satrs_core::pus::verification::{FailParams, VerificationReporterWithSender};
|
||||
use satrs_core::pus::MpscPusInStoreSendError;
|
||||
use satrs_core::seq_count::{SeqCountProviderSyncClonable, SequenceCountProviderCore};
|
||||
use satrs_core::spacepackets::time::cds::{TimeProvider};
|
||||
use satrs_core::spacepackets::time::{CcsdsTimeProvider, TimeWriter};
|
||||
use satrs_core::spacepackets::tm::{PusTm, PusTmSecondaryHeader};
|
||||
use satrs_core::spacepackets::SpHeader;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use strum_macros::EnumIter;
|
||||
use satrs_core::tmtc::AddressableId;
|
||||
|
||||
pub type CollectionIntervalFactor = u32;
|
||||
|
||||
pub const MGM_FIELD_1: UniqueId = 1;
|
||||
pub const MGM_FIELD_2: UniqueId = 2;
|
||||
pub const MGM_FIELD_3: UniqueId = 3;
|
||||
pub const CSS_SUN_VECTOR_1: UniqueId = 4;
|
||||
pub const CSS_SUN_VECTOR_2: UniqueId = 5;
|
||||
pub const CSS_SUN_VECTOR_3: UniqueId = 6;
|
||||
pub const CSS_VOLTAGE_4: UniqueId = 7;
|
||||
pub const CSS_VOLTAGE_5: UniqueId = 8;
|
||||
pub const CSS_VOLTAGE_6: UniqueId = 9;
|
||||
pub const STR_QUATERNION_1: UniqueId = 10;
|
||||
pub const STR_QUATERNION_2: UniqueId = 11;
|
||||
pub const STR_QUATERNION_3: UniqueId = 12;
|
||||
pub const STR_QUATERNION_4: UniqueId = 13;
|
||||
pub const GPS_LATITUDE: UniqueId = 14;
|
||||
pub const GPS_LONGITUDE: UniqueId = 15;
|
||||
pub const GPS_ALTITUDE: UniqueId = 16;
|
||||
|
||||
pub const AOCS_HK_NUM_OF_ELEMENTS: usize = 16 * 8;
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum AcsHkIds {
|
||||
TestMgmSet = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum AocsHkIds {
|
||||
TestAocsSet = 1,
|
||||
TestMgmSet = 2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AocsDataMap {
|
||||
map: HashMap<UniqueId, AocsDataType>,
|
||||
}
|
||||
|
||||
impl AocsDataMap {
|
||||
pub fn new() -> Self {
|
||||
let mut data_map = HashMap::new();
|
||||
|
||||
data_map.insert(MGM_FIELD_1, FloatValue(0.0));
|
||||
data_map.insert(MGM_FIELD_2, FloatValue(0.0));
|
||||
data_map.insert(MGM_FIELD_3, FloatValue(0.0));
|
||||
data_map.insert(CSS_SUN_VECTOR_1, FloatValue(0.0));
|
||||
data_map.insert(CSS_SUN_VECTOR_2, FloatValue(0.0));
|
||||
data_map.insert(CSS_SUN_VECTOR_3, FloatValue(0.0));
|
||||
data_map.insert(CSS_VOLTAGE_4, FloatValue(0.0));
|
||||
data_map.insert(CSS_VOLTAGE_5, FloatValue(0.0));
|
||||
data_map.insert(CSS_VOLTAGE_6, FloatValue(0.0));
|
||||
data_map.insert(STR_QUATERNION_1, FloatValue(0.0));
|
||||
data_map.insert(STR_QUATERNION_2, FloatValue(0.0));
|
||||
data_map.insert(STR_QUATERNION_3, FloatValue(0.0));
|
||||
data_map.insert(STR_QUATERNION_4, FloatValue(0.0));
|
||||
data_map.insert(GPS_LATITUDE, FloatValue(0.0));
|
||||
data_map.insert(GPS_LONGITUDE, FloatValue(0.0));
|
||||
data_map.insert(GPS_ALTITUDE, FloatValue(0.0));
|
||||
|
||||
Self { map: data_map }
|
||||
}
|
||||
|
||||
pub fn update_value(&mut self, id: UniqueId, val: AocsDataType) -> Result<(), ()> {
|
||||
if self.map.contains_key(&id) {
|
||||
self.map.insert(id, val);
|
||||
return Ok(());
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
|
||||
pub fn get_value(&self, id: UniqueId) -> Option<&AocsDataType> {
|
||||
self.map.get(&id)
|
||||
}
|
||||
|
||||
pub fn all_values_as_bytes(&self) -> [u8; AOCS_HK_NUM_OF_ELEMENTS] {
|
||||
let mut buf: [u8; AOCS_HK_NUM_OF_ELEMENTS] = [0; AOCS_HK_NUM_OF_ELEMENTS];
|
||||
let mut i = 0;
|
||||
let map = self.map.clone();
|
||||
let mut map_as_vec = map.keys().collect::<Vec<&UniqueId>>();
|
||||
map_as_vec.sort();
|
||||
for element in map_as_vec {
|
||||
match map.get(element).unwrap() {
|
||||
FloatValue(val) => {
|
||||
let val_as_byte = BigEndian::write_f64(&mut (buf[i..i + 8]), *val);
|
||||
}
|
||||
}
|
||||
i += 8;
|
||||
}
|
||||
debug!("{:?}", buf);
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, EnumIter, PartialEq, Copy, Clone)]
|
||||
pub enum AocsDataType {
|
||||
FloatValue(f64),
|
||||
}
|
||||
|
||||
pub struct AocsHousekeeper {
|
||||
data_map: Arc<Mutex<AocsDataMap>>,
|
||||
id_list: Vec<UniqueId>,
|
||||
request_rx: Receiver<RequestWithToken>,
|
||||
seq_count_provider: SeqCountProviderSyncClonable,
|
||||
aocs_tm_store: TmStore,
|
||||
aocs_tm_funnel_tx: Sender<StoreAddr>,
|
||||
verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>,
|
||||
periodic_hk_ids: Option<Vec<UniqueId>>,
|
||||
periodic_on: bool,
|
||||
prev_time_step: TimeProvider,
|
||||
collection_interval: Duration,
|
||||
}
|
||||
|
||||
impl AocsHousekeeper {
|
||||
pub fn new(
|
||||
sensor_data_pool: Arc<Mutex<AocsDataMap>>,
|
||||
request_rx: Receiver<RequestWithToken>,
|
||||
seq_count_provider: SeqCountProviderSyncClonable,
|
||||
aocs_tm_store: TmStore,
|
||||
aocs_tm_funnel_tx: Sender<StoreAddr>,
|
||||
verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>,
|
||||
) -> AocsHousekeeper {
|
||||
let id_list = vec![
|
||||
MGM_FIELD_1,
|
||||
MGM_FIELD_2,
|
||||
MGM_FIELD_3,
|
||||
CSS_SUN_VECTOR_1,
|
||||
CSS_SUN_VECTOR_2,
|
||||
CSS_SUN_VECTOR_3,
|
||||
CSS_VOLTAGE_4,
|
||||
CSS_VOLTAGE_5,
|
||||
CSS_VOLTAGE_6,
|
||||
STR_QUATERNION_1,
|
||||
STR_QUATERNION_2,
|
||||
STR_QUATERNION_3,
|
||||
STR_QUATERNION_4,
|
||||
GPS_LATITUDE,
|
||||
GPS_LONGITUDE,
|
||||
GPS_ALTITUDE,
|
||||
];
|
||||
|
||||
AocsHousekeeper {
|
||||
data_map: sensor_data_pool,
|
||||
id_list,
|
||||
request_rx,
|
||||
seq_count_provider,
|
||||
aocs_tm_store,
|
||||
aocs_tm_funnel_tx,
|
||||
verif_reporter,
|
||||
periodic_hk_ids: None,
|
||||
periodic_on: false,
|
||||
prev_time_step: TimeProvider::from_now_with_u16_days().unwrap(),
|
||||
collection_interval: Duration::seconds(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_collection_interval(
|
||||
sensor_data_pool: Arc<Mutex<AocsDataMap>>,
|
||||
request_rx: Receiver<RequestWithToken>,
|
||||
seq_count_provider: SeqCountProviderSyncClonable,
|
||||
aocs_tm_store: TmStore,
|
||||
aocs_tm_funnel_tx: Sender<StoreAddr>,
|
||||
verif_reporter: VerificationReporterWithSender<MpscPusInStoreSendError>,
|
||||
collection_interval: Duration,
|
||||
) -> AocsHousekeeper {
|
||||
let id_list = vec![
|
||||
MGM_FIELD_1,
|
||||
MGM_FIELD_2,
|
||||
MGM_FIELD_3,
|
||||
CSS_SUN_VECTOR_1,
|
||||
CSS_SUN_VECTOR_2,
|
||||
CSS_SUN_VECTOR_3,
|
||||
CSS_VOLTAGE_4,
|
||||
CSS_VOLTAGE_5,
|
||||
CSS_VOLTAGE_6,
|
||||
STR_QUATERNION_1,
|
||||
STR_QUATERNION_2,
|
||||
STR_QUATERNION_3,
|
||||
STR_QUATERNION_4,
|
||||
GPS_LATITUDE,
|
||||
GPS_LONGITUDE,
|
||||
GPS_ALTITUDE,
|
||||
];
|
||||
|
||||
AocsHousekeeper {
|
||||
data_map: sensor_data_pool,
|
||||
id_list,
|
||||
request_rx,
|
||||
seq_count_provider,
|
||||
aocs_tm_store,
|
||||
aocs_tm_funnel_tx,
|
||||
verif_reporter,
|
||||
periodic_hk_ids: None,
|
||||
periodic_on: false,
|
||||
prev_time_step: TimeProvider::from_now_with_u16_days().unwrap(),
|
||||
collection_interval,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn periodic_op(&mut self) {
|
||||
self.handle_hk_request();
|
||||
self.periodic_hk();
|
||||
}
|
||||
|
||||
// housekeeper has methods for both sending individual variables as tm as well as entire aocs data set
|
||||
// individual values results in way too much traffic, therefore is not used
|
||||
// the functions for it are kept here since the logic could be easily adapted to send different sets (something which is currently not implemented)
|
||||
// for now, ..._individual functions are rather unnecessary
|
||||
pub fn handle_hk_request(&mut self) {
|
||||
let mut time_stamp_buf: [u8; 7] = [0; 7];
|
||||
|
||||
if let Ok(request_with_token) = self.request_rx.try_recv() {
|
||||
if let Request::HkRequest(hk_req) = request_with_token.0 {
|
||||
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
|
||||
let start_token = self //implement this for verification
|
||||
.verif_reporter
|
||||
.start_success(request_with_token.1.unwrap(), Some(&time_stamp_buf))
|
||||
.expect("Error sending start success");
|
||||
if let Ok(()) = match hk_req {
|
||||
HkRequest::OneShot(id) => self.one_shot(),
|
||||
HkRequest::Enable(id) => self.enable_periodic(),
|
||||
HkRequest::Disable(id) => self.disable_periodic(),
|
||||
HkRequest::ModifyCollectionInterval(_id, _collection_interval) => Ok(()),
|
||||
} {
|
||||
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
|
||||
self.verif_reporter
|
||||
.completion_success(start_token, Some(&time_stamp_buf))
|
||||
.expect("Error sending completion success");
|
||||
} else {
|
||||
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
|
||||
self.verif_reporter
|
||||
.completion_failure(
|
||||
start_token,
|
||||
FailParams::new(
|
||||
Some(&time_stamp_buf),
|
||||
&hk_err::UNKNOWN_TARGET_ID,
|
||||
None,
|
||||
),
|
||||
)
|
||||
.expect("Error sending completion success");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_period(&mut self) -> bool {
|
||||
let current_time = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
let prev_time = self.prev_time_step.clone();
|
||||
let delta = current_time.date_time().unwrap() - prev_time.date_time().unwrap();
|
||||
delta > self.collection_interval
|
||||
}
|
||||
|
||||
pub fn periodic_hk(&mut self) {
|
||||
if self.periodic_on && self.check_period() {
|
||||
self.prev_time_step = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
let map = self.data_map.lock().unwrap();
|
||||
let mut data_as_bytes = map.all_values_as_bytes();
|
||||
debug!("{:?}", &map);
|
||||
drop(map);
|
||||
self.send_hk_packet(1, &mut data_as_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn periodic_hk_individual(&mut self) {
|
||||
//let json_string = self.aocs_data_to_str();
|
||||
let data = self.data_map.lock().unwrap();
|
||||
let data_copy = data.clone();
|
||||
drop(data);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
if let Some(ids) = &self.periodic_hk_ids {
|
||||
for id in ids.clone() {
|
||||
if let Some(FloatValue(field)) = data_copy.get_value(id) {
|
||||
let data_str = LittleEndian::write_f64(&mut buf, *field);
|
||||
let _ = &self.send_hk_packet(id, &buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn one_shot(&mut self) -> Result<(), ()> {
|
||||
let map = self.data_map.lock().unwrap();
|
||||
let data_as_bytes = map.all_values_as_bytes();
|
||||
drop(map);
|
||||
// currently gives 1 as id, meaning one is the spid, if multiple spids in this housekeeper, this needs to change!
|
||||
self.send_hk_packet(1, &data_as_bytes);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn one_shot_hk_individual(&mut self, id: UniqueId) -> Result<(), ()> {
|
||||
let data = self.data_map.lock().unwrap();
|
||||
let data_copy = data.clone();
|
||||
drop(data);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
if let Some(FloatValue(field)) = data_copy.get_value(id) {
|
||||
let data_str = LittleEndian::write_f64(&mut buf, *field);
|
||||
self.send_hk_packet(id, &buf);
|
||||
return Ok(());
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
|
||||
pub fn enable_periodic(&mut self) -> Result<(), ()> {
|
||||
self.periodic_on = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enable_periodic_individual(&mut self, id: UniqueId) -> Result<(), ()> {
|
||||
if !self.id_list.contains(&id) {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let periodic_hk_ids = self.periodic_hk_ids.clone();
|
||||
match periodic_hk_ids {
|
||||
None => self.periodic_hk_ids = Some(vec![id]),
|
||||
Some(mut ids) => {
|
||||
ids.push(id);
|
||||
self.periodic_hk_ids = Some(ids);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn disable_periodic(&mut self) -> Result<(), ()> {
|
||||
self.periodic_on = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn disable_periodic_individual(&mut self, id: UniqueId) -> Result<(), ()> {
|
||||
if !self.id_list.contains(&id) {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let periodic_hk_ids = self.periodic_hk_ids.clone();
|
||||
match periodic_hk_ids {
|
||||
None => return Err(()),
|
||||
Some(mut ids) => {
|
||||
if !ids.contains(&id) {
|
||||
return Err(());
|
||||
}
|
||||
// .unwrap is allowed, since existence check is performed
|
||||
let index = ids.iter().position(|x| *x == id).unwrap();
|
||||
ids.remove(index);
|
||||
if ids.len() < 1 {
|
||||
self.periodic_hk_ids = None;
|
||||
} else {
|
||||
self.periodic_hk_ids = Some(ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn aocs_data_to_str(&mut self) -> String {
|
||||
let pool = self.data_map.lock().unwrap();
|
||||
serde_json::to_string(pool.deref()).unwrap()
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
pub fn send_hk_packet_from_str(&mut self, id: UniqueId, data: &str) {
|
||||
let mut time_stamp_buf: [u8; 7] = [0; 7];
|
||||
let mut huge_buf: [u8; 8192] = [0; 8192];
|
||||
|
||||
let mut sp_header =
|
||||
SpHeader::tm_unseg(0x02, self.seq_count_provider.get_and_increment(), 0).unwrap();
|
||||
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
|
||||
huge_buf[0..4].copy_from_slice(&id.to_be_bytes());
|
||||
let mut len = 4;
|
||||
huge_buf[8..data.len() + 8].copy_from_slice(data.as_bytes());
|
||||
len += data.len();
|
||||
let tm_sec_header =
|
||||
PusTmSecondaryHeader::new_simple(3, Subservice::TmHkPacket as u8, &time_stamp_buf);
|
||||
let hk_tm = PusTm::new(&mut sp_header, tm_sec_header, Some(&huge_buf[0..len]), true);
|
||||
let addr = self.aocs_tm_store.add_pus_tm(&hk_tm);
|
||||
self.aocs_tm_funnel_tx.send(addr).expect("sending failed");
|
||||
}
|
||||
|
||||
pub fn send_hk_packet(&mut self, id: UniqueId, data: &[u8]) {
|
||||
let mut time_stamp_buf: [u8; 7] = [0; 7];
|
||||
let mut huge_buf: [u8; 8192] = [0; 8192];
|
||||
|
||||
let mut sp_header =
|
||||
SpHeader::tm_unseg(AOCS_HK_APID, self.seq_count_provider.get_and_increment(), 0)
|
||||
.unwrap();
|
||||
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
|
||||
huge_buf[0..4].copy_from_slice(&id.to_be_bytes());
|
||||
let mut len = 8;
|
||||
huge_buf[len..data.len() + 8].copy_from_slice(data);
|
||||
len += data.len();
|
||||
let data = huge_buf[0..len].to_vec();
|
||||
let tm_sec_header =
|
||||
PusTmSecondaryHeader::new_simple(3, Subservice::TmHkPacket as u8, &time_stamp_buf);
|
||||
sp_header.data_len = len as u16;
|
||||
let hk_tm = PusTm::new(&mut sp_header, tm_sec_header, Some(&huge_buf[0..len]), true);
|
||||
let addr = self.aocs_tm_store.add_pus_tm(&hk_tm);
|
||||
self.aocs_tm_funnel_tx.send(addr).expect("sending failed");
|
||||
}
|
||||
pub enum HkRequest {
|
||||
OneShot(AddressableId),
|
||||
Enable(AddressableId),
|
||||
Disable(AddressableId),
|
||||
ModifyCollectionInterval(AddressableId, CollectionIntervalFactor),
|
||||
}
|
||||
|
20
src/lib.rs
20
src/lib.rs
@ -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] = &[
|
||||
|
506
src/main.rs
506
src/main.rs
@ -1,64 +1,90 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
// remove this, just here for now since application isn't fully developed
|
||||
|
||||
mod action;
|
||||
mod aocs;
|
||||
mod cam;
|
||||
#[cfg(feature = "can")]
|
||||
mod can;
|
||||
mod can_ids;
|
||||
mod ccsds;
|
||||
mod helpers;
|
||||
mod pld_handler;
|
||||
mod hk;
|
||||
mod logger;
|
||||
mod messages;
|
||||
mod pld_handler;
|
||||
mod power_handler;
|
||||
mod pus;
|
||||
mod requests;
|
||||
mod tmtc;
|
||||
mod pcdu;
|
||||
|
||||
use crate::requests::RequestWithToken;
|
||||
use crate::tmtc::{core_tmtc_task, OtherArgs, PusTcSource, TcArgs, TcStore, TmArgs, TmFunnel, TmStore, AOCS_APID, AOCS_HK_APID, CSS_APID, MGM_APID, MGT_APID, PLD_APID, PUS_APID, PWR_APID, RWL_APID, STR_APID, GPS_APID};
|
||||
use crate::requests::{Request, RequestWithToken};
|
||||
use crate::tmtc::{
|
||||
core_tmtc_task, OtherArgs, PusTcSource, TcArgs, TcStore, TmArgs, TmFunnel, TmStore, PUS_APID,
|
||||
};
|
||||
use eurosim_obsw::{RequestTargetId, OBSW_SERVER_ADDR, SERVER_PORT};
|
||||
use satrs_core::event_man::{
|
||||
EventManagerWithMpscQueue, MpscEventReceiver, MpscEventU32SendProvider, SendEventProvider,
|
||||
};
|
||||
use satrs_core::events::EventU32;
|
||||
use satrs_core::pool::{LocalPool, PoolCfg};
|
||||
use satrs_core::pool::{LocalPool, PoolCfg, StoreAddr};
|
||||
use satrs_core::pus::event_man::{
|
||||
DefaultPusMgmtBackendProvider, EventReporter, EventRequestWithToken, PusEventDispatcher,
|
||||
DefaultPusMgmtBackendProvider, EventReporter, EventRequestWithToken,
|
||||
PusEventDispatcher,
|
||||
};
|
||||
use satrs_core::pus::verification::{
|
||||
MpscVerifSender, VerificationReporterCfg, VerificationReporterWithSender,
|
||||
};
|
||||
use satrs_core::seq_count::SeqCountProviderSyncClonable;
|
||||
use satrs_core::pus::{EcssTmErrorWithSend, EcssTmSenderCore};
|
||||
use satrs_core::seq_count::{
|
||||
SeqCountProviderSyncClonable,
|
||||
};
|
||||
use satrs_core::{
|
||||
spacepackets::time::cds::TimeProvider,
|
||||
spacepackets::time::TimeWriter,
|
||||
spacepackets::tm::{PusTm},
|
||||
};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::can_ids::{
|
||||
load_message_id_to_apids, load_message_id_to_threads, DeviceId, MessageModel,
|
||||
};
|
||||
use chrono::Duration;
|
||||
use log::info;
|
||||
use satrs_core::power::{SwitchId, SwitchState};
|
||||
use crate::can_ids::{can_id_to_package_id, DeviceId, load_package_ids, PackageId, PackageModel, ThreadId};
|
||||
use embedded_can::{Id, StandardId};
|
||||
use log::{info, warn};
|
||||
use std::collections::HashMap;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::{mpsc, Arc, Mutex, RwLock};
|
||||
use std::sync::mpsc::{channel};
|
||||
use std::sync::{mpsc, Arc, RwLock, Mutex};
|
||||
use std::thread;
|
||||
use satrs_core::power::{SwitchId, SwitchState};
|
||||
//use libc::time64_t;
|
||||
use crate::aocs::{AocsController, MGMHandler, STRHandler, GPSHandler, CSSHandler};
|
||||
#[cfg(feature = "can")]
|
||||
use crate::can::CanTxHandler;
|
||||
use crate::helpers::{ModeHelper, VerifHelper};
|
||||
use crate::hk::{AocsDataMap, AocsHousekeeper};
|
||||
use crate::pld_handler::core_pld_task;
|
||||
use crate::power_handler::{core_power_task, DeviceState, PowerSwitcher};
|
||||
use crate::action::ActionRequest;
|
||||
use crate::cam::CameraRequest;
|
||||
use crate::pld_handler::{CameraHandler, core_pld_task};
|
||||
use crate::pcdu::{core_power_task, PowerSwitcher};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct EventTmSender {
|
||||
store_helper: TmStore,
|
||||
sender: mpsc::Sender<StoreAddr>,
|
||||
}
|
||||
|
||||
impl EventTmSender {
|
||||
fn new(store_helper: TmStore, sender: mpsc::Sender<StoreAddr>) -> Self {
|
||||
Self {
|
||||
store_helper,
|
||||
sender,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EcssTmSenderCore for EventTmSender {
|
||||
type Error = mpsc::SendError<StoreAddr>;
|
||||
|
||||
fn send_tm(&mut self, tm: PusTm) -> Result<(), EcssTmErrorWithSend<Self::Error>> {
|
||||
let addr = self.store_helper.add_pus_tm(&tm);
|
||||
self.sender
|
||||
.send(addr)
|
||||
.map_err(EcssTmErrorWithSend::SendError)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Running SESPSat OBSW");
|
||||
|
||||
logger::setup_logger().unwrap();
|
||||
info!("Running DemoSat OBSW!");
|
||||
|
||||
let tm_pool = LocalPool::new(PoolCfg::new(vec![
|
||||
(30, 32),
|
||||
@ -84,25 +110,17 @@ fn main() {
|
||||
};
|
||||
|
||||
let seq_count_provider = SeqCountProviderSyncClonable::default();
|
||||
let msg_count_provider = SeqCountProviderSyncClonable::default();
|
||||
let aocs_hk_seq_count_provider = SeqCountProviderSyncClonable::default();
|
||||
let aocs_ctrl_seq_count_provider = SeqCountProviderSyncClonable::default();
|
||||
let mgm_seq_count_provider = SeqCountProviderSyncClonable::default();
|
||||
let css_seq_count_provider = SeqCountProviderSyncClonable::default();
|
||||
let str_seq_count_provider = SeqCountProviderSyncClonable::default();
|
||||
let gps_seq_count_provider = SeqCountProviderSyncClonable::default();
|
||||
let verif_seq_count_provider = seq_count_provider.clone();
|
||||
let tmtc_seq_count_provider = seq_count_provider.clone();
|
||||
let aocs_seq_count_provider = seq_count_provider.clone();
|
||||
|
||||
let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), SERVER_PORT);
|
||||
let (tc_source_tx, tc_source_rx) = channel();
|
||||
let (tm_funnel_tx, tm_funnel_rx) = channel();
|
||||
let (tm_server_tx, tm_server_rx) = channel();
|
||||
let verif_sender = MpscVerifSender::new(1, "name", tm_store.pool.clone(), tm_funnel_tx.clone());
|
||||
let verif_sender = MpscVerifSender::new(tm_store.pool.clone(), tm_funnel_tx.clone());
|
||||
let verif_cfg = VerificationReporterCfg::new(
|
||||
PUS_APID,
|
||||
Box::new(verif_seq_count_provider.clone()),
|
||||
Box::new(msg_count_provider),
|
||||
#[allow(clippy::box_default)]
|
||||
Box::new(seq_count_provider.clone()),
|
||||
1,
|
||||
2,
|
||||
8,
|
||||
@ -118,28 +136,20 @@ fn main() {
|
||||
let mut event_man = EventManagerWithMpscQueue::new(Box::new(event_recv));
|
||||
let event_reporter = EventReporter::new(PUS_APID, 128).unwrap();
|
||||
let pus_tm_backend = DefaultPusMgmtBackendProvider::<EventU32>::default();
|
||||
let pus_event_dispatcher = PusEventDispatcher::new(event_reporter, Box::new(pus_tm_backend));
|
||||
let mut pus_event_dispatcher =
|
||||
PusEventDispatcher::new(event_reporter, Box::new(pus_tm_backend));
|
||||
let (pus_event_man_tx, pus_event_man_rx) = channel();
|
||||
let pus_event_man_send_provider = MpscEventU32SendProvider::new(1, pus_event_man_tx);
|
||||
let reporter_event_handler = verif_reporter.clone();
|
||||
let reporter_aocs = verif_reporter.clone();
|
||||
let mut reporter_event_handler = verif_reporter.clone();
|
||||
let mut reporter_aocs = verif_reporter.clone();
|
||||
let mut reporter_pld = verif_reporter.clone();
|
||||
event_man.subscribe_all(pus_event_man_send_provider.id());
|
||||
|
||||
// possibly deprecated, as the apid should replace the target id
|
||||
let mut request_map = HashMap::new();
|
||||
let (aocs_thread_tx, aocs_thread_rx) = channel::<RequestWithToken>();
|
||||
let (acs_thread_tx, acs_thread_rx) = channel::<RequestWithToken>();
|
||||
let (pld_thread_tx, pld_thread_rx) = channel::<RequestWithToken>();
|
||||
let (pwr_thread_tx, pwr_thread_rx) = channel::<RequestWithToken>();
|
||||
let (aocs_hk_tx, aocs_hk_rx) = channel::<RequestWithToken>();
|
||||
let (mgm_tx, mgm_rx) = channel::<RequestWithToken>();
|
||||
let (css_tx, css_rx) = channel::<RequestWithToken>();
|
||||
let (str_tx, str_rx) = channel::<RequestWithToken>();
|
||||
let (gps_tx, gps_rx) = channel::<RequestWithToken>();
|
||||
let (mgt_tx, mgt_rx) = channel::<RequestWithToken>();
|
||||
let (rwl_tx, rwl_rx) = channel::<RequestWithToken>();
|
||||
request_map.insert(RequestTargetId::AcsSubsystem as u32, aocs_thread_tx.clone());
|
||||
request_map.insert(RequestTargetId::PldSubsystem as u32, pld_thread_tx.clone());
|
||||
request_map.insert(RequestTargetId::AcsSubsystem as u32, acs_thread_tx);
|
||||
request_map.insert(RequestTargetId::PldSubsystem as u32, pld_thread_tx);
|
||||
//add here receivers for tmtc task to send requests to
|
||||
//request_map.insert(RequestTargetId::CanTask as u32, can_thread_tx);
|
||||
|
||||
@ -148,27 +158,13 @@ fn main() {
|
||||
tc_source: tc_source_tx,
|
||||
};
|
||||
|
||||
let mut apid_map = HashMap::new();
|
||||
apid_map.insert(PLD_APID, pld_thread_tx.clone());
|
||||
apid_map.insert(PWR_APID, pwr_thread_tx.clone());
|
||||
apid_map.insert(AOCS_APID, aocs_thread_tx.clone());
|
||||
apid_map.insert(AOCS_HK_APID, aocs_hk_tx.clone());
|
||||
apid_map.insert(MGM_APID, mgm_tx.clone());
|
||||
apid_map.insert(CSS_APID, css_tx.clone());
|
||||
apid_map.insert(STR_APID, str_tx.clone());
|
||||
apid_map.insert(GPS_APID, gps_tx.clone());
|
||||
apid_map.insert(MGT_APID, mgt_tx.clone());
|
||||
apid_map.insert(RWL_APID, rwl_tx.clone());
|
||||
|
||||
// Create clones here to allow moving the values
|
||||
let core_args = OtherArgs {
|
||||
sock_addr,
|
||||
verif_reporter: verif_reporter.clone(),
|
||||
verif_reporter,
|
||||
event_sender,
|
||||
event_request_tx,
|
||||
request_map,
|
||||
apid_map,
|
||||
seq_count_provider: verif_seq_count_provider,
|
||||
};
|
||||
let tc_args = TcArgs {
|
||||
tc_source,
|
||||
@ -180,28 +176,20 @@ fn main() {
|
||||
tm_server_rx,
|
||||
};
|
||||
|
||||
let (mgm_can_tx, mgm_can_rx) = mpsc::channel::<MessageModel>();
|
||||
let (mgt_can_tx, mgt_can_rx) = mpsc::channel::<MessageModel>();
|
||||
let (css_can_tx, css_can_rx) = mpsc::channel::<MessageModel>();
|
||||
let (rwl_can_tx, rwl_can_rx) = mpsc::channel::<MessageModel>();
|
||||
let (str_can_tx, str_can_rx) = mpsc::channel::<MessageModel>();
|
||||
let (gps_can_tx, gps_can_rx) = mpsc::channel::<MessageModel>();
|
||||
let (power_can_tx, power_can_rx) = mpsc::channel::<MessageModel>();
|
||||
let (pld_can_tx, pld_can_rx) = mpsc::channel::<MessageModel>();
|
||||
let (aocs_can_tx, aocs_can_rx) = mpsc::channel::<PackageModel>();
|
||||
let (power_can_tx, power_can_rx) = mpsc::channel::<PackageModel>();
|
||||
let (pld_can_tx, pld_can_rx) = mpsc::channel::<PackageModel>();
|
||||
|
||||
// make tx thread id hashmap
|
||||
let mut can_senders = HashMap::new();
|
||||
can_senders.insert(PWR_APID, power_can_tx);
|
||||
can_senders.insert(PLD_APID, pld_can_tx);
|
||||
can_senders.insert(MGM_APID, mgm_can_tx);
|
||||
can_senders.insert(MGT_APID, mgt_can_tx);
|
||||
can_senders.insert(RWL_APID, rwl_can_tx);
|
||||
can_senders.insert(CSS_APID, css_can_tx);
|
||||
can_senders.insert(STR_APID, str_can_tx);
|
||||
can_senders.insert(GPS_APID, gps_can_tx);
|
||||
can_senders.insert(ThreadId::AOCSThread, aocs_can_tx);
|
||||
can_senders.insert(ThreadId::PowerThread, power_can_tx);
|
||||
can_senders.insert(ThreadId::PLDThread, pld_can_tx);
|
||||
|
||||
// get package id hashmap
|
||||
let message_ids_rx = load_message_id_to_apids();
|
||||
let package_ids_rx = load_package_ids();
|
||||
|
||||
let socket0 = can::CanRxHandler::new_socket("can0", can_senders, package_ids_rx).unwrap();
|
||||
|
||||
info!("Starting TMTC task");
|
||||
let builder0 = thread::Builder::new().name("TMTCThread".into());
|
||||
@ -209,76 +197,146 @@ fn main() {
|
||||
core_tmtc_task(core_args, tc_args, tm_args);
|
||||
});
|
||||
|
||||
let (can_tx_sender, can_tx_receiver) = channel();
|
||||
|
||||
#[cfg(feature = "can")]
|
||||
let mut can_rx_socket =
|
||||
can::CanRxHandler::new_socket("can0", can_senders.clone(), message_ids_rx.clone()).unwrap();
|
||||
|
||||
#[cfg(feature = "can")]
|
||||
info!("Starting CAN Socket listening task");
|
||||
let builder1 = thread::Builder::new().name("CanRxHandler".into());
|
||||
let jh1 = builder1.spawn(move || loop {
|
||||
#[cfg(feature = "can")]
|
||||
can_rx_socket.process_incoming();
|
||||
});
|
||||
|
||||
#[cfg(feature = "can")]
|
||||
let mut can_tx_socket =
|
||||
CanTxHandler::new_socket("can0", message_ids_rx.clone(), can_tx_receiver).unwrap();
|
||||
|
||||
#[cfg(feature = "can")]
|
||||
info!("Starting CAN Socket writing task");
|
||||
let builder_can_tx = thread::Builder::new().name("TxHandler".into());
|
||||
let jh_can_tx = builder_can_tx.spawn(move || loop {
|
||||
#[cfg(feature = "can")]
|
||||
can_tx_socket.process_incoming();
|
||||
let frame = socket0.rx_socket();
|
||||
if let Some(frame) = frame {
|
||||
let forward = socket0.forward_frame(frame);
|
||||
}
|
||||
});
|
||||
|
||||
let (pcdu_tx, pcdu_rx) = mpsc::channel::<(SwitchId, SwitchState)>();
|
||||
let pcdu_can_tx_sender = can_tx_sender.clone();
|
||||
let pcdu_can_tx =
|
||||
can::CanTxHandler::new_socket("can0", ThreadId::PowerThread, load_package_ids()).unwrap();
|
||||
|
||||
|
||||
let mut device_state_map = HashMap::new();
|
||||
for id in DeviceId::iter() {
|
||||
device_state_map.insert(id, SwitchState::Off);
|
||||
}
|
||||
for id in DeviceId::iter() {
|
||||
device_state_map.insert(id, SwitchState::Off);
|
||||
}
|
||||
let clonable_device_state_map = Arc::new(Mutex::new(device_state_map));
|
||||
|
||||
let power_switcher = PowerSwitcher::new(pcdu_tx, clonable_device_state_map.clone());
|
||||
let mut power_switcher = PowerSwitcher::new(pcdu_tx, clonable_device_state_map.clone());
|
||||
|
||||
info!("Starting Power Handling task");
|
||||
info!("Starting power task");
|
||||
let builder2 = thread::Builder::new().name("PowerThread".into());
|
||||
let jh2 = builder2.spawn(move || {
|
||||
core_power_task(
|
||||
pcdu_rx,
|
||||
pcdu_can_tx_sender,
|
||||
power_can_rx,
|
||||
clonable_device_state_map.clone(),
|
||||
);
|
||||
core_power_task(pcdu_rx, pcdu_can_tx, power_can_rx, clonable_device_state_map.clone());
|
||||
});
|
||||
|
||||
let package_map_pld_tx = load_message_id_to_threads();
|
||||
|
||||
let package_map_aocs_tx = load_package_ids();
|
||||
let aocs_tm_funnel_tx = tm_funnel_tx.clone();
|
||||
let mut aocs_tm_store = tm_store.clone();
|
||||
|
||||
/*
|
||||
// AOCS Thread
|
||||
let socket1 =
|
||||
can::CanTxHandler::new_socket("can0", ThreadId::AOCSThread, package_map_aocs_tx).unwrap();
|
||||
info!("Starting AOCS receiving thread");
|
||||
let builder2 = thread::Builder::new().name("AOCSThread".into());
|
||||
let jh2 = builder2.spawn(move || {
|
||||
let mut time_stamp_buf: [u8; 7] = [0; 7];
|
||||
let mut huge_buf: [u8; 8192] = [0; 8192];
|
||||
let data: [u8; 3] = [1, 2, 3];
|
||||
let current_mgm_data = MgmData::default();
|
||||
//let current_mgt_data = MgtData::default();
|
||||
//let current_
|
||||
loop {
|
||||
// device handling
|
||||
//info!("Sending {:?}", PackageId::AOCSControlMGT1);
|
||||
//socket1.tx_socket(PackageId::AOCSControlMGT1, &data);
|
||||
//info!("Waiting for {:?}", PackageId::AOCSDataMGM1);
|
||||
let msg = aocs_can_rx.try_recv();
|
||||
//current_mgm_data.x = new_data
|
||||
match aocs_can_rx.try_recv() {
|
||||
Ok(package) => match package.package_id() {
|
||||
_ => warn!("Incorrect Id"),
|
||||
},
|
||||
Err(_) => {}
|
||||
}
|
||||
|
||||
// telecommand handling
|
||||
match acs_thread_rx.try_recv() {
|
||||
Ok(request_with_token) => {
|
||||
match request_with_token.0 {
|
||||
Request::HkRequest(hk_req) => {
|
||||
match hk_req {
|
||||
HkRequest::OneShot(id) => {
|
||||
assert_eq!(id.target_id, RequestTargetId::AcsSubsystem as u32);
|
||||
if id.unique_id == 0 {
|
||||
let mut sp_header = SpHeader::tm_unseg(
|
||||
0x02,
|
||||
aocs_seq_count_provider.get_and_increment(),
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
let cds_stamp =
|
||||
TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut time_stamp_buf);
|
||||
let mut len = id.write_to_be_bytes(&mut huge_buf).unwrap();
|
||||
let json_string = "asdf";
|
||||
huge_buf[8..json_string.len() + 8]
|
||||
.copy_from_slice(json_string.as_bytes());
|
||||
len += json_string.len();
|
||||
let tm_sec_header = PusTmSecondaryHeader::new_simple(
|
||||
3,
|
||||
Subservice::TmHkPacket as u8,
|
||||
&time_stamp_buf,
|
||||
);
|
||||
let hk_tm = PusTm::new(
|
||||
&mut sp_header,
|
||||
tm_sec_header,
|
||||
Some(&huge_buf[0..len]),
|
||||
true,
|
||||
);
|
||||
let addr = aocs_tm_store.add_pus_tm(&hk_tm);
|
||||
aocs_tm_funnel_tx.send(addr).expect("sending failed");
|
||||
/* let start_token = self //implement this for verification
|
||||
.verif_reporter
|
||||
.start_success(token, &self.time_stamp)
|
||||
.expect("Error sending start success");
|
||||
self.tm_tx
|
||||
.send(addr)
|
||||
.expect("Sending TM to TM funnel failed");
|
||||
self.verif_reporter
|
||||
.completion_success(start_token, &self.time_stamp)
|
||||
.expect("Error sending completion success");
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
HkRequest::Enable(_) => {}
|
||||
HkRequest::Disable(_) => {}
|
||||
HkRequest::ModifyCollectionInterval(_, _) => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
let package_map_pld_tx = load_package_ids();
|
||||
let pld_tm_funnel_tx = tm_funnel_tx.clone();
|
||||
let pld_tm_store = tm_store.clone();
|
||||
let mut pld_tm_store = tm_store.clone();
|
||||
|
||||
let pld_can_tx_sender = can_tx_sender.clone();
|
||||
|
||||
let power_switcher_pld = power_switcher.clone();
|
||||
let PLDCanSocket =
|
||||
can::CanTxHandler::new_socket("can0", ThreadId::PLDThread, package_map_pld_tx).unwrap();
|
||||
|
||||
//let mut pcdu_tx_clone = pcdu_tx.clone();
|
||||
info!("Starting Payload Handling task");
|
||||
println!("Starting Payload Handling task");
|
||||
let builder3 = thread::Builder::new().name("PLDThread".into());
|
||||
let jh3 = builder3.spawn(move || {
|
||||
core_pld_task(
|
||||
power_switcher_pld.clone(),
|
||||
pld_thread_rx,
|
||||
pld_can_rx,
|
||||
pld_can_tx_sender,
|
||||
&mut reporter_pld,
|
||||
);
|
||||
core_pld_task(power_switcher.clone(), pld_thread_rx, pld_can_rx, &mut reporter_pld);
|
||||
});
|
||||
|
||||
info!("Starting TM funnel task");
|
||||
println!("Starting TM funnel task");
|
||||
let builder4 = thread::Builder::new().name("TMFunnelThread".into());
|
||||
let jh4 = builder4.spawn(move || {
|
||||
let tm_funnel = TmFunnel {
|
||||
@ -295,189 +353,15 @@ fn main() {
|
||||
}
|
||||
});
|
||||
|
||||
let package_map_aocs_tx = load_message_id_to_threads();
|
||||
let aocs_tm_funnel_tx = tm_funnel_tx.clone();
|
||||
let aocs_tm_store = tm_store.clone();
|
||||
|
||||
let aocs_data_not_threadsafe = AocsDataMap::new();
|
||||
/*
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(1, AocsDataType::float_value(1.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(2, AocsDataType::float_value(2.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(3, AocsDataType::float_value(3.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(4, AocsDataType::float_value(4.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(5, AocsDataType::float_value(5.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(6, AocsDataType::float_value(6.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(7, AocsDataType::float_value(7.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(8, AocsDataType::float_value(8.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(9, AocsDataType::float_value(9.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(10, AocsDataType::float_value(10.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(11, AocsDataType::float_value(11.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(12, AocsDataType::float_value(12.0))
|
||||
.unwrap();
|
||||
aocs_data_not_threadsafe
|
||||
.update_value(13, AocsDataType::float_value(13.0))
|
||||
.unwrap();
|
||||
*/
|
||||
let aocs_data = Arc::new(Mutex::new(aocs_data_not_threadsafe));
|
||||
|
||||
info!("Starting AOCS task");
|
||||
let builder5 = thread::Builder::new().name("AOCSThread".into());
|
||||
let jh5 = builder5.spawn(move || {
|
||||
let mut aocs_housekeeper = AocsHousekeeper::new_with_collection_interval(
|
||||
aocs_data.clone(),
|
||||
aocs_hk_rx,
|
||||
aocs_hk_seq_count_provider,
|
||||
aocs_tm_store.clone(),
|
||||
aocs_tm_funnel_tx.clone(),
|
||||
reporter_aocs.clone(),
|
||||
Duration::seconds(1),
|
||||
);
|
||||
|
||||
let aocs_verif_helper = VerifHelper::new(verif_reporter.clone());
|
||||
let aocs_controller_mode_helper = ModeHelper::new(
|
||||
AOCS_APID,
|
||||
aocs_ctrl_seq_count_provider.clone(),
|
||||
aocs_tm_store.clone(),
|
||||
aocs_tm_funnel_tx.clone(),
|
||||
);
|
||||
|
||||
let mut aocs_controller = AocsController::new(
|
||||
aocs_thread_rx,
|
||||
mgm_tx.clone(),
|
||||
css_tx.clone(),
|
||||
str_tx.clone(),
|
||||
gps_tx.clone(),
|
||||
aocs_ctrl_seq_count_provider.clone(),
|
||||
aocs_verif_helper.clone(),
|
||||
aocs_controller_mode_helper,
|
||||
);
|
||||
|
||||
let mgm_mode_helper = ModeHelper::new(
|
||||
MGM_APID,
|
||||
mgm_seq_count_provider,
|
||||
aocs_tm_store.clone(),
|
||||
aocs_tm_funnel_tx.clone(),
|
||||
);
|
||||
|
||||
let mut mgm_handler = MGMHandler::new(
|
||||
power_switcher.clone(),
|
||||
DeviceId::MGM1,
|
||||
DeviceState::Off,
|
||||
aocs_data.clone(),
|
||||
can_tx_sender.clone(),
|
||||
mgm_can_rx,
|
||||
mgm_rx,
|
||||
aocs_verif_helper.clone(),
|
||||
mgm_mode_helper,
|
||||
);
|
||||
|
||||
let str_mode_helper = ModeHelper::new(
|
||||
STR_APID,
|
||||
str_seq_count_provider,
|
||||
aocs_tm_store.clone(),
|
||||
aocs_tm_funnel_tx.clone(),
|
||||
);
|
||||
|
||||
let mut str_handler = STRHandler::new(
|
||||
power_switcher.clone(),
|
||||
DeviceId::StarTracker,
|
||||
DeviceState::Off,
|
||||
aocs_data.clone(),
|
||||
can_tx_sender.clone(),
|
||||
str_can_rx,
|
||||
str_rx,
|
||||
aocs_verif_helper.clone(),
|
||||
str_mode_helper,
|
||||
);
|
||||
|
||||
let css_mode_helper = ModeHelper::new(
|
||||
CSS_APID,
|
||||
css_seq_count_provider,
|
||||
aocs_tm_store.clone(),
|
||||
aocs_tm_funnel_tx.clone(),
|
||||
);
|
||||
|
||||
let mut css_handler = CSSHandler::new(
|
||||
power_switcher.clone(),
|
||||
DeviceId::SunSensor1,
|
||||
DeviceState::Off,
|
||||
aocs_data.clone(),
|
||||
can_tx_sender.clone(),
|
||||
css_can_rx,
|
||||
css_rx,
|
||||
aocs_verif_helper.clone(),
|
||||
css_mode_helper,
|
||||
);
|
||||
|
||||
let gps_mode_helper = ModeHelper::new(
|
||||
GPS_APID,
|
||||
gps_seq_count_provider,
|
||||
aocs_tm_store.clone(),
|
||||
aocs_tm_funnel_tx.clone(),
|
||||
);
|
||||
|
||||
let mut gps_handler = GPSHandler::new(
|
||||
power_switcher.clone(),
|
||||
DeviceId::GPS,
|
||||
DeviceState::Off,
|
||||
aocs_data.clone(),
|
||||
can_tx_sender.clone(),
|
||||
gps_can_rx,
|
||||
gps_rx,
|
||||
aocs_verif_helper.clone(),
|
||||
gps_mode_helper,
|
||||
);
|
||||
|
||||
loop {
|
||||
aocs_housekeeper.periodic_op();
|
||||
aocs_controller.periodic_op();
|
||||
mgm_handler.periodic_op();
|
||||
str_handler.periodic_op();
|
||||
css_handler.periodic_op();
|
||||
gps_handler.periodic_op();
|
||||
}
|
||||
});
|
||||
|
||||
jh0.unwrap()
|
||||
.join()
|
||||
.expect("Joining UDP TMTC server thread failed");
|
||||
|
||||
jh1.unwrap()
|
||||
.join()
|
||||
.expect("Joining CAN Bus Listening thread failed");
|
||||
jh_can_tx
|
||||
.unwrap()
|
||||
.join()
|
||||
.expect("Joining CAN Bus Writing thread failed");
|
||||
jh2.unwrap().join().expect("Joining power thread failed");
|
||||
jh3.unwrap().join().expect("Joining PLD thread failed");
|
||||
jh4.unwrap()
|
||||
.join()
|
||||
.expect("Joining TM funnel thread failed");
|
||||
jh5.unwrap().join().expect("Joining AOCS thread failed");
|
||||
jh4.unwrap().join().expect("Joining TM funnel thread failed");
|
||||
}
|
||||
#[derive(Default)]
|
||||
struct MgmData {
|
||||
|
@ -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 {}
|
@ -1,14 +1,17 @@
|
||||
use crate::can_ids::{DeviceId, MessageId, MessageModel};
|
||||
use satrs_core::power::{PowerSwitchInfo, PowerSwitcherCommandSender, SwitchId, SwitchState};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use satrs_core::power::{PowerSwitcherCommandSender, PowerSwitchInfo, PowerSwitchProvider, SwitchId, SwitchState};
|
||||
use crate::can::{CanTxHandler};
|
||||
use crate::can_ids::{DeviceId, PackageId, PackageModel};
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use std::vec;
|
||||
use log::info;
|
||||
pub use strum::IntoEnumIterator; // 0.17.1
|
||||
pub use strum_macros::EnumIter; // 0.17.1
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, EnumIter)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, EnumIter)]
|
||||
pub enum DeviceState {
|
||||
On,
|
||||
Off,
|
||||
@ -23,22 +26,16 @@ pub struct PowerSwitcher {
|
||||
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
|
||||
}
|
||||
|
||||
pub struct PCDUHandler {
|
||||
pub struct PCDU {
|
||||
switch_rx: Receiver<(SwitchId, SwitchState)>,
|
||||
can_tx: Sender<MessageModel>,
|
||||
can_rx: Receiver<MessageModel>,
|
||||
can_tx: CanTxHandler,
|
||||
can_rx: Receiver<PackageModel>,
|
||||
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
|
||||
}
|
||||
|
||||
impl PowerSwitcher {
|
||||
pub fn new(
|
||||
switch_tx: Sender<(SwitchId, SwitchState)>,
|
||||
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
|
||||
) -> PowerSwitcher {
|
||||
PowerSwitcher {
|
||||
switch_tx,
|
||||
device_state_map,
|
||||
}
|
||||
pub fn new(switch_tx: Sender<(SwitchId, SwitchState)>, device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>) -> PowerSwitcher {
|
||||
PowerSwitcher{switch_tx, device_state_map}
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,16 +44,16 @@ impl PowerSwitcherCommandSender for PowerSwitcher {
|
||||
|
||||
fn send_switch_on_cmd(&mut self, switch_id: SwitchId) -> Result<(), Self::Error> {
|
||||
return match self.switch_tx.send((switch_id, SwitchState::On)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(()),
|
||||
};
|
||||
Ok(_) => {Ok(())}
|
||||
Err(_) => {Err(())}
|
||||
}
|
||||
}
|
||||
|
||||
fn send_switch_off_cmd(&mut self, switch_id: SwitchId) -> Result<(), Self::Error> {
|
||||
return match self.switch_tx.send((switch_id, SwitchState::Off)) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(()),
|
||||
};
|
||||
Ok(_) => {Ok(())}
|
||||
Err(_) => {Err(())}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,10 +67,11 @@ impl PowerSwitchInfo for PowerSwitcher {
|
||||
Ok(*state)
|
||||
} else {
|
||||
Err(())
|
||||
};
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn switch_delay_ms(&self) -> u32 {
|
||||
@ -81,91 +79,86 @@ impl PowerSwitchInfo for PowerSwitcher {
|
||||
}
|
||||
}
|
||||
|
||||
impl PCDUHandler {
|
||||
pub fn new(
|
||||
switch_rx: Receiver<(SwitchId, SwitchState)>,
|
||||
can_tx: Sender<MessageModel>,
|
||||
can_rx: Receiver<MessageModel>,
|
||||
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
|
||||
) -> PCDUHandler {
|
||||
PCDUHandler {
|
||||
switch_rx,
|
||||
can_tx,
|
||||
can_rx,
|
||||
device_state_map,
|
||||
}
|
||||
impl PowerSwitchProvider for PowerSwitcher {
|
||||
type Error = ();
|
||||
}
|
||||
|
||||
impl PCDU {
|
||||
pub fn new(switch_rx: Receiver<(SwitchId, SwitchState)>, can_tx: CanTxHandler, can_rx: Receiver<PackageModel>, device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>) -> PCDU{
|
||||
PCDU{switch_rx, can_tx, can_rx, device_state_map}
|
||||
}
|
||||
|
||||
pub fn send_power_on(&mut self, switch_id: SwitchId) -> Result<(), ()> {
|
||||
return if let Ok(dev_id) = DeviceId::try_from(switch_id) {
|
||||
let dev_id_bytes = dev_id as u8;
|
||||
let buf: &[u8] = &dev_id_bytes.to_be_bytes();
|
||||
self.can_tx
|
||||
.send(MessageModel::new(MessageId::DevicePowerOnRequest, buf).unwrap())
|
||||
.unwrap();
|
||||
self.can_tx.tx_socket(PackageId::DevicePowerOnRequest, buf);
|
||||
let mut map_lock = self.device_state_map.lock().unwrap();
|
||||
*map_lock.get_mut(&dev_id).unwrap() = SwitchState::Unknown;
|
||||
// TODO: potentially change bus logic -> remove acceptance and verification of power off/on, since status is simply called in next step anyway
|
||||
self.can_rx.recv();
|
||||
self.can_rx.recv();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_power_off(&mut self, switch_id: SwitchId) -> Result<(), ()> {
|
||||
return if let Ok(dev_id) = DeviceId::try_from(switch_id) {
|
||||
let dev_id_bytes = dev_id as u8;
|
||||
let buf: &[u8] = &dev_id_bytes.to_be_bytes();
|
||||
self.can_tx
|
||||
.send(MessageModel::new(MessageId::DevicePowerOffRequest, buf).unwrap())
|
||||
.unwrap();
|
||||
self.can_tx.tx_socket(PackageId::DevicePowerOffRequest, buf);
|
||||
let mut map_lock = self.device_state_map.lock().unwrap();
|
||||
*map_lock.get_mut(&dev_id).unwrap() = SwitchState::Unknown;
|
||||
self.can_rx.recv();
|
||||
self.can_rx.recv();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_states_helper(&mut self, dev_id: &DeviceId) -> Result<(), ()> {
|
||||
/*let _switch_id: SwitchId = *dev_id as u16;
|
||||
let switch_id: SwitchId = *dev_id as u16;
|
||||
let dev_id_bytes = *dev_id as u8;
|
||||
let buf: &[u8] = &dev_id_bytes.to_be_bytes();
|
||||
self.can_tx
|
||||
.send(PackageModel::new(PackageId::DevicePowerStatusRequest, buf).unwrap())
|
||||
.unwrap();
|
||||
self.can_tx.tx_socket(PackageId::DevicePowerStatusRequest, buf);
|
||||
match self.can_rx.recv_timeout(Duration::from_secs(10)) {
|
||||
Ok(msg) => {
|
||||
if msg.package_id() == PackageId::DevicePowerStatusResponse
|
||||
&& msg.data()[0] == dev_id_bytes
|
||||
{
|
||||
debug!("received power status response");
|
||||
if msg.package_id() == PackageId::DevicePowerStatusResponse && msg.data()[0] == dev_id_bytes{
|
||||
info!("received power status response");
|
||||
let mut map_lock = self.device_state_map.lock().unwrap();
|
||||
let state: SwitchState;
|
||||
let mut state: SwitchState;
|
||||
match msg.data()[1] {
|
||||
0 => state = SwitchState::Off,
|
||||
1 => state = SwitchState::On,
|
||||
2 => state = SwitchState::Faulty,
|
||||
0 => {
|
||||
state = SwitchState::Off
|
||||
},
|
||||
1 => {
|
||||
state = SwitchState::On
|
||||
},
|
||||
2 => {
|
||||
state = SwitchState::Faulty
|
||||
},
|
||||
_ => {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
*map_lock.get_mut(&dev_id).unwrap() = state;
|
||||
debug!("{:?}", map_lock);
|
||||
info!("{:?}", map_lock);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
Err(_) => Err(()),
|
||||
Err(_) => {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_all_states_helper(&mut self) -> Result<(), ()> {
|
||||
let map_lock = self.device_state_map.lock().unwrap();
|
||||
let mut map_lock = self.device_state_map.lock().unwrap();
|
||||
let mut device_list = vec::Vec::new();
|
||||
for key in map_lock.keys() {
|
||||
device_list.push(key.clone());
|
||||
@ -177,61 +170,56 @@ impl PCDUHandler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_switch_states(&mut self, switch_id: SwitchId, mut switch_state: SwitchState) -> Result<(), ()> {
|
||||
pub fn update_switch_states(&mut self, switch_id: SwitchId) -> Result<(), ()> {
|
||||
return if let Ok(dev_id) = DeviceId::try_from(switch_id) {
|
||||
match dev_id {
|
||||
//DeviceId::All => self.update_all_states_helper(),
|
||||
DeviceId::All => {Ok(())}
|
||||
DeviceId::All => {
|
||||
self.update_all_states_helper()
|
||||
}
|
||||
_ => {
|
||||
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(())
|
||||
},
|
||||
self.update_states_helper(&dev_id)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_power_requests(&mut self) -> Result<u16, ()> {
|
||||
pub fn handle_power_requests(&mut self) -> Result<u16, ()>{
|
||||
let mut i = 0;
|
||||
while let Ok((switch_id, switch_state)) = self.switch_rx.recv() {
|
||||
match switch_state {
|
||||
SwitchState::Off => match self.send_power_off(switch_id) {
|
||||
Ok(_) => {
|
||||
self.update_switch_states(switch_id, switch_state).expect("error updating switch states");
|
||||
i = i + 1;
|
||||
SwitchState::Off => {
|
||||
match self.send_power_off(switch_id) {
|
||||
Ok(_) => {
|
||||
i = i + 1;
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(());
|
||||
}
|
||||
SwitchState::On => {
|
||||
match self.send_power_on(switch_id) {
|
||||
Ok(_) => {
|
||||
i = i + 1;
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
},
|
||||
SwitchState::On => match self.send_power_on(switch_id) {
|
||||
Ok(_) => {
|
||||
self.update_switch_states(switch_id, switch_state).expect("error updating switch states");
|
||||
i = i + 1;
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(());
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.update_switch_states(switch_id);
|
||||
}
|
||||
return Ok(i);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn core_power_task(
|
||||
switch_rx: Receiver<(SwitchId, SwitchState)>,
|
||||
can_tx: Sender<MessageModel>,
|
||||
can_rx: Receiver<MessageModel>,
|
||||
device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>,
|
||||
) {
|
||||
let mut pcdu = PCDUHandler::new(switch_rx, can_tx, can_rx, device_state_map);
|
||||
loop {
|
||||
pub fn core_power_task(switch_rx: Receiver<(SwitchId, SwitchState)>, can_tx: CanTxHandler, can_rx: Receiver<PackageModel>, device_state_map: Arc<Mutex<HashMap<DeviceId, SwitchState>>>) {
|
||||
let mut pcdu = PCDU::new(switch_rx, can_tx, can_rx, device_state_map);
|
||||
loop{
|
||||
pcdu.handle_power_requests().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,17 @@
|
||||
use crate::action::ActionRequest;
|
||||
use crate::can_ids::{DeviceId, MessageId, MessageModel};
|
||||
use crate::power_handler::{DeviceState, PowerSwitcher};
|
||||
use crate::requests::{Request, RequestWithToken};
|
||||
use eurosim_obsw::{RequestTargetId};
|
||||
use log::debug;
|
||||
use satrs_core::power::{PowerSwitchInfo, PowerSwitcherCommandSender, SwitchId};
|
||||
use satrs_core::pus::verification::{VerificationReporterWithSender};
|
||||
use satrs_core::pus::MpscPusInStoreSendError;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::{Receiver, Sender, TryRecvError};
|
||||
use log::info;
|
||||
use satrs_core::power::{PowerSwitcherCommandSender, PowerSwitchInfo, SwitchId, SwitchState};
|
||||
use satrs_core::pus::verification::{StdVerifSenderError, VerificationReporterWithSender};
|
||||
use satrs_core::spacepackets::time::cds::TimeProvider;
|
||||
use satrs_core::spacepackets::time::TimeWriter;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use eurosim_obsw::RequestTargetId;
|
||||
use crate::action::ActionRequest;
|
||||
use crate::can::CanTxHandler;
|
||||
use crate::can_ids::{DeviceId, load_package_ids, PackageId, PackageModel, ThreadId};
|
||||
use crate::pld_handler::CameraMode::PictureRequest;
|
||||
use crate::pcdu::{DeviceState, PowerSwitcher};
|
||||
use crate::requests::{Request, RequestWithToken};
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub enum CameraMode {
|
||||
@ -21,7 +20,6 @@ pub enum CameraMode {
|
||||
Verification,
|
||||
Start,
|
||||
End,
|
||||
Broken,
|
||||
}
|
||||
|
||||
pub struct CameraHandler {
|
||||
@ -29,40 +27,22 @@ pub struct CameraHandler {
|
||||
camera_device_id: DeviceId,
|
||||
camera_switch_id: SwitchId,
|
||||
device_state: DeviceState,
|
||||
can_tx: Sender<MessageModel>,
|
||||
can_rx: Receiver<MessageModel>,
|
||||
can_tx: CanTxHandler,
|
||||
can_rx: Receiver<PackageModel>,
|
||||
mode: CameraMode,
|
||||
mode_rx: Receiver<CameraMode>,
|
||||
action_rx: Receiver<RequestWithToken>,
|
||||
}
|
||||
|
||||
impl CameraHandler {
|
||||
pub fn new(
|
||||
power_switcher: PowerSwitcher,
|
||||
camera_device_id: DeviceId,
|
||||
can_tx: Sender<MessageModel>,
|
||||
can_rx: Receiver<MessageModel>,
|
||||
mode_rx: Receiver<CameraMode>,
|
||||
action_rx: Receiver<RequestWithToken>,
|
||||
) -> CameraHandler {
|
||||
pub fn new(power_switcher: PowerSwitcher, camera_device_id: DeviceId, can_tx: CanTxHandler, can_rx: Receiver<PackageModel>, mode_rx: Receiver<CameraMode>) -> CameraHandler {
|
||||
let camera_switch_id = camera_device_id as u16;
|
||||
CameraHandler {
|
||||
power_switcher,
|
||||
camera_device_id,
|
||||
camera_switch_id,
|
||||
device_state: DeviceState::Off,
|
||||
can_tx,
|
||||
can_rx,
|
||||
mode: CameraMode::Idle,
|
||||
mode_rx,
|
||||
action_rx,
|
||||
}
|
||||
CameraHandler{power_switcher, camera_device_id, camera_switch_id, device_state: DeviceState::Off, can_tx, can_rx, mode: CameraMode::Idle, mode_rx}
|
||||
}
|
||||
|
||||
pub fn set_mode(&mut self, mode: CameraMode) {
|
||||
if self.mode == CameraMode::Idle {
|
||||
if self.mode == CameraMode::Idle{
|
||||
if mode == CameraMode::PictureRequest {
|
||||
self.mode = CameraMode::PictureRequest;
|
||||
self.mode = PictureRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,17 +51,84 @@ impl CameraHandler {
|
||||
self.mode
|
||||
}
|
||||
|
||||
pub fn handle_mode_requests(&mut self) {
|
||||
match self.mode_rx.try_recv() {
|
||||
Ok(mode) => {
|
||||
self.set_mode(mode);
|
||||
pub fn periodic_op(&mut self) {
|
||||
// Camera Device Handler State Machine
|
||||
|
||||
match self.mode {
|
||||
CameraMode::Idle => {}
|
||||
CameraMode::PictureRequest => {
|
||||
if self.device_state == DeviceState::Off {
|
||||
self.power_switcher.send_switch_on_cmd(self.camera_switch_id).expect("sending switch cmd failed");
|
||||
self.device_state = DeviceState::SwitchingPower;
|
||||
info!("switching power");
|
||||
}
|
||||
if self.device_state == DeviceState::SwitchingPower {
|
||||
if self.power_switcher.get_is_switch_on(self.camera_switch_id).expect("reading switch state failed") {
|
||||
self.device_state = DeviceState::On;
|
||||
info!("device on");
|
||||
}
|
||||
}
|
||||
if self.device_state == DeviceState::On {
|
||||
self.can_tx.tx_socket(PackageId::CameraImageRequest, &[1]);
|
||||
info!("sent camera request");
|
||||
self.mode = CameraMode::Verification;
|
||||
}
|
||||
}
|
||||
CameraMode::Verification => {
|
||||
if self.device_state == DeviceState::On {
|
||||
info!("waiting for image request confirmation");
|
||||
if let Ok(msg) = self.can_rx.recv() {
|
||||
if msg.package_id() == PackageId::CameraImageRequestConfirmation {
|
||||
self.mode = CameraMode::Start;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CameraMode::Start => {
|
||||
if self.device_state == DeviceState::On {
|
||||
info!("waiting for image start confirmation");
|
||||
if let Ok(msg) = self.can_rx.recv() {
|
||||
if msg.package_id() == PackageId::CameraImageExecutionStart {
|
||||
self.mode = CameraMode::End;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CameraMode::End => {
|
||||
if self.device_state == DeviceState::On {
|
||||
info!("waiting for image end confirmation");
|
||||
if let Ok(msg) = self.can_rx.recv() {
|
||||
if msg.package_id() == PackageId::CameraImageExectutionEnd {
|
||||
self.power_switcher.send_switch_off_cmd(self.camera_switch_id).expect("sending switch command failed");
|
||||
self.device_state = DeviceState::SwitchingPower;
|
||||
info!("switching power");
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.device_state == DeviceState::SwitchingPower {
|
||||
if !self.power_switcher.get_is_switch_on(self.camera_switch_id).expect("reading switch state failed") {
|
||||
self.device_state = DeviceState::Off;
|
||||
info!("device off");
|
||||
}
|
||||
}
|
||||
if self.device_state == DeviceState::Off {
|
||||
self.mode = CameraMode::Idle;
|
||||
}
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*pub fn handle_action_requests(&mut self) {
|
||||
match self.action_rx.try_recv() {
|
||||
pub fn core_pld_task(power_switcher: PowerSwitcher, pld_thread_rx: Receiver<RequestWithToken>, pld_can_rx: Receiver<PackageModel>, reporter_pld: &mut VerificationReporterWithSender<StdVerifSenderError>) {
|
||||
let (camera_mode_tx, camera_mode_rx) = mpsc::channel();
|
||||
let camera_can_tx =
|
||||
CanTxHandler::new_socket("can0", ThreadId::PLDThread, load_package_ids()).unwrap();
|
||||
|
||||
let mut camera_handler = CameraHandler::new(power_switcher, DeviceId::Camera, camera_can_tx, pld_can_rx, camera_mode_rx);
|
||||
|
||||
let mut time_stamp_buf: [u8; 7] = [0; 7];
|
||||
loop {
|
||||
match pld_thread_rx.try_recv() {
|
||||
Ok(request_with_token) => {
|
||||
match request_with_token.0 {
|
||||
Request::ActionRequest(action_id) => {
|
||||
@ -97,13 +144,11 @@ impl CameraHandler {
|
||||
.start_success(request_with_token.1, Some(&time_stamp_buf))
|
||||
.expect("Error sending start success.");
|
||||
|
||||
debug!("{:?}", camera_handler.get_mode());
|
||||
info!("{:?}", camera_handler.get_mode());
|
||||
while camera_handler.get_mode() != CameraMode::Idle {
|
||||
camera_handler.periodic_op();
|
||||
}
|
||||
|
||||
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
|
||||
// send end verification with token
|
||||
reporter_pld
|
||||
.completion_success(
|
||||
@ -123,159 +168,4 @@ impl CameraHandler {
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
pub fn take_picture(&mut self) {}
|
||||
|
||||
pub fn periodic_op(&mut self) {
|
||||
// Camera Device Handler State Machine
|
||||
|
||||
match self.mode {
|
||||
CameraMode::Broken => {}
|
||||
CameraMode::Idle => {}
|
||||
CameraMode::PictureRequest => {
|
||||
if self.device_state == DeviceState::Off {
|
||||
self.power_switcher
|
||||
.send_switch_on_cmd(self.camera_switch_id)
|
||||
.expect("sending switch cmd failed");
|
||||
self.device_state = DeviceState::SwitchingPower;
|
||||
debug!("switching power");
|
||||
}
|
||||
if self.device_state == DeviceState::SwitchingPower {
|
||||
let allowed_cycles = 10;
|
||||
for i in 0..allowed_cycles {
|
||||
if self
|
||||
.power_switcher
|
||||
.get_is_switch_on(self.camera_switch_id)
|
||||
.expect("reading switch state failed")
|
||||
{
|
||||
self.device_state = DeviceState::On;
|
||||
debug!("device on");
|
||||
}
|
||||
}
|
||||
self.mode = CameraMode::Broken;
|
||||
}
|
||||
if self.device_state == DeviceState::On {
|
||||
self.can_tx
|
||||
.send(MessageModel::new(MessageId::CameraImageRequest, &[1]).unwrap())
|
||||
.unwrap();
|
||||
debug!("sent camera request");
|
||||
self.mode = CameraMode::Verification;
|
||||
}
|
||||
}
|
||||
CameraMode::Verification => {
|
||||
if self.device_state == DeviceState::On {
|
||||
debug!("waiting for image request confirmation");
|
||||
if let Ok(msg) = self.can_rx.recv() {
|
||||
if msg.message_id() == MessageId::CameraImageRequestConfirmation {
|
||||
self.mode = CameraMode::Start;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CameraMode::Start => {
|
||||
if self.device_state == DeviceState::On {
|
||||
debug!("waiting for image start confirmation");
|
||||
if let Ok(msg) = self.can_rx.recv() {
|
||||
if msg.message_id() == MessageId::CameraImageExecutionStart {
|
||||
self.mode = CameraMode::End;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CameraMode::End => {
|
||||
if self.device_state == DeviceState::On {
|
||||
debug!("waiting for image end confirmation");
|
||||
if let Ok(msg) = self.can_rx.recv() {
|
||||
if msg.message_id() == MessageId::CameraImageExectutionEnd {
|
||||
self.power_switcher
|
||||
.send_switch_off_cmd(self.camera_switch_id)
|
||||
.expect("sending switch command failed");
|
||||
self.device_state = DeviceState::SwitchingPower;
|
||||
debug!("switching power");
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.device_state == DeviceState::SwitchingPower {
|
||||
if !self
|
||||
.power_switcher
|
||||
.get_is_switch_on(self.camera_switch_id)
|
||||
.expect("reading switch state failed")
|
||||
{
|
||||
self.device_state = DeviceState::Off;
|
||||
debug!("device off");
|
||||
}
|
||||
}
|
||||
if self.device_state == DeviceState::Off {
|
||||
self.mode = CameraMode::Idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn core_pld_task(
|
||||
power_switcher: PowerSwitcher,
|
||||
pld_thread_rx: Receiver<RequestWithToken>,
|
||||
pld_can_rx: Receiver<MessageModel>,
|
||||
pld_can_tx: Sender<MessageModel>,
|
||||
reporter_pld: &mut VerificationReporterWithSender<MpscPusInStoreSendError>,
|
||||
) {
|
||||
let (_camera_mode_tx, camera_mode_rx) = mpsc::channel();
|
||||
let (_action_tx, action_rx) = mpsc::channel();
|
||||
|
||||
let mut camera_handler = CameraHandler::new(
|
||||
power_switcher,
|
||||
DeviceId::Camera,
|
||||
pld_can_tx,
|
||||
pld_can_rx,
|
||||
camera_mode_rx,
|
||||
action_rx,
|
||||
);
|
||||
|
||||
let mut time_stamp_buf: [u8; 7] = [0; 7];
|
||||
loop {
|
||||
match pld_thread_rx.try_recv() {
|
||||
Ok(request_with_token) => {
|
||||
match request_with_token.0 {
|
||||
Request::ActionRequest(action_id) => {
|
||||
match action_id {
|
||||
ActionRequest::ImageRequest(target_id) => {
|
||||
assert_eq!(target_id, RequestTargetId::PldSubsystem);
|
||||
camera_handler.set_mode(CameraMode::PictureRequest);
|
||||
|
||||
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
|
||||
// send start verification and get token
|
||||
let start_token = reporter_pld
|
||||
.start_success(
|
||||
request_with_token.1.unwrap(),
|
||||
Some(&time_stamp_buf),
|
||||
)
|
||||
.expect("Error sending start success.");
|
||||
|
||||
debug!("{:?}", camera_handler.get_mode());
|
||||
while camera_handler.get_mode() != CameraMode::Idle {
|
||||
camera_handler.periodic_op();
|
||||
debug!("{:?}", camera_handler.get_mode());
|
||||
sleep(Duration::from_millis(1000));
|
||||
}
|
||||
|
||||
let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap();
|
||||
cds_stamp.write_to_bytes(&mut time_stamp_buf).unwrap();
|
||||
// send end verification with token
|
||||
reporter_pld
|
||||
.completion_success(start_token, Some(&time_stamp_buf))
|
||||
.expect("Error sending start success.");
|
||||
}
|
||||
ActionRequest::OrientationRequest(_) => {}
|
||||
ActionRequest::PointingRequest(_) => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
949
src/pus.rs
949
src/pus.rs
File diff suppressed because it is too large
Load Diff
@ -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>);
|
||||
|
446
src/temp_pus.rs
446
src/temp_pus.rs
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
83
src/tmtc.rs
83
src/tmtc.rs
@ -1,4 +1,3 @@
|
||||
use log::info;
|
||||
use satrs_core::events::EventU32;
|
||||
use satrs_core::hal::host::udp_server::{ReceiveResult, UdpTcServer};
|
||||
use satrs_core::params::Params;
|
||||
@ -13,29 +12,18 @@ use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::ccsds::CcsdsReceiver;
|
||||
use crate::pus::{PusReceiver, PusTcArgs, PusTmArgs};
|
||||
use crate::pus::PusReceiver;
|
||||
use crate::requests::RequestWithToken;
|
||||
use satrs_core::pool::{SharedPool, StoreAddr, StoreError};
|
||||
use satrs_core::pus::event_man::EventRequestWithToken;
|
||||
use satrs_core::pus::scheduling::{PusScheduler, TcInfo};
|
||||
use satrs_core::pus::scheduling::PusScheduler;
|
||||
use satrs_core::pus::verification::StdVerifReporterWithSender;
|
||||
use satrs_core::seq_count::SeqCountProviderSyncClonable;
|
||||
use satrs_core::spacepackets::{ecss::PusPacket, tc::PusTc, tm::PusTm, SpHeader};
|
||||
use satrs_core::tmtc::{
|
||||
CcsdsDistributor, CcsdsError, PusServiceProvider, ReceivesCcsdsTc, ReceivesEcssPusTc,
|
||||
};
|
||||
|
||||
pub const PUS_APID: u16 = 0x02;
|
||||
pub const PLD_APID: u16 = 0x30;
|
||||
pub const PWR_APID: u16 = 0x40;
|
||||
pub const AOCS_APID: u16 = 0x50;
|
||||
pub const AOCS_HK_APID: u16 = 0x51;
|
||||
pub const MGM_APID: u16 = 0x52;
|
||||
pub const CSS_APID: u16 = 0x53;
|
||||
pub const STR_APID: u16 = 0x54;
|
||||
pub const MGT_APID: u16 = 0x55;
|
||||
pub const RWL_APID: u16 = 0x56;
|
||||
pub const GPS_APID: u16 = 0x57;
|
||||
|
||||
pub struct OtherArgs {
|
||||
pub sock_addr: SocketAddr,
|
||||
@ -43,8 +31,6 @@ pub struct OtherArgs {
|
||||
pub event_sender: Sender<(EventU32, Option<Params>)>,
|
||||
pub event_request_tx: Sender<EventRequestWithToken>,
|
||||
pub request_map: HashMap<u32, Sender<RequestWithToken>>,
|
||||
pub apid_map: HashMap<u16, Sender<RequestWithToken>>,
|
||||
pub seq_count_provider: SeqCountProviderSyncClonable,
|
||||
}
|
||||
|
||||
pub struct TmArgs {
|
||||
@ -59,7 +45,6 @@ pub struct TcArgs {
|
||||
}
|
||||
|
||||
impl TcArgs {
|
||||
#[allow(dead_code)]
|
||||
fn split(self) -> (PusTcSource, Receiver<StoreAddr>) {
|
||||
(self.tc_source, self.tc_receiver)
|
||||
}
|
||||
@ -175,28 +160,22 @@ impl ReceivesCcsdsTc for PusTcSource {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn core_tmtc_task(args: OtherArgs, mut tc_args: TcArgs, tm_args: TmArgs) {
|
||||
let scheduler = Rc::new(RefCell::new(
|
||||
let mut scheduler = Rc::new(RefCell::new(
|
||||
PusScheduler::new_with_current_init_time(Duration::from_secs(5)).unwrap(),
|
||||
));
|
||||
|
||||
let sched_clone = scheduler.clone();
|
||||
let pus_tm_args = PusTmArgs {
|
||||
tm_tx: tm_args.tm_sink_sender,
|
||||
tm_store: tm_args.tm_store.clone(),
|
||||
verif_reporter: args.verif_reporter,
|
||||
seq_count_provider: args.seq_count_provider.clone(),
|
||||
};
|
||||
let pus_tc_args = PusTcArgs {
|
||||
event_request_tx: args.event_request_tx,
|
||||
request_map: args.request_map,
|
||||
tc_source: tc_args.tc_source.clone(),
|
||||
event_sender: args.event_sender,
|
||||
scheduler: sched_clone,
|
||||
apid_map: args.apid_map,
|
||||
};
|
||||
let mut pus_receiver = PusReceiver::new(PUS_APID, pus_tm_args, pus_tc_args);
|
||||
let mut sched_clone = scheduler.clone();
|
||||
let mut pus_receiver = PusReceiver::new(
|
||||
PUS_APID,
|
||||
tm_args.tm_sink_sender,
|
||||
tm_args.tm_store.clone(),
|
||||
args.verif_reporter,
|
||||
tc_args.tc_source.clone(),
|
||||
args.event_request_tx,
|
||||
args.request_map,
|
||||
sched_clone,
|
||||
);
|
||||
|
||||
let ccsds_receiver = CcsdsReceiver {
|
||||
tc_source: tc_args.tc_source.clone(),
|
||||
@ -213,13 +192,17 @@ pub fn core_tmtc_task(args: OtherArgs, mut tc_args: TcArgs, tm_args: TmArgs) {
|
||||
tm_store: tm_args.tm_store.pool.clone(),
|
||||
};
|
||||
|
||||
//let (mut tc_source, mut tc_receiver) = tc_args.split();
|
||||
|
||||
let mut tc_buf: [u8; 4096] = [0; 4096];
|
||||
loop {
|
||||
let tmtc_sched = scheduler.clone();
|
||||
let mut tmtc_sched = scheduler.clone();
|
||||
core_tmtc_loop(
|
||||
&mut udp_tmtc_server,
|
||||
&mut tc_args,
|
||||
&mut tc_buf,
|
||||
//&mut tc_source,
|
||||
//&mut tc_receiver,
|
||||
&mut pus_receiver,
|
||||
tmtc_sched,
|
||||
);
|
||||
@ -231,18 +214,16 @@ fn core_tmtc_loop(
|
||||
udp_tmtc_server: &mut UdpTmtcServer,
|
||||
tc_args: &mut TcArgs,
|
||||
tc_buf: &mut [u8],
|
||||
//tc_source: &mut PusTcSource,
|
||||
//tc_receiver: &mut Receiver<StoreAddr>,
|
||||
pus_receiver: &mut PusReceiver,
|
||||
scheduler: Rc<RefCell<PusScheduler>>,
|
||||
) {
|
||||
let releaser = |enabled: bool, info: &TcInfo| -> bool {
|
||||
if enabled {
|
||||
tc_args
|
||||
.tc_source
|
||||
.tc_source
|
||||
.send(info.addr())
|
||||
.expect("sending TC to TC source failed");
|
||||
let releaser = |enabled: bool, addr: &StoreAddr| -> bool {
|
||||
match tc_args.tc_source.tc_source.send(*addr) {
|
||||
Ok(_) => true,
|
||||
Err(_) => false,
|
||||
}
|
||||
true
|
||||
};
|
||||
|
||||
let mut pool = tc_args
|
||||
@ -254,11 +235,15 @@ fn core_tmtc_loop(
|
||||
|
||||
let mut scheduler = scheduler.borrow_mut();
|
||||
scheduler.update_time_from_now().unwrap();
|
||||
if let Ok(released_tcs) = scheduler.release_telecommands(releaser, pool.as_mut()) {
|
||||
if released_tcs > 0 {
|
||||
info!("{released_tcs} TC(s) released from scheduler");
|
||||
match scheduler.release_telecommands(releaser, pool.as_mut()) {
|
||||
Ok(released_tcs) => {
|
||||
if released_tcs > 0 {
|
||||
println!("{} Tc(s) released from scheduler", released_tcs);
|
||||
}
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
//.expect("error releasing tc");
|
||||
drop(pool);
|
||||
drop(scheduler);
|
||||
|
||||
@ -331,9 +316,9 @@ fn core_tm_handling(udp_tmtc_server: &mut UdpTmtcServer, recv_addr: &SocketAddr)
|
||||
if buf.len() > 9 {
|
||||
let service = buf[7];
|
||||
let subservice = buf[8];
|
||||
info!("Sending PUS TM[{service},{subservice}]")
|
||||
println!("Sending PUS TM[{service},{subservice}]")
|
||||
} else {
|
||||
info!("Sending PUS TM");
|
||||
println!("Sending PUS TM");
|
||||
}
|
||||
udp_tmtc_server
|
||||
.udp_tc_server
|
||||
|
Loading…
x
Reference in New Issue
Block a user