From 27790242b0c493b61bccc5dc7db4ef46d21768fb Mon Sep 17 00:00:00 2001 From: lkoester Date: Wed, 1 Feb 2023 11:05:57 +0100 Subject: [PATCH] added scheduling implementation from example --- Cargo.lock | 283 ++++++++++++++++++++++++++++++++++---- Cargo.toml | 20 ++- pyclient/main.py | 27 +++- pyclient/requirements.txt | 3 +- src/action.rs | 4 +- src/aocs.rs | 1 + src/cam.rs | 1 - src/can.rs | 26 ++-- src/can_ids.rs | 5 +- src/device_handler.rs | 53 ++++--- src/hk.rs | 2 +- src/main.rs | 39 ++++-- src/pus.rs | 190 ++++++++++++++++++++----- src/requests.rs | 4 +- src/tmtc.rs | 88 ++++++++++-- 15 files changed, 614 insertions(+), 132 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 77424fb..ffd1b9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,12 +43,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "bitflags" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3" - [[package]] name = "bitflags" version = "1.3.2" @@ -84,6 +78,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "byte_conv" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649972315d4931137a26fc2bf3ca95ee257ad796a5b57bdeb04205c91a4b5780" + [[package]] name = "byteorder" version = "1.4.3" @@ -109,9 +109,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ "iana-time-zone", + "js-sys", "num-integer", "num-traits", "serde", + "time", + "wasm-bindgen", "winapi", ] @@ -173,7 +176,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ "bstr", "csv-core", - "itoa", + "itoa 0.4.8", "ryu", "serde", ] @@ -254,6 +257,12 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2" +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + [[package]] name = "embed-doc-image" version = "0.1.4" @@ -266,13 +275,43 @@ dependencies = [ "syn", ] +[[package]] +name = "embedded-can" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" +dependencies = [ + "nb", +] + [[package]] name = "eurosim-obsw" version = "0.1.0" dependencies = [ + "chrono", + "embedded-can", + "fern", + "libc", + "log", + "num", + "num-derive", + "num-traits", "satrs-core", "satrs-mib", + "serde", + "serde_json", "socketcan", + "strum", + "strum_macros", +] + +[[package]] +name = "fern" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdd7b0849075e79ee9a1836df22c717d1eba30451796fdc631b04565dd11e2a" +dependencies = [ + "log", ] [[package]] @@ -284,6 +323,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -295,9 +340,9 @@ dependencies = [ [[package]] name = "hex" -version = "0.2.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "iana-time-zone" @@ -325,9 +370,12 @@ dependencies = [ [[package]] name = "itertools" -version = "0.4.19" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a9b56eb56058f43dc66e58f40a214b2ccbc9f3df51861b63d51dec7b65bc3f" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] [[package]] name = "itoa" @@ -335,6 +383,12 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + [[package]] name = "js-sys" version = "0.3.60" @@ -387,13 +441,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] -name = "nix" -version = "0.5.1" +name = "memoffset" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ - "bitflags 0.4.0", + "autocfg", +] + +[[package]] +name = "nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" + +[[package]] +name = "neli" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1805440578ced23f85145d00825c0a831e43c587132a90e100552172543ae30" +dependencies = [ + "byteorder", "libc", + "log", + "neli-proc-macros", +] + +[[package]] +name = "neli-proc-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn", +] + +[[package]] +name = "nix" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset", + "pin-utils", + "static_assertions", ] [[package]] @@ -402,6 +500,51 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -412,6 +555,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -456,6 +622,12 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1c2c742266c2f1041c914ba65355a83ae8747b05f208319784083583494b4b" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "proc-macro2" version = "1.0.47" @@ -480,7 +652,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -489,6 +661,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +[[package]] +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + [[package]] name = "ryu" version = "1.0.12" @@ -497,7 +675,7 @@ checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "satrs-core" -version = "0.1.0" +version = "0.1.0-alpha.0" dependencies = [ "bus", "crossbeam-channel", @@ -570,6 +748,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa 1.0.5", + "ryu", + "serde", +] + [[package]] name = "smallvec" version = "0.6.14" @@ -587,22 +776,25 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socketcan" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3101efc6ef5af6f1c1a488241b469757b7a183baca63af958cd90e4696446c80" +version = "2.0.0-pre.0" +source = "git+https://github.com/socketcan-rs/socketcan-rs.git?rev=1307b1fa76f7b98bbf7d414b88d8f30a41a753b4#1307b1fa76f7b98bbf7d414b88d8f30a41a753b4" dependencies = [ + "bitflags", + "byte_conv", + "embedded-can", "hex", "itertools", "libc", + "nb", + "neli", "nix", - "try_from", ] [[package]] name = "spacepackets" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9199251260fa674673a195bbe68703ba8d7ac0875d97df05cd4b5618218da054" +checksum = "a31966b4c2a1ca1902c6d34050648e4fbffeb124144775396422a94340068efd" dependencies = [ "chrono", "crc", @@ -612,6 +804,34 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "1.0.105" @@ -633,10 +853,15 @@ dependencies = [ ] [[package]] -name = "try_from" -version = "0.2.2" +name = "time" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923a7ee3e97dbfe8685261beb4511cc9620a1252405d02693d43169729570111" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi", + "winapi", +] [[package]] name = "unicode-ident" @@ -656,6 +881,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasm-bindgen" version = "0.2.83" diff --git a/Cargo.toml b/Cargo.toml index fefd3cd..bcbe2fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,25 @@ categories = ["aerospace", "hardware-support", "embedded"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -socketcan = {version = "1.7.0", optional = true } +# socketcan = {version = "1.7.0", optional = true } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +log = "0.4" +fern = "0.6" +chrono = "0.4" +embedded-can = "0.4" +libc = "0.2" +strum = { version = "0.24", features = ["derive"] } +strum_macros = "0.24" +num = "0.4" +num-derive = "0.3" +num-traits = "0.2" + +[dependencies.socketcan] +git = "https://github.com/socketcan-rs/socketcan-rs.git" +rev = "1307b1fa76f7b98bbf7d414b88d8f30a41a753b4" +optional = true + #[dependencies.spacepackets] #path = "../satrs-launchpad/spacepackets" diff --git a/pyclient/main.py b/pyclient/main.py index e57c5fd..d0f830a 100644 --- a/pyclient/main.py +++ b/pyclient/main.py @@ -4,19 +4,22 @@ import enum import struct import sys import time -from typing import Optional, Tuple +from typing import Optional +import datetime import tmtccmd from spacepackets.ecss import PusTelemetry, PusTelecommand, PusVerificator from spacepackets.ecss.pus_17_test import Service17Tm 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, Subservices +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 from tmtccmd.tm import CcsdsTmHandler, SpecificApidHandlerBase -from tmtccmd.com_if import ComInterface +from tmtccmd.com import ComInterface from tmtccmd.config import ( default_json_path, SetupParams, @@ -41,7 +44,7 @@ from tmtccmd.tc import ( SendCbParams, DefaultPusQueueHelper, ) -from tmtccmd.tm.pus_5_event import Service5Tm +from tmtccmd.tm.pus_5_fsfw_event import Service5Tm from tmtccmd.util import FileSeqCountProvider, PusFileSeqCountProvider from tmtccmd.util.obj_id import ObjectIdDictT @@ -108,6 +111,14 @@ class SatRsConfigHook(TmTcCfgHookBase): op_code_entry=oce ) + srv_11 = OpCodeEntry() + srv_11.add("0", "Scheduled TC Test") + defs.add_service( + name=CoreServiceList.SERVICE_11, + info="PUS Service 11 TC Scheduling", + op_code_entry=srv_11, + ) + return defs def perform_mode_operation(self, tmtc_backend: CcsdsTmtcBackend, mode: int): @@ -284,6 +295,14 @@ class TcHandler(TcHandlerBase): return q.add_pus_tc( PusTelecommand(service=8, subservice=1, app_data=make_target_id(RequestTargetId.PLD)) ) + if service == CoreServiceList.SERVICE_11: + 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))) + ) if service == ServiceList.AOCS: if op_code in AocsOpCodes.ONE_SHOT: q.add_log_cmd("Sending HK one shot request") diff --git a/pyclient/requirements.txt b/pyclient/requirements.txt index 8e9634c..b79a422 100644 --- a/pyclient/requirements.txt +++ b/pyclient/requirements.txt @@ -1 +1,2 @@ -tmtccmd == 3.0.0 +# tmtccmd == 3.0.0 +-e git+https://github.com/robamu-org/tmtccmd@97e5e51101a08b21472b3ddecc2063359f7e307a#egg=tmtccmd diff --git a/src/action.rs b/src/action.rs index bb5fc76..7bf821b 100644 --- a/src/action.rs +++ b/src/action.rs @@ -1,5 +1,5 @@ -use satrs_core::tmtc::AddressableId; use eurosim_obsw::RequestTargetId; +use satrs_core::tmtc::AddressableId; pub type CollectionIntervalFactor = u32; @@ -19,4 +19,4 @@ pub enum Subservice { ImageRequest = 1, OrientationRequest = 2, PointingRequest = 3, -} \ No newline at end of file +} diff --git a/src/aocs.rs b/src/aocs.rs index e69de29..8b13789 100644 --- a/src/aocs.rs +++ b/src/aocs.rs @@ -0,0 +1 @@ + diff --git a/src/cam.rs b/src/cam.rs index af2d89d..563bd15 100644 --- a/src/cam.rs +++ b/src/cam.rs @@ -4,7 +4,6 @@ pub type CollectionIntervalFactor = u32; //#[derive(Debug, Copy, Clone, PartialEq, Eq)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum CameraRequest { OneShot(AddressableId), diff --git a/src/can.rs b/src/can.rs index 3e5b384..b4e1e92 100644 --- a/src/can.rs +++ b/src/can.rs @@ -152,20 +152,20 @@ impl CanTxHandler { let value = self.package_map.get(&package_id).unwrap(); if value.get_sender() == DeviceId::OBC { //if value.get_thread() == self.thread_id { - if data.len() <= 8 { - let frame_id = package_id_to_can_id(&package_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() - ); + if data.len() <= 8 { + let frame_id = package_id_to_can_id(&package_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, mismatched thread id: {:?}", diff --git a/src/can_ids.rs b/src/can_ids.rs index ec34c2c..a92e380 100644 --- a/src/can_ids.rs +++ b/src/can_ids.rs @@ -5,7 +5,6 @@ use std::fs; use std::sync::mpsc::Sender; use std::thread::Thread; - pub use num_derive::{FromPrimitive, ToPrimitive}; pub use num_traits::{FromPrimitive, ToPrimitive}; pub use strum::IntoEnumIterator; // 0.17.1 @@ -61,7 +60,7 @@ pub enum PackageId { AOCSDataSunSensor5 = 69, AOCSDataSunSensor6 = 70, AOCSDataStarTracker = 71, - CameraImageRequest = 101 , + CameraImageRequest = 101, CameraImageRequestConfirmation = 102, CameraImageExecutionStart = 103, CameraImageExectutionEnd = 104, @@ -193,7 +192,7 @@ pub fn load_package_ids() -> HashMap { 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:: OBC , DeviceId:: Camera , ThreadId:: PLDThread ), + SenderReceiverThread::new(DeviceId::OBC, DeviceId::Camera, ThreadId::PLDThread), SenderReceiverThread::new(DeviceId::Camera, DeviceId::OBC, ThreadId::PLDThread), SenderReceiverThread::new(DeviceId::Camera, DeviceId::OBC, ThreadId::PLDThread), SenderReceiverThread::new(DeviceId::Camera, DeviceId::OBC, ThreadId::PLDThread), diff --git a/src/device_handler.rs b/src/device_handler.rs index b997216..16b058a 100644 --- a/src/device_handler.rs +++ b/src/device_handler.rs @@ -1,15 +1,15 @@ +use crate::can_ids::{DeviceId, PackageId, PackageModel, ThreadId}; +use log::{info, warn}; +use socketcan::{errors, frame, socket, CanFrame, Socket}; use std::collections::HashMap; use std::hash::Hash; use std::sync::mpsc::{Receiver, RecvError, Sender}; -use log::{info, warn}; -use crate::can_ids::{DeviceId, PackageId, PackageModel, ThreadId}; -use socketcan::{errors, frame, socket, CanFrame, Socket}; +use crate::can::{CanRxHandler, CanTxHandler}; pub use num_derive::{FromPrimitive, ToPrimitive}; pub use num_traits::{FromPrimitive, ToPrimitive}; pub use strum::IntoEnumIterator; // 0.17.1 -pub use strum_macros::EnumIter; -use crate::can::{CanRxHandler, CanTxHandler}; // 0.17.1 +pub use strum_macros::EnumIter; // 0.17.1 #[derive(Copy, Clone, Debug, PartialEq)] pub enum DeviceState { @@ -26,23 +26,31 @@ pub struct CanDeviceHandler { } impl CanDeviceHandler { - pub fn new(can_tx_handler: CanTxHandler, can_rx_receiver: Receiver) -> CanDeviceHandler { - let mut device_state_map:HashMap = HashMap::new(); + pub fn new( + can_tx_handler: CanTxHandler, + can_rx_receiver: Receiver, + ) -> CanDeviceHandler { + let mut device_state_map: HashMap = HashMap::new(); for id in DeviceId::iter() { device_state_map.insert(id, DeviceState::Unknown); } - CanDeviceHandler { device_state_map, can_tx_handler, can_rx_receiver } + CanDeviceHandler { + device_state_map, + can_tx_handler, + can_rx_receiver, + } } - pub fn power_on(&mut self, id: DeviceId) -> Result<(),()> { + pub fn power_on(&mut self, id: DeviceId) -> Result<(), ()> { if !self.device_state_map.contains_key(&id) { return Err(()); } info!("Powering on device {:?}", id); let msg_data: [u8; 1] = [id as u8]; - self.can_tx_handler.tx_socket(PackageId::DevicePowerOnRequest, &msg_data); + self.can_tx_handler + .tx_socket(PackageId::DevicePowerOnRequest, &msg_data); let request_confirmation = self.can_rx_receiver.recv(); match request_confirmation { @@ -93,14 +101,15 @@ impl CanDeviceHandler { Ok(()) } - pub fn power_off(&mut self, id: DeviceId) -> Result<(),()> { + pub fn power_off(&mut self, id: DeviceId) -> Result<(), ()> { if !self.device_state_map.contains_key(&id) { return Err(()); } info!("Powering on device {:?}", id); let msg_data: [u8; 1] = [id as u8]; - self.can_tx_handler.tx_socket(PackageId::DevicePowerOffRequest, &msg_data); + self.can_tx_handler + .tx_socket(PackageId::DevicePowerOffRequest, &msg_data); let request_confirmation = self.can_rx_receiver.recv(); match request_confirmation { @@ -153,23 +162,26 @@ impl CanDeviceHandler { pub fn get_power_states(&mut self) -> HashMap { for id in DeviceId::iter() { - self.update_power_state(id).expect("Error updating power state."); + self.update_power_state(id) + .expect("Error updating power state."); } self.device_state_map.clone() } pub fn get_power_state(&mut self, id: DeviceId) -> Option<&DeviceState> { - self.update_power_state(id).expect("Error updating power state."); + self.update_power_state(id) + .expect("Error updating power state."); self.device_state_map.get(&id) } - pub fn update_power_state(&mut self, id: DeviceId) -> Result<(),()> { + pub fn update_power_state(&mut self, id: DeviceId) -> Result<(), ()> { if !self.device_state_map.contains_key(&id) { return Err(()); } let msg_data: [u8; 1] = [id as u8]; - self.can_tx_handler.tx_socket(PackageId::DevicePowerStatusRequest, &msg_data); + self.can_tx_handler + .tx_socket(PackageId::DevicePowerStatusRequest, &msg_data); let response = self.can_rx_receiver.recv(); if let Ok(response) = response { @@ -193,15 +205,18 @@ impl CanDeviceHandler { pub fn power_up_sequence(mut device_handler: CanDeviceHandler) -> HashMap { for id in DeviceId::iter() { - device_handler.power_on(id).expect("Error powering on device."); + device_handler + .power_on(id) + .expect("Error powering on device."); } device_handler.get_power_states() } pub fn power_down_sequence(mut device_handler: CanDeviceHandler) -> HashMap { for id in DeviceId::iter() { - device_handler.power_off(id).expect("Error powering on device."); + device_handler + .power_off(id) + .expect("Error powering on device."); } device_handler.get_power_states() } - diff --git a/src/hk.rs b/src/hk.rs index 6bd07bd..d27c0f0 100644 --- a/src/hk.rs +++ b/src/hk.rs @@ -13,4 +13,4 @@ pub enum HkRequest { Enable(AddressableId), Disable(AddressableId), ModifyCollectionInterval(AddressableId, CollectionIntervalFactor), -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 92e4256..a922ae6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +mod action; +mod aocs; +mod cam; mod can; mod can_ids; mod ccsds; @@ -7,9 +10,6 @@ mod logger; mod pus; mod requests; mod tmtc; -mod aocs; -mod cam; -mod action; use crate::hk::{AcsHkIds, HkRequest}; use crate::requests::{Request, RequestWithToken}; @@ -332,8 +332,7 @@ fn main() { ActionRequest::ImageRequest(target_id) => { assert_eq!(target_id, RequestTargetId::PldSubsystem); // get current time stamp - let cds_stamp = - TimeProvider::from_now_with_u16_days().unwrap(); + let cds_stamp = TimeProvider::from_now_with_u16_days().unwrap(); cds_stamp.write_to_bytes(&mut time_stamp_buf); // send start verification and get token @@ -353,7 +352,10 @@ fn main() { loop { match pld_can_rx.recv() { Ok(msg) => { - if msg.package_id() == PackageId::CameraImageRequestConfirmation && msg.data()[0] == 1 { + if msg.package_id() + == PackageId::CameraImageRequestConfirmation + && msg.data()[0] == 1 + { break; } } @@ -366,7 +368,10 @@ fn main() { loop { match pld_can_rx.recv() { Ok(msg) => { - if msg.package_id() == PackageId::CameraImageExecutionStart && msg.data()[0] == 1 { + if msg.package_id() + == PackageId::CameraImageExecutionStart + && msg.data()[0] == 1 + { break; } } @@ -379,14 +384,21 @@ fn main() { loop { match pld_can_rx.recv() { Ok(msg) => { - if msg.package_id() == PackageId::CameraImageExectutionEnd && msg.data()[0] == 1 { + if msg.package_id() + == PackageId::CameraImageExectutionEnd + && msg.data()[0] == 1 + { let cds_stamp = - TimeProvider::from_now_with_u16_days().unwrap(); + TimeProvider::from_now_with_u16_days() + .unwrap(); cds_stamp.write_to_bytes(&mut time_stamp_buf); // send end verification with token reporter_pld - .completion_success(start_token, Some(&time_stamp_buf)) + .completion_success( + start_token, + Some(&time_stamp_buf), + ) .expect("Error sending start success."); break; } @@ -409,7 +421,6 @@ fn main() { } }); - println!("Starting TM funnel task"); let builder4 = thread::Builder::new().name("TMFunnelThread".into()); let jh4 = builder4.spawn(move || { @@ -427,7 +438,9 @@ fn main() { } }); - jh0.unwrap().join().expect("Joining UDP TMTC server thread failed"); + jh0.unwrap() + .join() + .expect("Joining UDP TMTC server thread failed"); jh1.unwrap() .join() .expect("Joining CAN Bus Listening thread failed"); @@ -446,4 +459,4 @@ struct MgmData { x: i16, y: i16, z: i16, -} \ No newline at end of file +} diff --git a/src/pus.rs b/src/pus.rs index 7a63ff2..41a089a 100644 --- a/src/pus.rs +++ b/src/pus.rs @@ -1,7 +1,7 @@ use crate::hk::{CollectionIntervalFactor, HkRequest}; use crate::requests::{Request, RequestWithToken}; use crate::tmtc::{PusTcSource, TmStore}; -use eurosim_obsw::{hk_err, RequestTargetId, tmtc_err}; +use eurosim_obsw::{hk_err, tmtc_err, RequestTargetId}; use satrs_core::events::EventU32; use satrs_core::pool::StoreAddr; use satrs_core::pus::event::Subservices; @@ -14,16 +14,19 @@ 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, + spacepackets, spacepackets::ecss::PusPacket, spacepackets::tc::PusTc, + spacepackets::time::cds::TimeProvider, spacepackets::time::TimeWriter, spacepackets::SpHeader, }; +use std::cell::RefCell; -use std::collections::HashMap; -use std::sync::mpsc::Sender; -use satrs_core::spacepackets::ecss::PusServiceId::Action; -use eurosim_obsw::RequestTargetId::{AcsSubsystem, PldSubsystem}; use crate::action; use crate::action::ActionRequest; +use eurosim_obsw::RequestTargetId::{AcsSubsystem, PldSubsystem}; +use satrs_core::pus::scheduling::PusScheduler; +use satrs_core::spacepackets::ecss::PusServiceId::Action; +use std::collections::HashMap; +use std::rc::Rc; +use std::sync::mpsc::Sender; pub struct PusReceiver { pub tm_helper: PusTmWithCdsShortHelper, @@ -36,6 +39,7 @@ pub struct PusReceiver { request_map: HashMap>, stamper: TimeProvider, time_stamp: [u8; 7], + scheduler: Rc>, } impl PusReceiver { @@ -47,6 +51,7 @@ impl PusReceiver { tc_source: PusTcSource, event_request_tx: Sender, request_map: HashMap>, + scheduler: Rc>, ) -> Self { Self { tm_helper: PusTmWithCdsShortHelper::new(apid), @@ -58,6 +63,7 @@ impl PusReceiver { request_map, stamper: TimeProvider::new_with_u16_days(0, 0), time_stamp: [0; 7], + scheduler, } } } @@ -85,6 +91,8 @@ impl PusServiceProvider for PusReceiver { 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 @@ -120,7 +128,11 @@ impl PusReceiver { self.verif_reporter .start_failure( token, - FailParams::new(Some(&self.time_stamp), &tmtc_err::INVALID_PUS_SUBSERVICE, None), + FailParams::new( + Some(&self.time_stamp), + &tmtc_err::INVALID_PUS_SUBSERVICE, + None, + ), ) .expect("Sending start failure TM failed"); } @@ -277,41 +289,38 @@ impl PusReceiver { } } - - fn handle_function_request(&mut self, pus_tc: &PusTc, token: VerificationToken) { + fn handle_function_request( + &mut self, + pus_tc: &PusTc, + token: VerificationToken, + ) { if pus_tc.user_data().is_none() { self.update_time_stamp(); - /*self.verif_reporter + self.verif_reporter .start_failure( token, - FailParams::new(&self.time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA, None), + 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)); - } - _ => {} + 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 { @@ -320,4 +329,119 @@ impl PusReceiver { send_request(ActionRequest::OrientationRequest(AcsSubsystem)); } } + + fn handle_scheduled_tc(&mut self, pus_tc: &PusTc, token: VerificationToken) { + 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::(pus_tc, pool.as_mut()) + .expect("TODO: panic message"); + let time = + TimeProvider::from_bytes_with_u16_days(&pus_tc.user_data().unwrap()).unwrap(); + 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; + } + } + } } diff --git a/src/requests.rs b/src/requests.rs index d10f0ac..e739398 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -1,7 +1,7 @@ -use crate::hk::HkRequest; -use satrs_core::pus::verification::{TcStateAccepted, VerificationToken}; use crate::action::ActionRequest; use crate::cam::CameraRequest; +use crate::hk::HkRequest; +use satrs_core::pus::verification::{TcStateAccepted, VerificationToken}; #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum Request { diff --git a/src/tmtc.rs b/src/tmtc.rs index c23e38e..bd0ab0b 100644 --- a/src/tmtc.rs +++ b/src/tmtc.rs @@ -1,11 +1,14 @@ use satrs_core::events::EventU32; use satrs_core::hal::host::udp_server::{ReceiveResult, UdpTcServer}; use satrs_core::params::Params; +use std::cell::RefCell; use std::collections::HashMap; use std::error::Error; use std::fmt::{Display, Formatter}; use std::net::SocketAddr; +use std::rc::Rc; use std::sync::mpsc::{Receiver, SendError, Sender, TryRecvError}; +use std::sync::{Arc, LockResult, Mutex}; use std::thread; use std::time::Duration; @@ -14,16 +17,13 @@ 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; use satrs_core::pus::verification::StdVerifReporterWithSender; +use satrs_core::spacepackets::{ecss::PusPacket, tc::PusTc, tm::PusTm, SpHeader}; use satrs_core::tmtc::{ CcsdsDistributor, CcsdsError, PusServiceProvider, ReceivesCcsdsTc, ReceivesEcssPusTc, }; -use satrs_core::{ - spacepackets::ecss::PusPacket, spacepackets::tc::PusTc, spacepackets::tm::PusTm, - spacepackets::SpHeader, -}; - pub const PUS_APID: u16 = 0x02; pub struct OtherArgs { @@ -45,6 +45,12 @@ pub struct TcArgs { pub tc_receiver: Receiver, } +impl TcArgs { + fn split(self) -> (PusTcSource, Receiver) { + (self.tc_source, self.tc_receiver) + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum MpscStoreAndSendError { StoreError(StoreError), @@ -55,10 +61,10 @@ impl Display for MpscStoreAndSendError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { MpscStoreAndSendError::StoreError(s) => { - write!(f, "store error {}", s) + write!(f, "store error {s}") } MpscStoreAndSendError::SendError(s) => { - write!(f, "send error {}", s) + write!(f, "send error {s}") } } } @@ -156,6 +162,11 @@ impl ReceivesCcsdsTc for PusTcSource { } } pub fn core_tmtc_task(args: OtherArgs, mut tc_args: TcArgs, tm_args: TmArgs) { + let mut scheduler = Rc::new(RefCell::new( + PusScheduler::new_with_current_init_time(Duration::from_secs(5)).unwrap(), + )); + + let mut sched_clone = scheduler.clone(); let mut pus_receiver = PusReceiver::new( PUS_APID, tm_args.tm_sink_sender, @@ -164,11 +175,15 @@ pub fn core_tmtc_task(args: OtherArgs, mut tc_args: TcArgs, tm_args: TmArgs) { 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(), }; + let ccsds_distributor = CcsdsDistributor::new(Box::new(ccsds_receiver)); + let udp_tc_server = UdpTcServer::new(args.sock_addr, 2048, Box::new(ccsds_distributor)) .expect("Creating UDP TMTC server failed"); @@ -177,8 +192,21 @@ pub fn core_tmtc_task(args: OtherArgs, mut tc_args: TcArgs, tm_args: TmArgs) { tm_rx: tm_args.tm_server_rx, 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 { - core_tmtc_loop(&mut udp_tmtc_server, &mut tc_args, &mut pus_receiver); + 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, + ); thread::sleep(Duration::from_millis(400)); } } @@ -186,8 +214,40 @@ pub fn core_tmtc_task(args: OtherArgs, mut tc_args: TcArgs, tm_args: TmArgs) { 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, pus_receiver: &mut PusReceiver, + scheduler: Rc>, ) { + let releaser = |enabled: bool, addr: &StoreAddr| -> bool { + match tc_args.tc_source.tc_source.send(*addr) { + Ok(_) => true, + Err(_) => false, + } + }; + + let mut pool = tc_args + .tc_source + .tc_store + .pool + .write() + .expect("error locking pool"); + + let mut scheduler = scheduler.borrow_mut(); + scheduler.update_time_from_now().unwrap(); + 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); + while poll_tc_server(udp_tmtc_server) {} match tc_args.tc_receiver.try_recv() { Ok(addr) => { @@ -198,15 +258,17 @@ fn core_tmtc_loop( .read() .expect("locking tc pool failed"); let data = pool.read(&addr).expect("reading pool failed"); - match PusTc::from_bytes(data) { + tc_buf[0..data.len()].copy_from_slice(data); + drop(pool); + match PusTc::from_bytes(tc_buf) { Ok((pus_tc, _)) => { pus_receiver .handle_pus_tc_packet(pus_tc.service(), pus_tc.sp_header(), &pus_tc) .ok(); } Err(e) => { - println!("error creating PUS TC from raw data: {}", e); - println!("raw data: {:x?}", data); + println!("error creating PUS TC from raw data: {e}"); + println!("raw data: {tc_buf:x?}"); } } } @@ -226,7 +288,7 @@ fn poll_tc_server(udp_tmtc_server: &mut UdpTmtcServer) -> bool { Ok(_) => true, Err(e) => match e { ReceiveResult::ReceiverError(e) => match e { - CcsdsError::PacketError(e) => { + CcsdsError::ByteConversionError(e) => { println!("Got packet error: {e:?}"); true } @@ -255,7 +317,7 @@ fn core_tm_handling(udp_tmtc_server: &mut UdpTmtcServer, recv_addr: &SocketAddr) if buf.len() > 9 { let service = buf[7]; let subservice = buf[8]; - println!("Sending PUS TM[{},{}]", service, subservice) + println!("Sending PUS TM[{service},{subservice}]") } else { println!("Sending PUS TM"); }