Compare commits

..

2 Commits

Author SHA1 Message Date
Robin Mueller
45a99cabce bump spacepackets 2025-09-11 09:29:34 +02:00
Robin Mueller
ab44e3312c update all the code 2025-09-10 19:01:44 +02:00
41 changed files with 1673 additions and 2922 deletions

View File

@@ -47,8 +47,6 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --all -- --check
docs:
@@ -57,7 +55,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- run: RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc -p satrs --all-features
- run: cargo +nightly doc --all-features --config 'build.rustdocflags=["--cfg", "docs_rs"]'
clippy:
name: Clippy
@@ -65,6 +63,4 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- run: cargo clippy -- -D warnings

View File

@@ -1,23 +0,0 @@
all: check embedded test fmt clippy docs
check:
cargo check
cargo check -p satrs-example --no-default-features
test:
cargo nextest run --all-features
cargo test --doc --all-features
embedded:
cargo check -p satrs --target=thumbv7em-none-eabihf --no-default-features
fmt:
cargo fmt --all -- --check
clippy:
cargo clippy -- -D warnings
docs-satrs:
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p satrs --all-features
docs: docs-satrs

View File

@@ -11,6 +11,8 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/sat-rs"
fern = "0.7"
chrono = "0.4"
log = "0.4"
arbitrary-int = "2"
bitbybit = "1.4"
crossbeam-channel = "0.5"
delegate = "0.13"
zerocopy = "0.8"
@@ -21,8 +23,6 @@ lazy_static = "1"
strum = { version = "0.27", features = ["derive"] }
derive-new = "0.7"
cfg-if = "1"
arbitrary-int = "2"
bitbybit = "1.4"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
@@ -38,8 +38,8 @@ version = "0.1.1"
path = "../satrs-mib"
[features]
default = ["heap_tmtc"]
heap_tmtc = []
default = ["heap_tmtc"]
[dev-dependencies]
env_logger = "0.11"

View File

@@ -1,4 +1,3 @@
use arbitrary_int::u11;
use lazy_static::lazy_static;
use satrs::{
res_code::ResultU16,
@@ -11,7 +10,7 @@ use strum::IntoEnumIterator;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use satrs::{
events_legacy::{EventU32TypedSev, SeverityInfo},
events::{EventU32TypedSev, SeverityInfo},
pool::{StaticMemoryPool, StaticPoolConfig},
};
@@ -45,7 +44,7 @@ lazy_static! {
pub static ref PACKET_ID_VALIDATOR: HashSet<PacketId> = {
let mut set = HashSet::new();
for id in crate::ids::Apid::iter() {
set.insert(PacketId::new(PacketType::Tc, true, u11::new(id as u16)));
set.insert(PacketId::new(PacketType::Tc, true, id.raw_value()));
}
set
};

View File

@@ -1,15 +1,14 @@
use std::sync::mpsc::{self};
use crate::pus::create_verification_reporter;
use arbitrary_int::traits::Integer as _;
use arbitrary_int::u11;
use satrs::event_man_legacy::{EventMessageU32, EventRoutingError};
use satrs::event_man::{EventMessageU32, EventRoutingError};
use satrs::pus::event::EventTmHook;
use satrs::pus::verification::VerificationReporter;
use satrs::pus::EcssTmSender;
use satrs::request::UniqueApidTargetId;
use satrs::{
event_man_legacy::{EventManagerWithBoundedMpsc, EventSendProvider, EventU32SenderMpscBounded},
event_man::{EventManagerWithBoundedMpsc, EventSendProvider, EventU32SenderMpscBounded},
pus::{
event_man::{
DefaultPusEventU32TmCreator, EventReporter, EventRequest, EventRequestWithToken,
@@ -61,11 +60,12 @@ impl<TmSender: EcssTmSender> PusEventHandler<TmSender> {
// telemetry for each event.
let event_reporter = EventReporter::new_with_hook(
PUS_EVENT_MANAGEMENT.raw(),
u11::ZERO,
u11::new(0),
0,
128,
EventApidSetter::default(),
);
)
.unwrap();
let pus_event_dispatcher =
DefaultPusEventU32TmCreator::new_with_default_backend(event_reporter);
let pus_event_man_send_provider = EventU32SenderMpscBounded::new(
@@ -219,7 +219,7 @@ impl<TmSender: EcssTmSender> EventHandler<TmSender> {
#[cfg(test)]
mod tests {
use satrs::{
events_legacy::EventU32,
events::EventU32,
pus::verification::VerificationReporterConfig,
spacepackets::ecss::{tm::PusTmReader, PusPacket},
tmtc::PacketAsVec,
@@ -228,7 +228,7 @@ mod tests {
use super::*;
const TEST_CREATOR_ID: UniqueApidTargetId = UniqueApidTargetId::new(u11::new(1), 2);
const TEST_EVENT: EventU32 = EventU32::new(satrs::events_legacy::Severity::Info, 1, 1);
const TEST_EVENT: EventU32 = EventU32::new(satrs::events::Severity::Info, 1, 1);
pub struct EventManagementTestbench {
pub event_tx: mpsc::SyncSender<EventMessageU32>,
@@ -242,7 +242,8 @@ mod tests {
let (event_tx, event_rx) = mpsc::sync_channel(10);
let (_event_req_tx, event_req_rx) = mpsc::sync_channel(10);
let (tm_sender, tm_receiver) = mpsc::channel();
let verif_reporter_cfg = VerificationReporterConfig::new(u11::new(0x05), 2, 2, 128);
let verif_reporter_cfg =
VerificationReporterConfig::new(u11::new(0x05), 2, 2, 128).unwrap();
let verif_reporter =
VerificationReporter::new(PUS_EVENT_MANAGEMENT.id(), &verif_reporter_cfg);
let mut event_manager = EventManagerWithBoundedMpsc::new(event_rx);
@@ -268,7 +269,7 @@ mod tests {
.event_tx
.send(EventMessageU32::new(
TEST_CREATOR_ID.id(),
EventU32::new(satrs::events_legacy::Severity::Info, 1, 1),
EventU32::new(satrs::events::Severity::Info, 1, 1),
))
.expect("failed to send event");
testbench.pus_event_handler.handle_event_requests();

View File

@@ -2,7 +2,7 @@
use satrs::request::UniqueApidTargetId;
#[derive(Debug, PartialEq, Eq, strum::EnumIter)]
#[bitbybit::bitenum(u11)]
#[bitbybit::bitenum(u11, exhaustive = false)]
pub enum Apid {
Sched = 1,
GenericPus = 2,
@@ -13,7 +13,6 @@ pub enum Apid {
}
pub mod acs {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Id {
Subsystem = 1,

View File

@@ -1,14 +1,13 @@
#![allow(dead_code)]
use std::net::{SocketAddr, UdpSocket};
use std::sync::mpsc;
use log::{info, warn};
use satrs::hal::std::udp_server::{ReceiveResult, UdpTcServer};
use satrs::pus::HandlingStatus;
use satrs::tmtc::{PacketAsVec, StoreAndSendError};
use satrs::pool::{PoolProviderWithGuards, SharedStaticMemoryPool};
use satrs::tmtc::PacketInPool;
use satrs::tmtc::{PacketAsVec, PacketInPool, StoreAndSendError};
use satrs::{
hal::std::udp_server::{ReceiveResult, UdpTcServer},
pool::{PoolProviderWithGuards, SharedStaticMemoryPool},
};
use crate::tmtc::sender::TmTcSender;
@@ -16,6 +15,7 @@ pub trait UdpTmHandler {
fn send_tm_to_udp_client(&mut self, socket: &UdpSocket, recv_addr: &SocketAddr);
}
#[allow(dead_code)]
pub struct StaticUdpTmHandler {
pub tm_rx: mpsc::Receiver<PacketInPool>,
pub tm_store: SharedStaticMemoryPool,

View File

@@ -456,6 +456,7 @@ mod tests {
app_data[4..8].copy_from_slice(&action_id.to_be_bytes());
let pus8_packet =
PusTcCreator::new(sp_header, sec_header, &app_data, CreatorConfig::default());
testbench.add_tc(&pus8_packet);
let time_stamp: [u8; 7] = [0; 7];
testbench.verify_next_tc_is_handled_properly(&time_stamp);

View File

@@ -302,7 +302,7 @@ impl TargetedPusService for HkServiceWrapper {
#[cfg(test)]
mod tests {
use arbitrary_int::traits::Integer as _;
use arbitrary_int::traits::Integer;
use arbitrary_int::u14;
use satrs::pus::test_util::{
TEST_COMPONENT_ID_0, TEST_COMPONENT_ID_1, TEST_UNIQUE_ID_0, TEST_UNIQUE_ID_1,
@@ -327,11 +327,12 @@ mod tests {
use super::{HkReply, HkReplyHandler, HkRequestConverter};
pub const ZERO_SEQ: u14 = u14::ZERO;
#[test]
fn hk_converter_one_shot_req() {
let mut hk_bench =
PusConverterTestbench::new(TEST_COMPONENT_ID_0.id(), HkRequestConverter::default());
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, ZERO_SEQ, 0);
let target_id = TEST_UNIQUE_ID_0;
let unique_id = 5_u32;
let mut app_data: [u8; 8] = [0; 8];
@@ -361,7 +362,7 @@ mod tests {
fn hk_converter_enable_periodic_generation() {
let mut hk_bench =
PusConverterTestbench::new(TEST_COMPONENT_ID_0.id(), HkRequestConverter::default());
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, ZERO_SEQ, 0);
let target_id = TEST_UNIQUE_ID_0;
let unique_id = 5_u32;
let mut app_data: [u8; 8] = [0; 8];
@@ -400,7 +401,7 @@ mod tests {
fn hk_conversion_disable_periodic_generation() {
let mut hk_bench =
PusConverterTestbench::new(TEST_COMPONENT_ID_0.id(), HkRequestConverter::default());
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, ZERO_SEQ, 0);
let target_id = TEST_UNIQUE_ID_0;
let unique_id = 5_u32;
let mut app_data: [u8; 8] = [0; 8];
@@ -439,7 +440,7 @@ mod tests {
fn hk_conversion_modify_interval() {
let mut hk_bench =
PusConverterTestbench::new(TEST_COMPONENT_ID_0.id(), HkRequestConverter::default());
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, ZERO_SEQ, 0);
let target_id = TEST_UNIQUE_ID_0;
let unique_id = 5_u32;
let mut app_data: [u8; 12] = [0; 12];

View File

@@ -33,7 +33,7 @@ pub mod stack;
pub mod test;
pub fn create_verification_reporter(owner_id: ComponentId, apid: Apid) -> VerificationReporter {
let verif_cfg = VerificationReporterConfig::new(apid, 1, 2, 8);
let verif_cfg = VerificationReporterConfig::new(apid, 1, 2, 8).unwrap();
// Every software component which needs to generate verification telemetry, gets a cloned
// verification reporter.
VerificationReporter::new(owner_id, &verif_cfg)

View File

@@ -1,4 +1,3 @@
use arbitrary_int::traits::Integer as _;
use arbitrary_int::u14;
use derive_new::new;
use satrs::mode_tree::{ModeNode, ModeParent};
@@ -80,7 +79,8 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
.write_to_be_bytes(&mut source_data)
.expect("writing mode reply failed");
let req_id = verification::RequestId::from(reply.request_id());
let sp_header = SpHeader::new_for_unseg_tm(req_id.packet_id().apid(), u14::ZERO, 0);
let sp_header =
SpHeader::new_for_unseg_tm(req_id.packet_id().apid(), u14::new(0), 0);
let sec_header =
PusTmSecondaryHeader::new(200, Subservice::TmModeReply as u8, 0, 0, time_stamp);
let pus_tm = PusTmCreator::new(
@@ -298,7 +298,6 @@ impl TargetedPusService for ModeServiceWrapper {
#[cfg(test)]
mod tests {
use arbitrary_int::traits::Integer;
use arbitrary_int::u14;
use satrs::pus::test_util::{TEST_APID, TEST_COMPONENT_ID_0, TEST_UNIQUE_ID_0};
use satrs::request::MessageMetadata;
@@ -325,7 +324,7 @@ mod tests {
fn mode_converter_read_mode_request() {
let mut testbench =
PusConverterTestbench::new(TEST_COMPONENT_ID_0.id(), ModeRequestConverter::default());
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::new(0), 0);
let sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcReadMode as u8);
let mut app_data: [u8; 4] = [0; 4];
app_data[0..4].copy_from_slice(&TEST_UNIQUE_ID_0.to_be_bytes());
@@ -341,7 +340,7 @@ mod tests {
fn mode_converter_set_mode_request() {
let mut testbench =
PusConverterTestbench::new(TEST_COMPONENT_ID_0.id(), ModeRequestConverter::default());
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::new(0), 0);
let sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcSetMode as u8);
let mut app_data: [u8; 4 + ModeAndSubmode::RAW_LEN] = [0; 4 + ModeAndSubmode::RAW_LEN];
let mode_and_submode = ModeAndSubmode::new(2, 1);
@@ -367,7 +366,7 @@ mod tests {
fn mode_converter_announce_mode() {
let mut testbench =
PusConverterTestbench::new(TEST_COMPONENT_ID_0.id(), ModeRequestConverter::default());
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::new(0), 0);
let sec_header = PusTcSecondaryHeader::new_simple(200, Subservice::TcAnnounceMode as u8);
let mut app_data: [u8; 4] = [0; 4];
app_data[0..4].copy_from_slice(&TEST_UNIQUE_ID_0.to_be_bytes());
@@ -383,7 +382,7 @@ mod tests {
fn mode_converter_announce_mode_recursively() {
let mut testbench =
PusConverterTestbench::new(TEST_COMPONENT_ID_0.id(), ModeRequestConverter::default());
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::new(0), 0);
let sec_header =
PusTcSecondaryHeader::new_simple(200, Subservice::TcAnnounceModeRecursive as u8);
let mut app_data: [u8; 4] = [0; 4];

View File

@@ -5,7 +5,7 @@ use crate::pus::create_verification_reporter;
use crate::tmtc::sender::TmTcSender;
use log::info;
use satrs::pool::{PoolProvider, StaticMemoryPool};
use satrs::pus::scheduler::{PusSchedulerAlloc, TcInfo};
use satrs::pus::scheduler::{PusScheduler, TcInfo};
use satrs::pus::scheduler_srv::PusSchedServiceHandler;
use satrs::pus::verification::VerificationReporter;
use satrs::pus::{
@@ -86,7 +86,7 @@ pub struct SchedulingServiceWrapper {
TmTcSender,
EcssTcCacher,
VerificationReporter,
PusSchedulerAlloc,
PusScheduler,
>,
pub sched_tc_pool: StaticMemoryPool,
pub releaser_buf: [u8; 4096],
@@ -179,7 +179,7 @@ pub fn create_scheduler_service(
pus_sched_rx: mpsc::Receiver<EcssTcAndToken>,
sched_tc_pool: StaticMemoryPool,
) -> SchedulingServiceWrapper {
let scheduler = PusSchedulerAlloc::new_with_current_init_time(Duration::from_secs(5))
let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5))
.expect("Creating PUS Scheduler failed");
let pus_11_handler = PusSchedServiceHandler::new(
PusServiceHelper::new(

View File

@@ -1,7 +1,7 @@
use crate::pus::create_verification_reporter;
use crate::tmtc::sender::TmTcSender;
use log::info;
use satrs::event_man_legacy::{EventMessage, EventMessageU32};
use satrs::event_man::{EventMessage, EventMessageU32};
use satrs::pus::test::PusService17TestHandler;
use satrs::pus::verification::{FailParams, VerificationReporter, VerificationReportingProvider};
use satrs::pus::PartialPusHandlingError;

View File

@@ -9,11 +9,13 @@ use satrs::{
pool::PoolProvider,
spacepackets::{
ecss::{tm::PusTmZeroCopyWriter, PusPacket},
seq_count::SequenceCounter,
seq_count::SequenceCounterCcsdsSimple,
time::cds::MIN_CDS_FIELD_LEN,
CcsdsPacket,
},
};
use satrs::{
spacepackets::seq_count::SequenceCounter,
tmtc::{PacketAsVec, PacketInPool, SharedPacketPool},
};

View File

@@ -11,7 +11,7 @@ license = "Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
spacepackets = { version = ">=0.14, <=0.16", default-features = false }
spacepackets = { git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git", version = ">=0.14, <=0.16", default-features = false }
[dependencies.serde]
version = "1"

View File

@@ -8,10 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased]
# [v0.3.0-alpha.3] 2025-09-??
- Bump `sat-rs` edition to 2024.
- Bumped `spacepackets` to v0.16
## Changed
@@ -222,8 +219,7 @@ docs-rs hotfix
Initial release.
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/sat-rs/compare/satrs-v0.3.0-alpha.3...HEAD
[v0.3.0-alpha.3]: https://egit.irs.uni-stuttgart.de/rust/sat-rs/compare/satrs-v0.3.0-alpha.2...satrs-v0.3.0-alpha.3
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/sat-rs/compare/satrs-v0.3.0-alpha.2...HEAD
[v0.3.0-alpha.2]: https://egit.irs.uni-stuttgart.de/rust/sat-rs/compare/satrs-v0.3.0-alpha.1...satrs-v0.3.0-alpha.2
[v0.3.0-alpha.1]: https://egit.irs.uni-stuttgart.de/rust/sat-rs/compare/satrs-v0.3.0-alpha.0...satrs-v0.3.0-alpha.1
[v0.3.0-alpha.0]: https://egit.irs.uni-stuttgart.de/rust/sat-rs/compare/satrs-v0.2.1...satrs-v0.3.0-alpha.0

View File

@@ -14,8 +14,9 @@ categories = ["aerospace", "aerospace::space-protocols", "no-std", "hardware-sup
[dependencies]
satrs-shared = { version = "0.2", path = "../satrs-shared" }
spacepackets = { version = "0.16", default-features = false }
spacepackets = { git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git", version = "0.16", default-features = false }
arbitrary-int = "2"
delegate = ">0.7, <=0.13"
paste = "1"
derive-new = ">=0.6, <=0.7"
@@ -24,16 +25,14 @@ cobs = { version = "0.4", default-features = false }
thiserror = { version = "2", default-features = false }
hashbrown = { version = ">=0.14, <=0.15", optional = true }
static_cell = { version = "2" }
heapless = { version = "0.9", optional = true }
static_cell = { version = "2", optional = true }
dyn-clone = { version = "1", optional = true }
heapless = { version = "0.9", optional = true }
downcast-rs = { version = "2", default-features = false, optional = true }
bus = { version = "2.2", optional = true }
crossbeam-channel = { version = "0.5", default-features = false, optional = true }
postcard = { version = "1", features = ["alloc"] }
serde = { version = "1", default-features = false, optional = true }
socket2 = { version = "0.6", features = ["all"], optional = true }
arbitrary-int = "2"
mio = { version = "1", features = ["os-poll", "net"], optional = true }
defmt = { version = "1", optional = true }
@@ -49,7 +48,7 @@ tempfile = "3"
version = "1"
[features]
default = ["std", "heapless"]
default = ["std"]
std = [
"downcast-rs/std",
"alloc",
@@ -71,7 +70,7 @@ alloc = [
]
serde = ["dep:serde", "spacepackets/serde", "satrs-shared/serde"]
crossbeam = ["crossbeam-channel"]
# heapless = ["dep:heapless", "static_cell"]
heapless = ["dep:heapless", "static_cell"]
defmt = ["dep:defmt", "spacepackets/defmt"]
test_util = []

View File

@@ -1 +0,0 @@
pub mod scheduler;

View File

@@ -1,129 +0,0 @@
use core::{hash::Hash, time::Duration};
#[cfg(feature = "alloc")]
pub use alloc_mod::*;
use spacepackets::{
ByteConversionError, PacketId, PacketSequenceControl,
time::{TimestampError, UnixTime},
};
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ScheduleError {
/// The release time is within the time-margin added on top of the current time.
/// The first parameter is the current time, the second one the time margin, and the third one
/// the release time.
#[error("release time in margin")]
ReleaseTimeInTimeMargin {
current_time: UnixTime,
time_margin: Duration,
release_time: UnixTime,
},
/// Nested time-tagged commands are not allowed.
#[error("nested scheduled tc")]
NestedScheduledTc,
#[error("tc data empty")]
TcDataEmpty,
#[error("timestamp error: {0}")]
TimestampError(#[from] TimestampError),
#[error("wrong subservice number {0}")]
WrongSubservice(u8),
#[error("wrong service number {0}")]
WrongService(u8),
#[error("byte conversion error: {0}")]
ByteConversionError(#[from] ByteConversionError),
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CcsdsPacketId {
pub packet_id: PacketId,
pub psc: PacketSequenceControl,
pub crc16: u16,
}
impl Hash for CcsdsPacketId {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.packet_id.hash(state);
self.psc.raw().hash(state);
self.crc16.hash(state);
}
}
pub mod alloc_mod {
use core::time::Duration;
#[cfg(feature = "std")]
use std::time::SystemTimeError;
use spacepackets::time::UnixTime;
use crate::ccsds::scheduler::CcsdsPacketId;
pub struct CcsdsScheduler {
tc_map: alloc::collections::BTreeMap<
UnixTime,
alloc::vec::Vec<(CcsdsPacketId, alloc::vec::Vec<u8>)>,
>,
packet_limit: usize,
pub(crate) current_time: UnixTime,
time_margin: Duration,
enabled: bool,
}
impl CcsdsScheduler {
pub fn new(current_time: UnixTime, packet_limit: usize, time_margin: Duration) -> Self {
Self {
tc_map: alloc::collections::BTreeMap::new(),
packet_limit,
current_time,
time_margin,
enabled: true,
}
}
/// Like [Self::new], but sets the `init_current_time` parameter to the current system time.
#[cfg(feature = "std")]
pub fn new_with_current_init_time(
packet_limit: usize,
time_margin: Duration,
) -> Result<Self, SystemTimeError> {
Ok(Self::new(UnixTime::now()?, packet_limit, time_margin))
}
pub fn num_of_entries(&self) -> usize {
self.tc_map
.values()
.map(|v| v.iter().map(|(_, v)| v.len()).sum::<usize>())
.sum()
}
#[inline]
pub fn enable(&mut self) {
self.enabled = true;
}
#[inline]
pub fn disable(&mut self) {
self.enabled = false;
}
#[inline]
pub fn update_time(&mut self, current_time: UnixTime) {
self.current_time = current_time;
}
#[inline]
pub fn current_time(&self) -> &UnixTime {
&self.current_time
}
// TODO: Implementation
pub fn insert_telecommand(
&mut self,
packet_id: CcsdsPacketId,
packet: alloc::vec::Vec<u8>,
release_time: UnixTime,
) {
}
}
}

View File

@@ -1,4 +1,4 @@
use spacepackets::SpHeader;
use spacepackets::{CcsdsPacket, SpHeader};
use crate::{ComponentId, tmtc::PacketSenderRaw};

File diff suppressed because it is too large Load Diff

View File

@@ -1,850 +0,0 @@
//! # Event management and forwarding
//!
//! This is a legacy module. It is recommended to use [super::event_man] instead.
//!
//! It is recommended to read the
//! [sat-rs book chapter](https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/book/events.html)
//! about events first.
//!
//! This module provides components to perform event routing. The most important component for this
//! task is the [EventManager]. It receives all events and then routes them to event subscribers
//! where appropriate.
//!
//! The event manager has a listener table abstracted by the [ListenerMapProvider], which maps
//! listener groups identified by [ListenerKey]s to a [listener ID][ComponentId].
//! It also contains a sender table abstracted by the [SenderMapProvider] which maps these sender
//! IDs to concrete [EventSendProvider]s. A simple approach would be to use one send event provider
//! for each OBSW thread and then subscribe for all interesting events for a particular thread
//! using the send event provider ID.
//!
//! This can be done with the [EventManager] like this:
//!
//! 1. Provide a concrete [EventReceiveProvider] implementation. This abstraction allow to use different
//! message queue backends. A straightforward implementation where dynamic memory allocation is
//! not a big concern would be to use the [std::sync::mpsc::Receiver] handle. The trait is
//! already implemented for this type.
//! 2. To set up event creators, create channel pairs using some message queue implementation.
//! Each event creator gets a (cloned) sender component which allows it to send events to the
//! manager.
//! 3. The event manager receives the receiver component as part of a [EventReceiveProvider]
//! implementation so all events are routed to the manager.
//! 4. Create the [event sender map][SenderMapProvider]s which allow routing events to
//! subscribers. You can now use the subscriber component IDs to subscribe
//! for event groups, for example by using the [EventManager::subscribe_single] method.
//! 5. Add the send provider as well using the [EventManager::add_sender] call so the event
//! manager can route listener groups to a the send provider.
//!
//! Some components like a PUS Event Service or PUS Event Action Service might require all
//! events to package them as telemetry or start actions where applicable.
//! Other components might only be interested in certain events. For example, a thermal system
//! handler might only be interested in temperature events generated by a thermal sensor component.
//!
//! # Examples
//!
//! You can check [integration test](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs/tests/pus_events.rs)
//! for a concrete example using multi-threading where events are routed to
//! different threads.
//!
//! The [satrs-example](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example)
//! also contains a full event manager instance and exposes a test event via the PUS test service.
//! The [PUS event](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example/src/pus/event.rs)
//! module and the generic [events module](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example/src/events.rs)
//! show how the event management modules can be integrated into a more complex software.
use crate::events_legacy::{EventU16, EventU32, GenericEvent, LargestEventRaw, LargestGroupIdRaw};
use crate::params::Params;
use crate::queue::GenericSendError;
use core::fmt::Debug;
use core::marker::PhantomData;
use core::slice::Iter;
use crate::ComponentId;
#[cfg(feature = "alloc")]
pub use alloc_mod::*;
#[cfg(feature = "std")]
pub use std_mod::*;
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum ListenerKey {
Single(LargestEventRaw),
Group(LargestGroupIdRaw),
All,
}
#[derive(Debug)]
pub struct EventMessage<Event: GenericEvent, Parameters: Debug = Params> {
sender_id: ComponentId,
event: Event,
params: Option<Parameters>,
}
impl<Event: GenericEvent, Parameters: Debug + Clone> EventMessage<Event, Parameters> {
pub fn new_generic(sender_id: ComponentId, event: Event, params: Option<&Parameters>) -> Self {
Self {
sender_id,
event,
params: params.cloned(),
}
}
pub fn sender_id(&self) -> ComponentId {
self.sender_id
}
pub fn event(&self) -> Event {
self.event
}
pub fn params(&self) -> Option<&Parameters> {
self.params.as_ref()
}
pub fn new(sender_id: ComponentId, event: Event) -> Self {
Self::new_generic(sender_id, event, None)
}
pub fn new_with_params(sender_id: ComponentId, event: Event, params: &Parameters) -> Self {
Self::new_generic(sender_id, event, Some(params))
}
}
pub type EventMessageU32 = EventMessage<EventU32, Params>;
pub type EventMessageU16 = EventMessage<EventU16, Params>;
/// Generic abstraction
pub trait EventSendProvider<Event: GenericEvent, ParamProvider: Debug = Params> {
type Error;
fn target_id(&self) -> ComponentId;
fn send(&self, message: EventMessage<Event, ParamProvider>) -> Result<(), Self::Error>;
}
/// Generic abstraction for an event receiver.
pub trait EventReceiveProvider<Event: GenericEvent, ParamsProvider: Debug = Params> {
type Error;
/// This function has to be provided by any event receiver. A call may or may not return
/// an event and optional auxiliary data.
fn try_recv_event(&self) -> Result<Option<EventMessage<Event, ParamsProvider>>, Self::Error>;
}
pub trait ListenerMapProvider {
#[cfg(feature = "alloc")]
fn get_listeners(&self) -> alloc::vec::Vec<ListenerKey>;
fn contains_listener(&self, key: &ListenerKey) -> bool;
fn get_listener_ids(&self, key: &ListenerKey) -> Option<Iter<'_, ComponentId>>;
fn add_listener(&mut self, key: ListenerKey, listener_id: ComponentId) -> bool;
fn remove_duplicates(&mut self, key: &ListenerKey);
}
pub trait SenderMapProvider<
EventSender: EventSendProvider<Event, ParamProvider>,
Event: GenericEvent = EventU32,
ParamProvider: Debug = Params,
>
{
fn contains_send_event_provider(&self, target_id: &ComponentId) -> bool;
fn get_send_event_provider(&self, target_id: &ComponentId) -> Option<&EventSender>;
fn add_send_event_provider(&mut self, send_provider: EventSender) -> bool;
}
/// Generic event manager implementation.
///
/// # Generics
///
/// * `EventReceiver`: [EventReceiveProvider] used to receive all events.
/// * `SenderMap`: [SenderMapProvider] which maps channel IDs to send providers.
/// * `ListenerMap`: [ListenerMapProvider] which maps listener keys to channel IDs.
/// * `EventSender`: [EventSendProvider] contained within the sender map which sends the events.
/// * `Event`: The event type. This type must implement the [GenericEvent]. Currently only [EventU32]
/// and [EventU16] are supported.
/// * `ParamProvider`: Auxiliary data which is sent with the event to provide optional context
/// information
pub struct EventManager<
EventReceiver: EventReceiveProvider<Event, ParamProvider>,
SenderMap: SenderMapProvider<EventSender, Event, ParamProvider>,
ListenerMap: ListenerMapProvider,
EventSender: EventSendProvider<Event, ParamProvider>,
Event: GenericEvent = EventU32,
ParamProvider: Debug = Params,
> {
event_receiver: EventReceiver,
sender_map: SenderMap,
listener_map: ListenerMap,
phantom: core::marker::PhantomData<(EventSender, Event, ParamProvider)>,
}
#[derive(Debug)]
pub enum EventRoutingResult<Event: GenericEvent, ParamProvider: Debug> {
/// No event was received
Empty,
/// An event was received and routed to listeners.
Handled {
num_recipients: u32,
event_msg: EventMessage<Event, ParamProvider>,
},
}
#[derive(Debug)]
pub enum EventRoutingError {
Send(GenericSendError),
NoSendersForKey(ListenerKey),
NoSenderForId(ComponentId),
}
impl<
EventReceiver: EventReceiveProvider<Event, ParamProvider>,
SenderMap: SenderMapProvider<EventSender, Event, ParamProvider>,
ListenerMap: ListenerMapProvider,
EventSender: EventSendProvider<Event, ParamProvider>,
Event: GenericEvent + Copy,
ParamProvider: Debug,
> EventManager<EventReceiver, SenderMap, ListenerMap, EventSender, Event, ParamProvider>
{
pub fn remove_duplicates(&mut self, key: &ListenerKey) {
self.listener_map.remove_duplicates(key)
}
/// Subscribe for a unique event.
pub fn subscribe_single(&mut self, event: &Event, sender_id: ComponentId) {
self.update_listeners(ListenerKey::Single(event.raw_as_largest_type()), sender_id);
}
/// Subscribe for an event group.
pub fn subscribe_group(&mut self, group_id: LargestGroupIdRaw, sender_id: ComponentId) {
self.update_listeners(ListenerKey::Group(group_id), sender_id);
}
/// Subscribe for all events received by the manager.
///
/// For example, this can be useful for a handler component which sends every event as
/// a telemetry packet.
pub fn subscribe_all(&mut self, sender_id: ComponentId) {
self.update_listeners(ListenerKey::All, sender_id);
}
}
impl<
EventReceiver: EventReceiveProvider<Event, ParamProvider>,
SenderMap: SenderMapProvider<EventSenderMap, Event, ParamProvider>,
ListenerMap: ListenerMapProvider,
EventSenderMap: EventSendProvider<Event, ParamProvider>,
Event: GenericEvent + Copy,
ParamProvider: Debug,
> EventManager<EventReceiver, SenderMap, ListenerMap, EventSenderMap, Event, ParamProvider>
{
pub fn new_with_custom_maps(
event_receiver: EventReceiver,
sender_map: SenderMap,
listener_map: ListenerMap,
) -> Self {
EventManager {
listener_map,
sender_map,
event_receiver,
phantom: PhantomData,
}
}
/// Add a new sender component which can be used to send events to subscribers.
pub fn add_sender(&mut self, send_provider: EventSenderMap) {
if !self
.sender_map
.contains_send_event_provider(&send_provider.target_id())
{
self.sender_map.add_send_event_provider(send_provider);
}
}
/// Generic function to update the event subscribers.
fn update_listeners(&mut self, key: ListenerKey, sender_id: ComponentId) {
self.listener_map.add_listener(key, sender_id);
}
}
impl<
EventReceiver: EventReceiveProvider<Event, ParamProvider>,
SenderMap: SenderMapProvider<EventSenderMap, Event, ParamProvider>,
ListenerMap: ListenerMapProvider,
EventSenderMap: EventSendProvider<Event, ParamProvider, Error = GenericSendError>,
Event: GenericEvent + Copy,
ParamProvider: Clone + Debug,
> EventManager<EventReceiver, SenderMap, ListenerMap, EventSenderMap, Event, ParamProvider>
{
/// This function will use the cached event receiver and try to receive one event.
/// If an event was received, it will try to route that event to all subscribed event listeners.
/// If this works without any issues, the [EventRoutingResult] will contain context information
/// about the routed event.
///
/// If an error occurs during the routing, the error handler will be called. The error handler
/// should take a reference to the event message as the first argument, and the routing error
/// as the second argument.
pub fn try_event_handling<E: FnMut(&EventMessage<Event, ParamProvider>, EventRoutingError)>(
&self,
mut error_handler: E,
) -> EventRoutingResult<Event, ParamProvider> {
let mut num_recipients = 0;
let mut send_handler =
|key: &ListenerKey, event_msg: &EventMessage<Event, ParamProvider>| {
if self.listener_map.contains_listener(key) {
if let Some(ids) = self.listener_map.get_listener_ids(key) {
for id in ids {
if let Some(sender) = self.sender_map.get_send_event_provider(id) {
if let Err(e) = sender.send(EventMessage::new_generic(
event_msg.sender_id,
event_msg.event,
event_msg.params.as_ref(),
)) {
error_handler(event_msg, EventRoutingError::Send(e));
} else {
num_recipients += 1;
}
} else {
error_handler(event_msg, EventRoutingError::NoSenderForId(*id));
}
}
} else {
error_handler(event_msg, EventRoutingError::NoSendersForKey(*key));
}
}
};
if let Ok(Some(event_msg)) = self.event_receiver.try_recv_event() {
let single_key = ListenerKey::Single(event_msg.event.raw_as_largest_type());
send_handler(&single_key, &event_msg);
let group_key = ListenerKey::Group(event_msg.event.group_id_as_largest_type());
send_handler(&group_key, &event_msg);
send_handler(&ListenerKey::All, &event_msg);
return EventRoutingResult::Handled {
num_recipients,
event_msg,
};
}
EventRoutingResult::Empty
}
}
#[cfg(feature = "alloc")]
pub mod alloc_mod {
use alloc::vec::Vec;
use hashbrown::HashMap;
use super::*;
/// Helper type which constrains the sender map and listener map generics to the [DefaultSenderMap]
/// and the [DefaultListenerMap]. It uses regular mpsc channels as the message queue backend.
pub type EventManagerWithMpsc<Event = EventU32, ParamProvider = Params> = EventManager<
EventU32ReceiverMpsc<ParamProvider>,
DefaultSenderMap<EventSenderMpsc<Event>, Event, ParamProvider>,
DefaultListenerMap,
EventSenderMpsc<Event>,
>;
/// Helper type which constrains the sender map and listener map generics to the [DefaultSenderMap]
/// and the [DefaultListenerMap]. It uses
/// [bounded mpsc senders](https://doc.rust-lang.org/std/sync/mpsc/struct.SyncSender.html) as the
/// message queue backend.
pub type EventManagerWithBoundedMpsc<Event = EventU32, ParamProvider = Params> = EventManager<
EventU32ReceiverMpsc<ParamProvider>,
DefaultSenderMap<EventSenderMpscBounded<Event>, Event, ParamProvider>,
DefaultListenerMap,
EventSenderMpscBounded<Event>,
>;
impl<
EventReceiver: EventReceiveProvider<Event, ParamProvider>,
EventSender: EventSendProvider<Event, ParamProvider>,
Event: GenericEvent + Copy,
ParamProvider: 'static + Debug,
>
EventManager<
EventReceiver,
DefaultSenderMap<EventSender, Event, ParamProvider>,
DefaultListenerMap,
EventSender,
Event,
ParamProvider,
>
{
/// Create an event manager where the sender table will be the [DefaultSenderMap]
/// and the listener table will be the [DefaultListenerMap].
pub fn new(event_receiver: EventReceiver) -> Self {
Self {
listener_map: DefaultListenerMap::default(),
sender_map: DefaultSenderMap::default(),
event_receiver,
phantom: PhantomData,
}
}
}
/// Default listener map.
///
/// Simple implementation which uses a [HashMap] and a [Vec] internally.
#[derive(Default)]
pub struct DefaultListenerMap {
listeners: HashMap<ListenerKey, Vec<ComponentId>>,
}
impl ListenerMapProvider for DefaultListenerMap {
fn get_listeners(&self) -> Vec<ListenerKey> {
let mut key_list = Vec::new();
for key in self.listeners.keys() {
key_list.push(*key);
}
key_list
}
fn contains_listener(&self, key: &ListenerKey) -> bool {
self.listeners.contains_key(key)
}
fn get_listener_ids(&self, key: &ListenerKey) -> Option<Iter<'_, ComponentId>> {
self.listeners.get(key).map(|vec| vec.iter())
}
fn add_listener(&mut self, key: ListenerKey, sender_id: ComponentId) -> bool {
if let Some(existing_list) = self.listeners.get_mut(&key) {
existing_list.push(sender_id);
} else {
let new_list = alloc::vec![sender_id];
self.listeners.insert(key, new_list);
}
true
}
fn remove_duplicates(&mut self, key: &ListenerKey) {
if let Some(list) = self.listeners.get_mut(key) {
list.sort_unstable();
list.dedup();
}
}
}
/// Default sender map.
///
/// Simple implementation which uses a [HashMap] internally.
pub struct DefaultSenderMap<
EventSender: EventSendProvider<Event, ParamProvider>,
Event: GenericEvent = EventU32,
ParamProvider: Debug = Params,
> {
senders: HashMap<ComponentId, EventSender>,
phantom: PhantomData<(Event, ParamProvider)>,
}
impl<
EventSender: EventSendProvider<Event, ParamProvider>,
Event: GenericEvent,
ParamProvider: Debug,
> Default for DefaultSenderMap<EventSender, Event, ParamProvider>
{
fn default() -> Self {
Self {
senders: Default::default(),
phantom: Default::default(),
}
}
}
impl<
EventSender: EventSendProvider<Event, ParamProvider>,
Event: GenericEvent,
ParamProvider: Debug,
> SenderMapProvider<EventSender, Event, ParamProvider>
for DefaultSenderMap<EventSender, Event, ParamProvider>
{
fn contains_send_event_provider(&self, id: &ComponentId) -> bool {
self.senders.contains_key(id)
}
fn get_send_event_provider(&self, id: &ComponentId) -> Option<&EventSender> {
self.senders
.get(id)
.filter(|sender| sender.target_id() == *id)
}
fn add_send_event_provider(&mut self, send_provider: EventSender) -> bool {
let id = send_provider.target_id();
if self.senders.contains_key(&id) {
return false;
}
self.senders.insert(id, send_provider).is_none()
}
}
}
#[cfg(feature = "std")]
pub mod std_mod {
use crate::queue::GenericReceiveError;
use super::*;
use std::sync::mpsc;
impl<Event: GenericEvent + Send, ParamProvider: Debug>
EventReceiveProvider<Event, ParamProvider>
for mpsc::Receiver<EventMessage<Event, ParamProvider>>
{
type Error = GenericReceiveError;
fn try_recv_event(
&self,
) -> Result<Option<EventMessage<Event, ParamProvider>>, Self::Error> {
match self.try_recv() {
Ok(msg) => Ok(Some(msg)),
Err(e) => match e {
mpsc::TryRecvError::Empty => Ok(None),
mpsc::TryRecvError::Disconnected => {
Err(GenericReceiveError::TxDisconnected(None))
}
},
}
}
}
pub type EventU32ReceiverMpsc<ParamProvider = Params> =
mpsc::Receiver<EventMessage<EventU32, ParamProvider>>;
pub type EventU16ReceiverMpsc<ParamProvider = Params> =
mpsc::Receiver<EventMessage<EventU16, ParamProvider>>;
/// Generic event sender which uses a regular [mpsc::Sender] as the messaging backend to
/// send events.
#[derive(Clone)]
pub struct EventSenderMpsc<Event: GenericEvent + Send> {
target_id: ComponentId,
sender: mpsc::Sender<EventMessage<Event>>,
}
impl<Event: GenericEvent + Send> EventSenderMpsc<Event> {
pub fn new(target_id: ComponentId, sender: mpsc::Sender<EventMessage<Event>>) -> Self {
Self { target_id, sender }
}
}
impl<Event: GenericEvent + Send> EventSendProvider<Event> for EventSenderMpsc<Event> {
type Error = GenericSendError;
fn target_id(&self) -> ComponentId {
self.target_id
}
fn send(&self, event_msg: EventMessage<Event>) -> Result<(), GenericSendError> {
self.sender
.send(event_msg)
.map_err(|_| GenericSendError::RxDisconnected)
}
}
/// Generic event sender which uses the [mpsc::SyncSender] as the messaging backend to send
/// events. This has the advantage that the channel is bounded and thus more deterministic.
#[derive(Clone)]
pub struct EventSenderMpscBounded<Event: GenericEvent + Send> {
target_id: ComponentId,
sender: mpsc::SyncSender<EventMessage<Event>>,
capacity: usize,
}
impl<Event: GenericEvent + Send> EventSenderMpscBounded<Event> {
pub fn new(
target_id: ComponentId,
sender: mpsc::SyncSender<EventMessage<Event>>,
capacity: usize,
) -> Self {
Self {
target_id,
sender,
capacity,
}
}
}
impl<Event: GenericEvent + Send> EventSendProvider<Event> for EventSenderMpscBounded<Event> {
type Error = GenericSendError;
fn target_id(&self) -> ComponentId {
self.target_id
}
fn send(&self, event_msg: EventMessage<Event>) -> Result<(), Self::Error> {
if let Err(e) = self.sender.try_send(event_msg) {
return match e {
mpsc::TrySendError::Full(_) => {
Err(GenericSendError::QueueFull(Some(self.capacity as u32)))
}
mpsc::TrySendError::Disconnected(_) => Err(GenericSendError::RxDisconnected),
};
}
Ok(())
}
}
pub type EventU32SenderMpsc = EventSenderMpsc<EventU32>;
pub type EventU16SenderMpsc = EventSenderMpsc<EventU16>;
pub type EventU32SenderMpscBounded = EventSenderMpscBounded<EventU32>;
pub type EventU16SenderMpscBounded = EventSenderMpscBounded<EventU16>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::event_man_legacy::EventManager;
use crate::events_legacy::{EventU32, GenericEvent, Severity};
use crate::params::{ParamsHeapless, ParamsRaw};
use crate::pus::test_util::{TEST_COMPONENT_ID_0, TEST_COMPONENT_ID_1};
use std::format;
use std::sync::mpsc::{self};
const TEST_EVENT: EventU32 = EventU32::new(Severity::Info, 0, 5);
fn check_next_event(
expected: EventU32,
receiver: &mpsc::Receiver<EventMessageU32>,
) -> Option<Params> {
if let Ok(event_msg) = receiver.try_recv() {
assert_eq!(event_msg.event, expected);
return event_msg.params;
}
None
}
fn check_handled_event(
res: EventRoutingResult<EventU32, Params>,
expected: EventU32,
expected_num_sent: u32,
expected_sender_id: ComponentId,
) {
assert!(matches!(res, EventRoutingResult::Handled { .. }));
if let EventRoutingResult::Handled {
num_recipients,
event_msg,
} = res
{
assert_eq!(event_msg.event, expected);
assert_eq!(event_msg.sender_id, expected_sender_id);
assert_eq!(num_recipients, expected_num_sent);
}
}
fn generic_event_man() -> (mpsc::Sender<EventMessageU32>, EventManagerWithMpsc) {
let (event_sender, event_receiver) = mpsc::channel();
(event_sender, EventManager::new(event_receiver))
}
#[test]
fn test_basic() {
let (event_sender, mut event_man) = generic_event_man();
let event_grp_0 = EventU32::new(Severity::Info, 0, 0);
let event_grp_1_0 = EventU32::new(Severity::High, 1, 0);
let (single_event_sender, single_event_receiver) = mpsc::channel();
let single_event_listener = EventSenderMpsc::new(0, single_event_sender);
event_man.subscribe_single(&event_grp_0, single_event_listener.target_id());
event_man.add_sender(single_event_listener);
let (group_event_sender_0, group_event_receiver_0) = mpsc::channel();
let group_event_listener = EventU32SenderMpsc::new(1, group_event_sender_0);
event_man.subscribe_group(event_grp_1_0.group_id(), group_event_listener.target_id());
event_man.add_sender(group_event_listener);
let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| {
panic!("routing error occurred for event {:?}: {:?}", event_msg, e);
};
// Test event with one listener
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_grp_0))
.expect("Sending single error failed");
let res = event_man.try_event_handling(&error_handler);
check_handled_event(res, event_grp_0, 1, TEST_COMPONENT_ID_0.id());
check_next_event(event_grp_0, &single_event_receiver);
// Test event which is sent to all group listeners
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_grp_1_0))
.expect("Sending group error failed");
let res = event_man.try_event_handling(&error_handler);
check_handled_event(res, event_grp_1_0, 1, TEST_COMPONENT_ID_1.id());
check_next_event(event_grp_1_0, &group_event_receiver_0);
}
#[test]
fn test_with_basic_params() {
let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| {
panic!("routing error occurred for event {:?}: {:?}", event_msg, e);
};
let (event_sender, mut event_man) = generic_event_man();
let event_grp_0 = EventU32::new(Severity::Info, 0, 0);
let (single_event_sender, single_event_receiver) = mpsc::channel();
let single_event_listener = EventSenderMpsc::new(0, single_event_sender);
event_man.subscribe_single(&event_grp_0, single_event_listener.target_id());
event_man.add_sender(single_event_listener);
event_sender
.send(EventMessage::new_with_params(
TEST_COMPONENT_ID_0.id(),
event_grp_0,
&Params::Heapless((2_u32, 3_u32).into()),
))
.expect("Sending group error failed");
let res = event_man.try_event_handling(&error_handler);
check_handled_event(res, event_grp_0, 1, TEST_COMPONENT_ID_0.id());
let aux = check_next_event(event_grp_0, &single_event_receiver);
assert!(aux.is_some());
let aux = aux.unwrap();
if let Params::Heapless(ParamsHeapless::Raw(ParamsRaw::U32Pair(pair))) = aux {
assert_eq!(pair.0, 2);
assert_eq!(pair.1, 3);
} else {
panic!("{}", format!("Unexpected auxiliary value type {:?}", aux));
}
}
/// Test listening for multiple groups
#[test]
fn test_multi_group() {
let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| {
panic!("routing error occurred for event {:?}: {:?}", event_msg, e);
};
let (event_sender, mut event_man) = generic_event_man();
let res = event_man.try_event_handling(error_handler);
assert!(matches!(res, EventRoutingResult::Empty));
let event_grp_0 = EventU32::new(Severity::Info, 0, 0);
let event_grp_1_0 = EventU32::new(Severity::High, 1, 0);
let (event_grp_0_sender, event_grp_0_receiver) = mpsc::channel();
let event_grp_0_and_1_listener = EventU32SenderMpsc::new(0, event_grp_0_sender);
event_man.subscribe_group(
event_grp_0.group_id(),
event_grp_0_and_1_listener.target_id(),
);
event_man.subscribe_group(
event_grp_1_0.group_id(),
event_grp_0_and_1_listener.target_id(),
);
event_man.add_sender(event_grp_0_and_1_listener);
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_grp_0))
.expect("Sending Event Group 0 failed");
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_grp_1_0))
.expect("Sendign Event Group 1 failed");
let res = event_man.try_event_handling(error_handler);
check_handled_event(res, event_grp_0, 1, TEST_COMPONENT_ID_0.id());
let res = event_man.try_event_handling(error_handler);
check_handled_event(res, event_grp_1_0, 1, TEST_COMPONENT_ID_1.id());
check_next_event(event_grp_0, &event_grp_0_receiver);
check_next_event(event_grp_1_0, &event_grp_0_receiver);
}
/// Test listening to the same event from multiple listeners. Also test listening
/// to both group and single events from one listener
#[test]
fn test_listening_to_same_event_and_multi_type() {
let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| {
panic!("routing error occurred for event {:?}: {:?}", event_msg, e);
};
let (event_sender, mut event_man) = generic_event_man();
let event_0 = EventU32::new(Severity::Info, 0, 5);
let event_1 = EventU32::new(Severity::High, 1, 0);
let (event_0_tx_0, event_0_rx_0) = mpsc::channel();
let (event_0_tx_1, event_0_rx_1) = mpsc::channel();
let event_listener_0 = EventU32SenderMpsc::new(0, event_0_tx_0);
let event_listener_1 = EventU32SenderMpsc::new(1, event_0_tx_1);
let event_listener_0_sender_id = event_listener_0.target_id();
event_man.subscribe_single(&event_0, event_listener_0_sender_id);
event_man.add_sender(event_listener_0);
let event_listener_1_sender_id = event_listener_1.target_id();
event_man.subscribe_single(&event_0, event_listener_1_sender_id);
event_man.add_sender(event_listener_1);
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_0))
.expect("Triggering Event 0 failed");
let res = event_man.try_event_handling(error_handler);
check_handled_event(res, event_0, 2, TEST_COMPONENT_ID_0.id());
check_next_event(event_0, &event_0_rx_0);
check_next_event(event_0, &event_0_rx_1);
event_man.subscribe_group(event_1.group_id(), event_listener_0_sender_id);
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_0))
.expect("Triggering Event 0 failed");
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_1))
.expect("Triggering Event 1 failed");
// 3 Events messages will be sent now
let res = event_man.try_event_handling(error_handler);
check_handled_event(res, event_0, 2, TEST_COMPONENT_ID_0.id());
let res = event_man.try_event_handling(error_handler);
check_handled_event(res, event_1, 1, TEST_COMPONENT_ID_1.id());
// Both the single event and the group event should arrive now
check_next_event(event_0, &event_0_rx_0);
check_next_event(event_1, &event_0_rx_0);
// Do double insertion and then remove duplicates
event_man.subscribe_group(event_1.group_id(), event_listener_0_sender_id);
event_man.remove_duplicates(&ListenerKey::Group(event_1.group_id()));
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_1))
.expect("Triggering Event 1 failed");
let res = event_man.try_event_handling(error_handler);
check_handled_event(res, event_1, 1, TEST_COMPONENT_ID_0.id());
}
#[test]
fn test_all_events_listener() {
let error_handler = |event_msg: &EventMessageU32, e: EventRoutingError| {
panic!("routing error occurred for event {:?}: {:?}", event_msg, e);
};
let (event_sender, event_receiver) = mpsc::channel();
let mut event_man = EventManagerWithMpsc::new(event_receiver);
let event_0 = EventU32::new(Severity::Info, 0, 5);
let event_1 = EventU32::new(Severity::High, 1, 0);
let (event_0_tx_0, all_events_rx) = mpsc::channel();
let all_events_listener = EventU32SenderMpsc::new(0, event_0_tx_0);
event_man.subscribe_all(all_events_listener.target_id());
event_man.add_sender(all_events_listener);
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), event_0))
.expect("Triggering event 0 failed");
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_1.id(), event_1))
.expect("Triggering event 1 failed");
let res = event_man.try_event_handling(error_handler);
check_handled_event(res, event_0, 1, TEST_COMPONENT_ID_0.id());
let res = event_man.try_event_handling(error_handler);
check_handled_event(res, event_1, 1, TEST_COMPONENT_ID_1.id());
check_next_event(event_0, &all_events_rx);
check_next_event(event_1, &all_events_rx);
}
#[test]
fn test_bounded_event_sender_queue_full() {
let (event_sender, _event_receiver) = mpsc::sync_channel(3);
let event_sender = EventU32SenderMpscBounded::new(1, event_sender, 3);
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT))
.expect("sending test event failed");
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT))
.expect("sending test event failed");
event_sender
.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT))
.expect("sending test event failed");
let error = event_sender.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT));
if let Err(e) = error {
assert!(matches!(e, GenericSendError::QueueFull(Some(3))));
} else {
panic!("unexpected error {error:?}");
}
}
#[test]
fn test_bounded_event_sender_rx_dropped() {
let (event_sender, event_receiver) = mpsc::sync_channel(3);
let event_sender = EventU32SenderMpscBounded::new(1, event_sender, 3);
drop(event_receiver);
if let Err(e) = event_sender.send(EventMessage::new(TEST_COMPONENT_ID_0.id(), TEST_EVENT)) {
assert!(matches!(e, GenericSendError::RxDisconnected));
} else {
panic!("Expected error");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,859 +0,0 @@
//! # Event support module
//!
//! This is a legacy module. It is recommended to use [super::events] instead.
//!
//! This module includes the basic event structs [EventU32] and [EventU16] and versions with the
//! ECSS severity levels as a type parameter. These structs are simple abstractions on top of the
//! [u32] and [u16] types where the raw value is the unique identifier for a particular event.
//! The abstraction also allows to group related events using a group ID, and the severity
//! of an event is encoded inside the raw value itself with four possible [Severity] levels:
//!
//! - INFO
//! - LOW
//! - MEDIUM
//! - HIGH
//!
//! All event structs implement the [EcssEnumeration] trait and can be created as constants.
//! This allows to easily create a static list of constant events which can then be used to generate
//! event telemetry using the PUS event manager modules.
//!
//! # Examples
//!
//! ```
//! use satrs::events_legacy::{EventU16, EventU32, EventU32TypedSev, Severity, SeverityHigh, SeverityInfo};
//!
//! const MSG_RECVD: EventU32TypedSev<SeverityInfo> = EventU32TypedSev::new(1, 0);
//! const MSG_FAILED: EventU32 = EventU32::new(Severity::Low, 1, 1);
//!
//! const TEMPERATURE_HIGH: EventU32TypedSev<SeverityHigh> = EventU32TypedSev::new(2, 0);
//!
//! let small_event = EventU16::new(Severity::Info, 3, 0);
//! ```
use core::fmt::Debug;
use core::hash::Hash;
use core::marker::PhantomData;
use delegate::delegate;
use spacepackets::ByteConversionError;
use spacepackets::ecss::EcssEnumeration;
use spacepackets::util::{ToBeBytes, UnsignedEnum};
/// Using a type definition allows to change this to u64 in the future more easily
pub type LargestEventRaw = u32;
/// Using a type definition allows to change this to u32 in the future more easily
pub type LargestGroupIdRaw = u16;
pub const MAX_GROUP_ID_U32_EVENT: u16 = 2_u16.pow(14) - 1;
pub const MAX_GROUP_ID_U16_EVENT: u16 = 2_u16.pow(6) - 1;
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Severity {
Info = 0,
Low = 1,
Medium = 2,
High = 3,
}
pub trait HasSeverity: Debug + PartialEq + Eq + Copy + Clone {
const SEVERITY: Severity;
}
/// Type level support struct
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct SeverityInfo {}
impl HasSeverity for SeverityInfo {
const SEVERITY: Severity = Severity::Info;
}
/// Type level support struct
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct SeverityLow {}
impl HasSeverity for SeverityLow {
const SEVERITY: Severity = Severity::Low;
}
/// Type level support struct
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct SeverityMedium {}
impl HasSeverity for SeverityMedium {
const SEVERITY: Severity = Severity::Medium;
}
/// Type level support struct
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct SeverityHigh {}
impl HasSeverity for SeverityHigh {
const SEVERITY: Severity = Severity::High;
}
pub trait GenericEvent: EcssEnumeration + Copy + Clone {
type Raw;
type GroupId;
type UniqueId;
fn raw(&self) -> Self::Raw;
fn severity(&self) -> Severity;
fn group_id(&self) -> Self::GroupId;
fn unique_id(&self) -> Self::UniqueId;
fn raw_as_largest_type(&self) -> LargestEventRaw;
fn group_id_as_largest_type(&self) -> LargestGroupIdRaw;
}
impl TryFrom<u8> for Severity {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
x if x == Severity::Info as u8 => Ok(Severity::Info),
x if x == Severity::Low as u8 => Ok(Severity::Low),
x if x == Severity::Medium as u8 => Ok(Severity::Medium),
x if x == Severity::High as u8 => Ok(Severity::High),
_ => Err(()),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
struct EventBase<Raw, GroupId, UniqueId> {
severity: Severity,
group_id: GroupId,
unique_id: UniqueId,
phantom: PhantomData<Raw>,
}
impl<Raw: ToBeBytes, GroupId, UniqueId> EventBase<Raw, GroupId, UniqueId> {
fn write_to_bytes(
&self,
raw: Raw,
buf: &mut [u8],
width: usize,
) -> Result<usize, ByteConversionError> {
if buf.len() < width {
return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(),
expected: width,
});
}
buf.copy_from_slice(raw.to_be_bytes().as_ref());
Ok(raw.written_len())
}
}
impl EventBase<u32, u16, u16> {
#[inline]
fn raw(&self) -> u32 {
((self.severity as u32) << 30) | ((self.group_id as u32) << 16) | self.unique_id as u32
}
}
impl EventBase<u16, u8, u8> {
#[inline]
fn raw(&self) -> u16 {
((self.severity as u16) << 14) | ((self.group_id as u16) << 8) | self.unique_id as u16
}
}
impl<RAW, GID, UID> EventBase<RAW, GID, UID> {
#[inline]
pub fn severity(&self) -> Severity {
self.severity
}
}
impl<RAW, GID> EventBase<RAW, GID, u16> {
#[inline]
pub fn unique_id(&self) -> u16 {
self.unique_id
}
}
impl<RAW, GID> EventBase<RAW, GID, u8> {
#[inline]
pub fn unique_id(&self) -> u8 {
self.unique_id
}
}
impl<RAW, UID> EventBase<RAW, u16, UID> {
#[inline]
pub fn group_id(&self) -> u16 {
self.group_id
}
}
impl<RAW, UID> EventBase<RAW, u8, UID> {
#[inline]
pub fn group_id(&self) -> u8 {
self.group_id
}
}
macro_rules! event_provider_impl {
() => {
#[inline]
fn raw(&self) -> Self::Raw {
self.base.raw()
}
/// Retrieve the severity of an event. Returns None if that severity bit field of the raw event
/// ID is invalid
#[inline]
fn severity(&self) -> Severity {
self.base.severity()
}
#[inline]
fn group_id(&self) -> Self::GroupId {
self.base.group_id()
}
#[inline]
fn unique_id(&self) -> Self::UniqueId {
self.base.unique_id()
}
};
}
macro_rules! impl_event_provider {
($BaseIdent: ident, $TypedIdent: ident, $raw: ty, $gid: ty, $uid: ty) => {
impl GenericEvent for $BaseIdent {
type Raw = $raw;
type GroupId = $gid;
type UniqueId = $uid;
event_provider_impl!();
fn raw_as_largest_type(&self) -> LargestEventRaw {
self.raw().into()
}
fn group_id_as_largest_type(&self) -> LargestGroupIdRaw {
self.group_id().into()
}
}
impl<SEVERITY: HasSeverity> GenericEvent for $TypedIdent<SEVERITY> {
type Raw = $raw;
type GroupId = $gid;
type UniqueId = $uid;
delegate!(to self.event {
fn raw(&self) -> Self::Raw;
fn severity(&self) -> Severity;
fn group_id(&self) -> Self::GroupId;
fn unique_id(&self) -> Self::UniqueId;
fn raw_as_largest_type(&self) -> LargestEventRaw;
fn group_id_as_largest_type(&self) -> LargestGroupIdRaw;
});
}
}
}
macro_rules! try_from_impls {
($SevIdent: ident, $severity: path, $raw: ty, $TypedSevIdent: ident) => {
impl TryFrom<$raw> for $TypedSevIdent<$SevIdent> {
type Error = Severity;
fn try_from(raw: $raw) -> Result<Self, Self::Error> {
Self::try_from_generic($severity, raw)
}
}
};
}
macro_rules! const_from_fn {
($from_fn_name: ident, $TypedIdent: ident, $SevIdent: ident) => {
pub const fn $from_fn_name(event: $TypedIdent<$SevIdent>) -> Self {
Self {
base: event.event.base,
}
}
};
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EventU32 {
base: EventBase<u32, u16, u16>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct EventU32TypedSev<SEVERITY> {
event: EventU32,
phantom: PhantomData<SEVERITY>,
}
impl<SEVERITY: HasSeverity> From<EventU32TypedSev<SEVERITY>> for EventU32 {
fn from(e: EventU32TypedSev<SEVERITY>) -> Self {
Self { base: e.event.base }
}
}
impl<Severity: HasSeverity> AsRef<EventU32> for EventU32TypedSev<Severity> {
fn as_ref(&self) -> &EventU32 {
&self.event
}
}
impl<Severity: HasSeverity> AsMut<EventU32> for EventU32TypedSev<Severity> {
fn as_mut(&mut self) -> &mut EventU32 {
&mut self.event
}
}
impl_event_provider!(EventU32, EventU32TypedSev, u32, u16, u16);
impl EventU32 {
/// Generate an event. The raw representation of an event has 32 bits.
/// If the passed group ID is invalid (too large), None wil be returned
///
/// # Parameter
///
/// * `severity`: Each event has a [severity][Severity]. The raw value of the severity will
/// be stored inside the uppermost 2 bits of the raw event ID
/// * `group_id`: Related events can be grouped using a group ID. The group ID will occupy the
/// next 14 bits after the severity. Therefore, the size is limited by dec 16383 hex 0x3FFF.
/// * `unique_id`: Each event has a unique 16 bit ID occupying the last 16 bits of the
/// raw event ID
pub fn new_checked(
severity: Severity,
group_id: <Self as GenericEvent>::GroupId,
unique_id: <Self as GenericEvent>::UniqueId,
) -> Option<Self> {
if group_id > MAX_GROUP_ID_U32_EVENT {
return None;
}
Some(Self {
base: EventBase {
severity,
group_id,
unique_id,
phantom: PhantomData,
},
})
}
/// This constructor will panic if the passed group is is larger than [MAX_GROUP_ID_U32_EVENT].
pub const fn new(
severity: Severity,
group_id: <Self as GenericEvent>::GroupId,
unique_id: <Self as GenericEvent>::UniqueId,
) -> Self {
if group_id > MAX_GROUP_ID_U32_EVENT {
panic!("Group ID too large");
}
Self {
base: EventBase {
severity,
group_id,
unique_id,
phantom: PhantomData,
},
}
}
pub fn from_be_bytes(bytes: [u8; 4]) -> Self {
Self::from(u32::from_be_bytes(bytes))
}
const_from_fn!(const_from_info, EventU32TypedSev, SeverityInfo);
const_from_fn!(const_from_low, EventU32TypedSev, SeverityLow);
const_from_fn!(const_from_medium, EventU32TypedSev, SeverityMedium);
const_from_fn!(const_from_high, EventU32TypedSev, SeverityHigh);
}
impl From<u32> for EventU32 {
fn from(raw: u32) -> Self {
// Severity conversion from u8 should never fail
let severity = Severity::try_from(((raw >> 30) & 0b11) as u8).unwrap();
let group_id = ((raw >> 16) & 0x3FFF) as u16;
let unique_id = (raw & 0xFFFF) as u16;
// Sanitized input, should never fail
Self::new(severity, group_id, unique_id)
}
}
impl UnsignedEnum for EventU32 {
fn size(&self) -> usize {
core::mem::size_of::<u32>()
}
fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
self.base.write_to_bytes(self.raw(), buf, self.size())
}
fn value(&self) -> u64 {
self.raw().into()
}
}
impl EcssEnumeration for EventU32 {
fn pfc(&self) -> u8 {
u32::BITS as u8
}
}
impl<SEVERITY: HasSeverity> EventU32TypedSev<SEVERITY> {
/// This is similar to [EventU32::new] but the severity is a type generic, which allows to
/// have distinct types for events with different severities
pub fn new_checked(
group_id: <Self as GenericEvent>::GroupId,
unique_id: <Self as GenericEvent>::UniqueId,
) -> Option<Self> {
let event = EventU32::new_checked(SEVERITY::SEVERITY, group_id, unique_id)?;
Some(Self {
event,
phantom: PhantomData,
})
}
/// This constructor will panic if the `group_id` is larger than [MAX_GROUP_ID_U32_EVENT].
pub const fn new(
group_id: <Self as GenericEvent>::GroupId,
unique_id: <Self as GenericEvent>::UniqueId,
) -> Self {
let event = EventU32::new(SEVERITY::SEVERITY, group_id, unique_id);
Self {
event,
phantom: PhantomData,
}
}
fn try_from_generic(expected: Severity, raw: u32) -> Result<Self, Severity> {
let severity = Severity::try_from(((raw >> 30) & 0b11) as u8).unwrap();
if severity != expected {
return Err(severity);
}
Ok(Self::new(
((raw >> 16) & 0x3FFF) as u16,
(raw & 0xFFFF) as u16,
))
}
}
try_from_impls!(SeverityInfo, Severity::Info, u32, EventU32TypedSev);
try_from_impls!(SeverityLow, Severity::Low, u32, EventU32TypedSev);
try_from_impls!(SeverityMedium, Severity::Medium, u32, EventU32TypedSev);
try_from_impls!(SeverityHigh, Severity::High, u32, EventU32TypedSev);
//noinspection RsTraitImplementation
impl<SEVERITY: HasSeverity> UnsignedEnum for EventU32TypedSev<SEVERITY> {
delegate!(to self.event {
fn size(&self) -> usize;
fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError>;
fn value(&self) -> u64;
});
}
//noinspection RsTraitImplementation
impl<SEVERITY: HasSeverity> EcssEnumeration for EventU32TypedSev<SEVERITY> {
delegate!(to self.event {
fn pfc(&self) -> u8;
});
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct EventU16 {
base: EventBase<u16, u8, u8>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct EventU16TypedSev<SEVERITY> {
event: EventU16,
phantom: PhantomData<SEVERITY>,
}
impl<Severity: HasSeverity> AsRef<EventU16> for EventU16TypedSev<Severity> {
fn as_ref(&self) -> &EventU16 {
&self.event
}
}
impl<Severity: HasSeverity> AsMut<EventU16> for EventU16TypedSev<Severity> {
fn as_mut(&mut self) -> &mut EventU16 {
&mut self.event
}
}
impl EventU16 {
/// Generate a small event. The raw representation of a small event has 16 bits.
/// If the passed group ID is invalid (too large), [None] wil be returned
///
/// # Parameter
///
/// * `severity`: Each event has a [severity][Severity]. The raw value of the severity will
/// be stored inside the uppermost 2 bits of the raw event ID
/// * `group_id`: Related events can be grouped using a group ID. The group ID will occupy the
/// next 6 bits after the severity. Therefore, the size is limited by dec 63 hex 0x3F.
/// * `unique_id`: Each event has a unique 8 bit ID occupying the last 8 bits of the
/// raw event ID
pub fn new_checked(
severity: Severity,
group_id: <Self as GenericEvent>::GroupId,
unique_id: <Self as GenericEvent>::UniqueId,
) -> Option<Self> {
if group_id > (2u8.pow(6) - 1) {
return None;
}
Some(Self {
base: EventBase {
severity,
group_id,
unique_id,
phantom: Default::default(),
},
})
}
/// This constructor will panic if the `group_id` is larger than [MAX_GROUP_ID_U16_EVENT].
pub const fn new(
severity: Severity,
group_id: <Self as GenericEvent>::GroupId,
unique_id: <Self as GenericEvent>::UniqueId,
) -> Self {
if group_id > (2u8.pow(6) - 1) {
panic!("Group ID too large");
}
Self {
base: EventBase {
severity,
group_id,
unique_id,
phantom: PhantomData,
},
}
}
pub fn from_be_bytes(bytes: [u8; 2]) -> Self {
Self::from(u16::from_be_bytes(bytes))
}
const_from_fn!(const_from_info, EventU16TypedSev, SeverityInfo);
const_from_fn!(const_from_low, EventU16TypedSev, SeverityLow);
const_from_fn!(const_from_medium, EventU16TypedSev, SeverityMedium);
const_from_fn!(const_from_high, EventU16TypedSev, SeverityHigh);
}
impl From<u16> for EventU16 {
fn from(raw: <Self as GenericEvent>::Raw) -> Self {
let severity = Severity::try_from(((raw >> 14) & 0b11) as u8).unwrap();
let group_id = ((raw >> 8) & 0x3F) as u8;
let unique_id = (raw & 0xFF) as u8;
// Sanitized input, new call should never fail
Self::new(severity, group_id, unique_id)
}
}
impl UnsignedEnum for EventU16 {
fn size(&self) -> usize {
core::mem::size_of::<u16>()
}
fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
self.base.write_to_bytes(self.raw(), buf, self.size())
}
fn value(&self) -> u64 {
self.raw().into()
}
}
impl EcssEnumeration for EventU16 {
#[inline]
fn pfc(&self) -> u8 {
u16::BITS as u8
}
}
impl<SEVERITY: HasSeverity> EventU16TypedSev<SEVERITY> {
/// This is similar to [EventU16::new] but the severity is a type generic, which allows to
/// have distinct types for events with different severities
pub fn new_checked(
group_id: <Self as GenericEvent>::GroupId,
unique_id: <Self as GenericEvent>::UniqueId,
) -> Option<Self> {
let event = EventU16::new_checked(SEVERITY::SEVERITY, group_id, unique_id)?;
Some(Self {
event,
phantom: PhantomData,
})
}
/// This constructor will panic if the `group_id` is larger than [MAX_GROUP_ID_U16_EVENT].
pub const fn new(
group_id: <Self as GenericEvent>::GroupId,
unique_id: <Self as GenericEvent>::UniqueId,
) -> Self {
let event = EventU16::new(SEVERITY::SEVERITY, group_id, unique_id);
Self {
event,
phantom: PhantomData,
}
}
fn try_from_generic(expected: Severity, raw: u16) -> Result<Self, Severity> {
let severity = Severity::try_from(((raw >> 14) & 0b11) as u8).unwrap();
if severity != expected {
return Err(severity);
}
Ok(Self::new(((raw >> 8) & 0x3F) as u8, (raw & 0xFF) as u8))
}
}
impl_event_provider!(EventU16, EventU16TypedSev, u16, u8, u8);
//noinspection RsTraitImplementation
impl<SEVERITY: HasSeverity> UnsignedEnum for EventU16TypedSev<SEVERITY> {
delegate!(to self.event {
fn size(&self) -> usize;
fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError>;
fn value(&self) -> u64;
});
}
//noinspection RsTraitImplementation
impl<SEVERITY: HasSeverity> EcssEnumeration for EventU16TypedSev<SEVERITY> {
delegate!(to self.event {
fn pfc(&self) -> u8;
});
}
try_from_impls!(SeverityInfo, Severity::Info, u16, EventU16TypedSev);
try_from_impls!(SeverityLow, Severity::Low, u16, EventU16TypedSev);
try_from_impls!(SeverityMedium, Severity::Medium, u16, EventU16TypedSev);
try_from_impls!(SeverityHigh, Severity::High, u16, EventU16TypedSev);
impl<Severity: HasSeverity> PartialEq<EventU32> for EventU32TypedSev<Severity> {
#[inline]
fn eq(&self, other: &EventU32) -> bool {
self.raw() == other.raw()
}
}
impl<Severity: HasSeverity> PartialEq<EventU32TypedSev<Severity>> for EventU32 {
#[inline]
fn eq(&self, other: &EventU32TypedSev<Severity>) -> bool {
self.raw() == other.raw()
}
}
impl<Severity: HasSeverity> PartialEq<EventU16> for EventU16TypedSev<Severity> {
#[inline]
fn eq(&self, other: &EventU16) -> bool {
self.raw() == other.raw()
}
}
impl<Severity: HasSeverity> PartialEq<EventU16TypedSev<Severity>> for EventU16 {
#[inline]
fn eq(&self, other: &EventU16TypedSev<Severity>) -> bool {
self.raw() == other.raw()
}
}
#[cfg(test)]
mod tests {
use super::EventU32TypedSev;
use super::*;
use spacepackets::ByteConversionError;
use std::mem::size_of;
fn assert_size<T>(_: T, val: usize) {
assert_eq!(size_of::<T>(), val);
}
const INFO_EVENT: EventU32TypedSev<SeverityInfo> = EventU32TypedSev::new(0, 0);
const INFO_EVENT_SMALL: EventU16TypedSev<SeverityInfo> = EventU16TypedSev::new(0, 0);
const HIGH_SEV_EVENT: EventU32TypedSev<SeverityHigh> = EventU32TypedSev::new(0x3FFF, 0xFFFF);
const HIGH_SEV_EVENT_SMALL: EventU16TypedSev<SeverityHigh> = EventU16TypedSev::new(0x3F, 0xff);
/// This working is a test in itself.
const INFO_REDUCED: EventU32 = EventU32::const_from_info(INFO_EVENT);
#[test]
fn test_normal_from_raw_conversion() {
let conv_from_raw = EventU32TypedSev::<SeverityInfo>::try_from(INFO_EVENT.raw())
.expect("Creating typed EventU32 failed");
assert_eq!(conv_from_raw, INFO_EVENT);
}
#[test]
fn test_small_from_raw_conversion() {
let conv_from_raw = EventU16TypedSev::<SeverityInfo>::try_from(INFO_EVENT_SMALL.raw())
.expect("Creating typed EventU16 failed");
assert_eq!(conv_from_raw, INFO_EVENT_SMALL);
}
#[test]
fn verify_normal_size() {
assert_size(INFO_EVENT.raw(), 4)
}
#[test]
fn verify_small_size() {
assert_size(INFO_EVENT_SMALL.raw(), 2)
}
#[test]
fn test_normal_event_getters() {
assert_eq!(INFO_EVENT.severity(), Severity::Info);
assert_eq!(INFO_EVENT.unique_id(), 0);
assert_eq!(INFO_EVENT.group_id(), 0);
let raw_event = INFO_EVENT.raw();
assert_eq!(raw_event, 0x00000000);
}
#[test]
fn test_small_event_getters() {
assert_eq!(INFO_EVENT_SMALL.severity(), Severity::Info);
assert_eq!(INFO_EVENT_SMALL.unique_id(), 0);
assert_eq!(INFO_EVENT_SMALL.group_id(), 0);
let raw_event = INFO_EVENT_SMALL.raw();
assert_eq!(raw_event, 0x00000000);
}
#[test]
fn all_ones_event_regular() {
assert_eq!(HIGH_SEV_EVENT.severity(), Severity::High);
assert_eq!(HIGH_SEV_EVENT.group_id(), 0x3FFF);
assert_eq!(HIGH_SEV_EVENT.unique_id(), 0xFFFF);
let raw_event = HIGH_SEV_EVENT.raw();
assert_eq!(raw_event, 0xFFFFFFFF);
}
#[test]
fn all_ones_event_small() {
assert_eq!(HIGH_SEV_EVENT_SMALL.severity(), Severity::High);
assert_eq!(HIGH_SEV_EVENT_SMALL.group_id(), 0x3F);
assert_eq!(HIGH_SEV_EVENT_SMALL.unique_id(), 0xFF);
let raw_event = HIGH_SEV_EVENT_SMALL.raw();
assert_eq!(raw_event, 0xFFFF);
}
#[test]
fn invalid_group_id_normal() {
assert!(EventU32TypedSev::<SeverityMedium>::new_checked(2_u16.pow(14), 0).is_none());
}
#[test]
fn invalid_group_id_small() {
assert!(EventU16TypedSev::<SeverityMedium>::new_checked(2_u8.pow(6), 0).is_none());
}
#[test]
fn regular_new() {
assert_eq!(
EventU32TypedSev::<SeverityInfo>::new_checked(0, 0)
.expect("Creating regular event failed"),
INFO_EVENT
);
}
#[test]
fn small_new() {
assert_eq!(
EventU16TypedSev::<SeverityInfo>::new_checked(0, 0)
.expect("Creating regular event failed"),
INFO_EVENT_SMALL
);
}
#[test]
fn as_largest_type() {
let event_raw = HIGH_SEV_EVENT.raw_as_largest_type();
assert_size(event_raw, 4);
assert_eq!(event_raw, 0xFFFFFFFF);
}
#[test]
fn as_largest_type_for_small_event() {
let event_raw = HIGH_SEV_EVENT_SMALL.raw_as_largest_type();
assert_size(event_raw, 4);
assert_eq!(event_raw, 0xFFFF);
}
#[test]
fn as_largest_group_id() {
let group_id = HIGH_SEV_EVENT.group_id_as_largest_type();
assert_size(group_id, 2);
assert_eq!(group_id, 0x3FFF);
}
#[test]
fn as_largest_group_id_small_event() {
let group_id = HIGH_SEV_EVENT_SMALL.group_id_as_largest_type();
assert_size(group_id, 2);
assert_eq!(group_id, 0x3F);
}
#[test]
fn write_to_buf() {
let mut buf: [u8; 4] = [0; 4];
assert!(HIGH_SEV_EVENT.write_to_be_bytes(&mut buf).is_ok());
let val_from_raw = u32::from_be_bytes(buf);
assert_eq!(val_from_raw, 0xFFFFFFFF);
let event_read_back = EventU32::from_be_bytes(buf);
assert_eq!(event_read_back, HIGH_SEV_EVENT);
}
#[test]
fn write_to_buf_small() {
let mut buf: [u8; 2] = [0; 2];
assert!(HIGH_SEV_EVENT_SMALL.write_to_be_bytes(&mut buf).is_ok());
let val_from_raw = u16::from_be_bytes(buf);
assert_eq!(val_from_raw, 0xFFFF);
let event_read_back = EventU16::from_be_bytes(buf);
assert_eq!(event_read_back, HIGH_SEV_EVENT_SMALL);
}
#[test]
fn write_to_buf_insufficient_buf() {
let mut buf: [u8; 3] = [0; 3];
let err = HIGH_SEV_EVENT.write_to_be_bytes(&mut buf);
assert!(err.is_err());
let err = err.unwrap_err();
if let ByteConversionError::ToSliceTooSmall { found, expected } = err {
assert_eq!(expected, 4);
assert_eq!(found, 3);
}
}
#[test]
fn write_to_buf_small_insufficient_buf() {
let mut buf: [u8; 1] = [0; 1];
let err = HIGH_SEV_EVENT_SMALL.write_to_be_bytes(&mut buf);
assert!(err.is_err());
let err = err.unwrap_err();
if let ByteConversionError::ToSliceTooSmall { found, expected } = err {
assert_eq!(expected, 2);
assert_eq!(found, 1);
}
}
#[test]
fn severity_from_invalid_raw_val() {
let invalid = 0xFF;
assert!(Severity::try_from(invalid).is_err());
let invalid = Severity::High as u8 + 1;
assert!(Severity::try_from(invalid).is_err());
}
#[test]
fn reduction() {
let event = EventU32TypedSev::<SeverityInfo>::new(1, 1);
let raw = event.raw();
let reduced: EventU32 = event.into();
assert_eq!(reduced.group_id(), 1);
assert_eq!(reduced.unique_id(), 1);
assert_eq!(raw, reduced.raw());
}
#[test]
fn const_reducation() {
assert_eq!(INFO_REDUCED.raw(), INFO_EVENT.raw());
}
}

View File

@@ -26,8 +26,7 @@ use std::vec::Vec;
/// use satrs::ComponentId;
/// use satrs::tmtc::PacketSenderRaw;
/// use spacepackets::SpHeader;
/// use spacepackets::ecss::tc::{PusTcCreator, CreatorConfig};
/// use arbitrary_int::u11;
/// use spacepackets::ecss::tc::PusTcCreator;
///
/// const UDP_SERVER_ID: ComponentId = 0x05;
///
@@ -35,8 +34,8 @@ use std::vec::Vec;
/// let dest_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7777);
/// let mut udp_tc_server = UdpTcServer::new(UDP_SERVER_ID, dest_addr, 2048, packet_sender)
/// .expect("Creating UDP TMTC server failed");
/// let sph = SpHeader::new_from_apid(u11::new(0x02));
/// let pus_tc = PusTcCreator::new_simple(sph, 17, 1, &[], CreatorConfig::default());
/// let sph = SpHeader::new_from_apid(0x02);
/// let pus_tc = PusTcCreator::new_simple(sph, 17, 1, &[], true);
/// // Can not fail.
/// let ping_tc_raw = pus_tc.to_vec().unwrap();
///

View File

@@ -15,7 +15,7 @@
//! the [ECSS PUS C standard](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/).
#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[cfg(any(feature = "alloc", test))]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
extern crate downcast_rs;
@@ -27,9 +27,7 @@ pub mod action;
pub mod dev_mgmt;
pub mod encoding;
pub mod event_man;
pub mod event_man_legacy;
pub mod events;
pub mod events_legacy;
#[cfg(feature = "std")]
pub mod executable;
pub mod hal;
@@ -51,7 +49,6 @@ pub mod scheduling;
pub mod subsystem;
pub mod time;
pub mod tmtc;
pub mod ccsds;
pub use spacepackets;

View File

@@ -258,9 +258,6 @@ pub trait PoolProvider {
/// Delete data inside the pool given a [PoolAddr].
fn delete(&mut self, addr: PoolAddr) -> Result<(), PoolError>;
fn clear(&mut self) -> Result<(), PoolError>;
fn has_element_at(&self, addr: &PoolAddr) -> Result<bool, PoolError>;
/// Retrieve the length of the data at the given store address.
@@ -717,13 +714,6 @@ pub mod heapless_mod {
Ok(())
}
fn clear(&mut self) -> Result<(), PoolError> {
for size in self.sizes_lists.iter_mut() {
size.fill(STORE_FREE);
}
Ok(())
}
fn has_element_at(&self, addr: &PoolAddr) -> Result<bool, PoolError> {
let addr = StaticPoolAddr::from(*addr);
self.validate_addr(&addr)?;
@@ -1065,13 +1055,6 @@ mod alloc_mod {
_ => size,
})
}
fn clear(&mut self) -> Result<(), PoolError> {
for size in self.sizes_lists.iter_mut() {
size.fill(STORE_FREE);
}
Ok(())
}
}
impl PoolProviderWithGuards for StaticMemoryPool {
@@ -1614,228 +1597,88 @@ mod tests {
mod heapless_tests {
use super::*;
use crate::static_subpool;
use std::cell::UnsafeCell;
use std::sync::Mutex;
const SUBPOOL_1_BLOCK_SIZE: usize = 4;
const SUBPOOL_1_NUM_ELEMENTS: u16 = 4;
static SUBPOOL_1: static_cell::ConstStaticCell<
[u8; SUBPOOL_1_NUM_ELEMENTS as usize * SUBPOOL_1_BLOCK_SIZE],
> = static_cell::ConstStaticCell::new(
[0; SUBPOOL_1_NUM_ELEMENTS as usize * SUBPOOL_1_BLOCK_SIZE],
);
static SUBPOOL_1_SIZES: Mutex<UnsafeCell<[usize; SUBPOOL_1_NUM_ELEMENTS as usize]>> =
Mutex::new(UnsafeCell::new(
[STORE_FREE; SUBPOOL_1_NUM_ELEMENTS as usize],
));
const SUBPOOL_2_NUM_ELEMENTS: u16 = 2;
const SUBPOOL_2_BLOCK_SIZE: usize = 8;
static SUBPOOL_2: static_cell::ConstStaticCell<
[u8; SUBPOOL_2_NUM_ELEMENTS as usize * SUBPOOL_2_BLOCK_SIZE],
> = static_cell::ConstStaticCell::new(
[0; SUBPOOL_2_NUM_ELEMENTS as usize * SUBPOOL_2_BLOCK_SIZE],
);
static SUBPOOL_2_SIZES: static_cell::ConstStaticCell<
[usize; SUBPOOL_2_NUM_ELEMENTS as usize],
> = static_cell::ConstStaticCell::new([STORE_FREE; SUBPOOL_2_NUM_ELEMENTS as usize]);
const SUBPOOL_3_NUM_ELEMENTS: u16 = 1;
const SUBPOOL_3_BLOCK_SIZE: usize = 16;
static_subpool!(
SUBPOOL_3,
SUBPOOL_3_SIZES,
SUBPOOL_3_NUM_ELEMENTS as usize,
SUBPOOL_3_BLOCK_SIZE
);
const SUBPOOL_4_NUM_ELEMENTS: u16 = 2;
const SUBPOOL_4_BLOCK_SIZE: usize = 16;
static_subpool!(
SUBPOOL_4,
SUBPOOL_4_SIZES,
SUBPOOL_4_NUM_ELEMENTS as usize,
SUBPOOL_4_BLOCK_SIZE
);
const SUBPOOL_5_NUM_ELEMENTS: u16 = 1;
const SUBPOOL_5_BLOCK_SIZE: usize = 8;
static_subpool!(
SUBPOOL_5,
SUBPOOL_5_SIZES,
SUBPOOL_5_NUM_ELEMENTS as usize,
SUBPOOL_5_BLOCK_SIZE
);
const SUBPOOL_6_NUM_ELEMENTS: u16 = 1;
const SUBPOOL_6_BLOCK_SIZE: usize = 12;
static_subpool!(
SUBPOOL_6,
SUBPOOL_6_SIZES,
SUBPOOL_6_NUM_ELEMENTS as usize,
SUBPOOL_6_BLOCK_SIZE
);
macro_rules! make_heapless_pool {
($prefix:ident) => {{
paste::paste! {
static [<$prefix _SUBPOOL_1>]: static_cell::ConstStaticCell<
[u8; SUBPOOL_1_NUM_ELEMENTS as usize * SUBPOOL_1_BLOCK_SIZE],
> = static_cell::ConstStaticCell::new(
[0; SUBPOOL_1_NUM_ELEMENTS as usize * SUBPOOL_1_BLOCK_SIZE],
);
static [<$prefix _SUBPOOL_1_SIZES>]: std::sync::Mutex<
std::cell::UnsafeCell<[usize; SUBPOOL_1_NUM_ELEMENTS as usize]>
> = std::sync::Mutex::new(
std::cell::UnsafeCell::new([STORE_FREE; SUBPOOL_1_NUM_ELEMENTS as usize])
);
static [<$prefix _SUBPOOL_2>]: static_cell::ConstStaticCell<
[u8; SUBPOOL_2_NUM_ELEMENTS as usize * SUBPOOL_2_BLOCK_SIZE],
> = static_cell::ConstStaticCell::new(
[0; SUBPOOL_2_NUM_ELEMENTS as usize * SUBPOOL_2_BLOCK_SIZE],
);
static [<$prefix _SUBPOOL_2_SIZES>]: static_cell::ConstStaticCell<
[usize; SUBPOOL_2_NUM_ELEMENTS as usize],
> = static_cell::ConstStaticCell::new(
[STORE_FREE; SUBPOOL_2_NUM_ELEMENTS as usize]
);
static [<$prefix _SUBPOOL_3>]: static_cell::ConstStaticCell<
[u8; SUBPOOL_3_NUM_ELEMENTS as usize * SUBPOOL_3_BLOCK_SIZE],
> = static_cell::ConstStaticCell::new(
[0; SUBPOOL_3_NUM_ELEMENTS as usize * SUBPOOL_3_BLOCK_SIZE],
);
static [<$prefix _SUBPOOL_3_SIZES>]: static_cell::ConstStaticCell<
[usize; SUBPOOL_3_NUM_ELEMENTS as usize],
> = static_cell::ConstStaticCell::new(
[STORE_FREE; SUBPOOL_3_NUM_ELEMENTS as usize]
);
let mut heapless_pool: StaticHeaplessMemoryPool<3> =
StaticHeaplessMemoryPool::new(false);
heapless_pool
.grow(
[<$prefix _SUBPOOL_1>].take(),
unsafe { &mut *[<$prefix _SUBPOOL_1_SIZES>].lock().unwrap().get() },
SUBPOOL_1_NUM_ELEMENTS,
true
)
.unwrap();
heapless_pool
.grow(
[<$prefix _SUBPOOL_2>].take(),
[<$prefix _SUBPOOL_2_SIZES>].take(),
SUBPOOL_2_NUM_ELEMENTS,
true
)
.unwrap();
heapless_pool
.grow(
[<$prefix _SUBPOOL_3>].take(),
[<$prefix _SUBPOOL_3_SIZES>].take(),
SUBPOOL_3_NUM_ELEMENTS,
true
)
.unwrap();
heapless_pool
}
}};
}
#[test]
fn test_heapless_add_and_read() {
let mut pool_provider = make_heapless_pool!(T0);
generic_test_add_and_read::<16>(&mut pool_provider);
}
#[test]
fn test_add_smaller_than_full_slot() {
let mut pool_provider = make_heapless_pool!(T1);
generic_test_add_smaller_than_full_slot(&mut pool_provider);
}
#[test]
fn test_delete() {
let mut pool_provider = make_heapless_pool!(T2);
generic_test_delete(&mut pool_provider);
}
#[test]
fn test_modify() {
let mut pool_provider = make_heapless_pool!(T3);
generic_test_modify(&mut pool_provider);
}
#[test]
fn test_consecutive_reservation() {
let mut pool_provider = make_heapless_pool!(T4);
generic_test_consecutive_reservation(&mut pool_provider);
}
#[test]
fn test_read_does_not_exist() {
let mut pool_provider = make_heapless_pool!(T5);
generic_test_read_does_not_exist(&mut pool_provider);
}
#[test]
fn test_store_full() {
let mut pool_provider = make_heapless_pool!(T6);
generic_test_store_full(&mut pool_provider);
}
#[test]
fn test_invalid_pool_idx() {
let mut pool_provider = make_heapless_pool!(T7);
generic_test_invalid_pool_idx(&mut pool_provider);
}
#[test]
fn test_invalid_packet_idx() {
let mut pool_provider = make_heapless_pool!(T8);
generic_test_invalid_packet_idx(&mut pool_provider);
}
#[test]
fn test_add_too_large() {
let mut pool_provider = make_heapless_pool!(T9);
generic_test_add_too_large(&mut pool_provider);
}
#[test]
fn test_data_too_large_1() {
let mut pool_provider = make_heapless_pool!(T10);
generic_test_data_too_large_1(&mut pool_provider);
}
#[test]
fn test_free_element_too_large() {
let mut pool_provider = make_heapless_pool!(T11);
generic_test_free_element_too_large(&mut pool_provider);
}
#[test]
fn test_pool_guard_deletion_man_creation() {
let mut pool_provider = make_heapless_pool!(T12);
generic_test_pool_guard_deletion_man_creation(&mut pool_provider);
}
#[test]
fn test_pool_guard_deletion() {
let mut pool_provider = make_heapless_pool!(T13);
generic_test_pool_guard_deletion(&mut pool_provider);
}
#[test]
fn test_pool_guard_with_release() {
let mut pool_provider = make_heapless_pool!(T14);
generic_test_pool_guard_with_release(&mut pool_provider);
}
#[test]
fn test_pool_modify_guard_man_creation() {
let mut pool_provider = make_heapless_pool!(T15);
generic_test_pool_modify_guard_man_creation(&mut pool_provider);
}
#[test]
fn test_pool_modify_guard() {
let mut pool_provider = make_heapless_pool!(T16);
generic_test_pool_modify_guard(&mut pool_provider);
}
#[test]
fn modify_pool_index_above_0() {
let mut pool_provider = make_heapless_pool!(T17);
generic_modify_pool_index_above_0(&mut pool_provider);
}
#[test]
fn test_spills_to_higher_subpools() {
static_subpool!(
SUBPOOL_2_T18,
SUBPOOL_2_SIZES_T18,
SUBPOOL_2_NUM_ELEMENTS as usize,
SUBPOOL_2_BLOCK_SIZE
);
static_subpool!(
SUBPOOL_4_T18,
SUBPOOL_4_SIZES_T18,
SUBPOOL_4_NUM_ELEMENTS as usize,
SUBPOOL_4_BLOCK_SIZE
);
let mut heapless_pool: StaticHeaplessMemoryPool<2> =
StaticHeaplessMemoryPool::new(true);
fn small_heapless_pool() -> StaticHeaplessMemoryPool<3> {
let mut heapless_pool: StaticHeaplessMemoryPool<3> =
StaticHeaplessMemoryPool::new(false);
assert!(
heapless_pool
.grow(
SUBPOOL_2_T18.take(),
SUBPOOL_2_SIZES_T18.take(),
SUBPOOL_1.take(),
unsafe { &mut *SUBPOOL_1_SIZES.lock().unwrap().get() },
SUBPOOL_1_NUM_ELEMENTS,
true
)
.is_ok()
);
assert!(
heapless_pool
.grow(
SUBPOOL_2.take(),
SUBPOOL_2_SIZES.take(),
SUBPOOL_2_NUM_ELEMENTS,
true
)
@@ -1844,8 +1687,143 @@ mod tests {
assert!(
heapless_pool
.grow(
SUBPOOL_4_T18.take(),
SUBPOOL_4_SIZES_T18.take(),
SUBPOOL_3.take(),
SUBPOOL_3_SIZES.take(),
SUBPOOL_3_NUM_ELEMENTS,
true
)
.is_ok()
);
heapless_pool
}
#[test]
fn test_heapless_add_and_read() {
let mut pool_provider = small_heapless_pool();
generic_test_add_and_read::<16>(&mut pool_provider);
}
#[test]
fn test_add_smaller_than_full_slot() {
let mut pool_provider = small_heapless_pool();
generic_test_add_smaller_than_full_slot(&mut pool_provider);
}
#[test]
fn test_delete() {
let mut pool_provider = small_heapless_pool();
generic_test_delete(&mut pool_provider);
}
#[test]
fn test_modify() {
let mut pool_provider = small_heapless_pool();
generic_test_modify(&mut pool_provider);
}
#[test]
fn test_consecutive_reservation() {
let mut pool_provider = small_heapless_pool();
generic_test_consecutive_reservation(&mut pool_provider);
}
#[test]
fn test_read_does_not_exist() {
let mut pool_provider = small_heapless_pool();
generic_test_read_does_not_exist(&mut pool_provider);
}
#[test]
fn test_store_full() {
let mut pool_provider = small_heapless_pool();
generic_test_store_full(&mut pool_provider);
}
#[test]
fn test_invalid_pool_idx() {
let mut pool_provider = small_heapless_pool();
generic_test_invalid_pool_idx(&mut pool_provider);
}
#[test]
fn test_invalid_packet_idx() {
let mut pool_provider = small_heapless_pool();
generic_test_invalid_packet_idx(&mut pool_provider);
}
#[test]
fn test_add_too_large() {
let mut pool_provider = small_heapless_pool();
generic_test_add_too_large(&mut pool_provider);
}
#[test]
fn test_data_too_large_1() {
let mut pool_provider = small_heapless_pool();
generic_test_data_too_large_1(&mut pool_provider);
}
#[test]
fn test_free_element_too_large() {
let mut pool_provider = small_heapless_pool();
generic_test_free_element_too_large(&mut pool_provider);
}
#[test]
fn test_pool_guard_deletion_man_creation() {
let mut pool_provider = small_heapless_pool();
generic_test_pool_guard_deletion_man_creation(&mut pool_provider);
}
#[test]
fn test_pool_guard_deletion() {
let mut pool_provider = small_heapless_pool();
generic_test_pool_guard_deletion(&mut pool_provider);
}
#[test]
fn test_pool_guard_with_release() {
let mut pool_provider = small_heapless_pool();
generic_test_pool_guard_with_release(&mut pool_provider);
}
#[test]
fn test_pool_modify_guard_man_creation() {
let mut pool_provider = small_heapless_pool();
generic_test_pool_modify_guard_man_creation(&mut pool_provider);
}
#[test]
fn test_pool_modify_guard() {
let mut pool_provider = small_heapless_pool();
generic_test_pool_modify_guard(&mut pool_provider);
}
#[test]
fn modify_pool_index_above_0() {
let mut pool_provider = small_heapless_pool();
generic_modify_pool_index_above_0(&mut pool_provider);
}
#[test]
fn test_spills_to_higher_subpools() {
let mut heapless_pool: StaticHeaplessMemoryPool<2> =
StaticHeaplessMemoryPool::new(true);
assert!(
heapless_pool
.grow(
SUBPOOL_2.take(),
SUBPOOL_2_SIZES.take(),
SUBPOOL_2_NUM_ELEMENTS,
true
)
.is_ok()
);
assert!(
heapless_pool
.grow(
SUBPOOL_4.take(),
SUBPOOL_4_SIZES.take(),
SUBPOOL_4_NUM_ELEMENTS,
true
)
@@ -1858,18 +1836,6 @@ mod tests {
fn test_spillage_fails_as_well() {
let mut heapless_pool: StaticHeaplessMemoryPool<2> =
StaticHeaplessMemoryPool::new(true);
static_subpool!(
SUBPOOL_5,
SUBPOOL_5_SIZES,
SUBPOOL_5_NUM_ELEMENTS as usize,
SUBPOOL_5_BLOCK_SIZE
);
static_subpool!(
SUBPOOL_3,
SUBPOOL_3_SIZES,
SUBPOOL_3_NUM_ELEMENTS as usize,
SUBPOOL_3_BLOCK_SIZE
);
assert!(
heapless_pool
.grow(
@@ -1897,24 +1863,6 @@ mod tests {
fn test_spillage_works_across_multiple_subpools() {
let mut heapless_pool: StaticHeaplessMemoryPool<3> =
StaticHeaplessMemoryPool::new(true);
static_subpool!(
SUBPOOL_3,
SUBPOOL_3_SIZES,
SUBPOOL_3_NUM_ELEMENTS as usize,
SUBPOOL_3_BLOCK_SIZE
);
static_subpool!(
SUBPOOL_5,
SUBPOOL_5_SIZES,
SUBPOOL_5_NUM_ELEMENTS as usize,
SUBPOOL_5_BLOCK_SIZE
);
static_subpool!(
SUBPOOL_6,
SUBPOOL_6_SIZES,
SUBPOOL_6_NUM_ELEMENTS as usize,
SUBPOOL_6_BLOCK_SIZE
);
assert!(
heapless_pool
.grow(
@@ -1950,24 +1898,6 @@ mod tests {
#[test]
fn test_spillage_fails_across_multiple_subpools() {
static_subpool!(
SUBPOOL_3,
SUBPOOL_3_SIZES,
SUBPOOL_3_NUM_ELEMENTS as usize,
SUBPOOL_3_BLOCK_SIZE
);
static_subpool!(
SUBPOOL_5,
SUBPOOL_5_SIZES,
SUBPOOL_5_NUM_ELEMENTS as usize,
SUBPOOL_5_BLOCK_SIZE
);
static_subpool!(
SUBPOOL_6,
SUBPOOL_6_SIZES,
SUBPOOL_6_NUM_ELEMENTS as usize,
SUBPOOL_6_BLOCK_SIZE
);
let mut heapless_pool: StaticHeaplessMemoryPool<3> =
StaticHeaplessMemoryPool::new(true);
assert!(

View File

@@ -2,10 +2,8 @@ use crate::pus::source_buffer_large_enough;
use arbitrary_int::u11;
use spacepackets::ByteConversionError;
use spacepackets::SpHeader;
use spacepackets::ecss::CreatorConfig;
use spacepackets::ecss::EcssEnumeration;
use spacepackets::ecss::tm::PusTmCreator;
use spacepackets::ecss::tm::PusTmSecondaryHeader;
use spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader};
use spacepackets::ecss::{CreatorConfig, EcssEnumeration};
#[cfg(feature = "alloc")]
pub use alloc_mod::*;
@@ -164,14 +162,14 @@ mod alloc_mod {
default_apid: u11,
default_dest_id: u16,
max_event_id_and_aux_data_size: usize,
) -> Self {
) -> Option<Self> {
let reporter = EventReportCreator::new(default_apid, default_dest_id);
Self {
Some(Self {
id,
source_data_buf: RefCell::new(vec![0; max_event_id_and_aux_data_size]),
report_creator: reporter,
tm_hook: DummyEventHook::default(),
}
})
}
}
impl<EventTmHookInstance: EventTmHook> EventReporter<EventTmHookInstance> {
@@ -181,14 +179,14 @@ mod alloc_mod {
default_dest_id: u16,
max_event_id_and_aux_data_size: usize,
tm_hook: EventTmHookInstance,
) -> Self {
) -> Option<Self> {
let reporter = EventReportCreator::new(default_apid, default_dest_id);
Self {
Some(Self {
id,
source_data_buf: RefCell::new(vec![0; max_event_id_and_aux_data_size]),
report_creator: reporter,
tm_hook,
}
})
}
pub fn event_info(
@@ -265,7 +263,7 @@ mod alloc_mod {
mod tests {
use super::*;
use crate::ComponentId;
use crate::events_legacy::{EventU32, Severity};
use crate::events::{EventU32, Severity};
use crate::pus::test_util::TEST_COMPONENT_ID_0;
use crate::pus::tests::CommonTmInfo;
use crate::pus::{ChannelWithId, EcssTmSender, EcssTmtcError, PusTmVariant};
@@ -375,12 +373,14 @@ mod tests {
error_data: Option<&[u8]>,
) {
let mut sender = TestSender::default();
let mut reporter = EventReporter::new(
let reporter = EventReporter::new(
TEST_COMPONENT_ID_0.id(),
EXAMPLE_APID,
0,
max_event_aux_data_buf,
);
assert!(reporter.is_some());
let mut reporter = reporter.unwrap();
let time_stamp_empty: [u8; 7] = [0; 7];
let mut error_copy = Vec::new();
if let Some(err_data) = error_data {
@@ -471,7 +471,9 @@ mod tests {
fn insufficient_buffer() {
let mut sender = TestSender::default();
for i in 0..3 {
let mut reporter = EventReporter::new(0, EXAMPLE_APID, 0, i);
let reporter = EventReporter::new(0, EXAMPLE_APID, 0, i);
assert!(reporter.is_some());
let mut reporter = reporter.unwrap();
check_buf_too_small(&mut reporter, &mut sender, i);
}
}

View File

@@ -1,6 +1,6 @@
use crate::events_legacy::{EventU32, GenericEvent, Severity};
use crate::events::{EventU32, GenericEvent, Severity};
#[cfg(feature = "alloc")]
use crate::events_legacy::{EventU32TypedSev, HasSeverity};
use crate::events::{EventU32TypedSev, HasSeverity};
#[cfg(feature = "alloc")]
use core::hash::Hash;
#[cfg(feature = "alloc")]
@@ -100,7 +100,7 @@ pub mod alloc_mod {
use core::marker::PhantomData;
use crate::{
events_legacy::EventU16,
events::EventU16,
params::{Params, WritableToBeBytes},
pus::event::{DummyEventHook, EventTmHook},
};
@@ -318,7 +318,7 @@ mod tests {
use super::*;
use crate::request::UniqueApidTargetId;
use crate::{events_legacy::SeverityInfo, tmtc::PacketAsVec};
use crate::{events::SeverityInfo, tmtc::PacketAsVec};
use std::sync::mpsc::{self, TryRecvError};
const INFO_EVENT: EventU32TypedSev<SeverityInfo> = EventU32TypedSev::<SeverityInfo>::new(1, 0);
@@ -328,11 +328,13 @@ mod tests {
const TEST_ID: UniqueApidTargetId = UniqueApidTargetId::new(TEST_APID, 0x05);
fn create_basic_man_1() -> DefaultPusEventU32TmCreator {
let reporter = EventReporter::new(TEST_ID.raw(), TEST_APID, 0, 128);
let reporter = EventReporter::new(TEST_ID.raw(), TEST_APID, 0, 128)
.expect("Creating event repoter failed");
PusEventTmCreatorWithMap::new_with_default_backend(reporter)
}
fn create_basic_man_2() -> DefaultPusEventU32TmCreator {
let reporter = EventReporter::new(TEST_ID.raw(), TEST_APID, 0, 128);
let reporter = EventReporter::new(TEST_ID.raw(), TEST_APID, 0, 128)
.expect("Creating event repoter failed");
let backend = DefaultPusEventReportingMap::default();
PusEventTmCreatorWithMap::new(reporter, backend)
}

View File

@@ -1,4 +1,4 @@
use crate::events_legacy::EventU32;
use crate::events::EventU32;
use crate::pus::event_man::{EventRequest, EventRequestWithToken};
use crate::pus::verification::TcStateToken;
use crate::pus::{DirectPusPacketHandlerResult, PartialPusHandlingError, PusPacketHandlingError};
@@ -168,7 +168,7 @@ mod tests {
use crate::pus::{GenericConversionError, HandlingStatus, MpscTcReceiver};
use crate::tmtc::PacketSenderWithSharedPool;
use crate::{
events_legacy::EventU32,
events::EventU32,
pus::{
DirectPusPacketHandlerResult, EcssTcInSharedPoolCacher, PusPacketHandlingError,
event_man::EventRequestWithToken,
@@ -179,7 +179,7 @@ mod tests {
use super::PusEventServiceHandler;
const TEST_EVENT_0: EventU32 = EventU32::new(crate::events_legacy::Severity::Info, 5, 25);
const TEST_EVENT_0: EventU32 = EventU32::new(crate::events::Severity::Info, 5, 25);
struct Pus5HandlerWithStoreTester {
common: PusServiceHandlerWithSharedStoreCommon,

View File

@@ -449,7 +449,7 @@ pub mod alloc_mod {
/// Having a dedicated trait for this allows maximum flexiblity and tailoring of the standard.
/// The only requirement is that a valid active request information instance and a request
/// are returned by the core conversion function. The active request type needs to fulfill
/// the [ActiveRequest] trait bound.
/// the [ActiveRequestProvider] trait bound.
///
/// The user should take care of performing the error handling as well. Some of the following
/// aspects might be relevant:
@@ -1126,7 +1126,7 @@ pub mod std_mod {
/// groups (for example individual services).
///
/// This base class can handle PUS telecommands backed by different memory storage machanisms
/// by using the [CacheAndReadRawEcssTc] abstraction. This object provides some convenience
/// by using the [EcssTcInMemConverter] abstraction. This object provides some convenience
/// methods to make the generic parts of TC handling easier.
pub struct PusServiceHelper<
TcReceiver: EcssTcReceiver,
@@ -1409,7 +1409,7 @@ pub mod tests {
let (test_srv_tc_tx, test_srv_tc_rx) = mpsc::sync_channel(10);
let (tm_tx, tm_rx) = mpsc::sync_channel(10);
let verif_cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, 8);
let verif_cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, 8).unwrap();
let verification_handler =
VerificationReporter::new(TEST_COMPONENT_ID_0.id(), &verif_cfg);
let test_srv_tm_sender =
@@ -1502,7 +1502,7 @@ pub mod tests {
let (test_srv_tc_tx, test_srv_tc_rx) = mpsc::channel();
let (tm_tx, tm_rx) = mpsc::channel();
let verif_cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, 8);
let verif_cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, 8).unwrap();
let verification_handler =
VerificationReporter::new(TEST_COMPONENT_ID_0.id(), &verif_cfg);
let in_store_converter = EcssTcVecCacher::default();

View File

@@ -3,7 +3,7 @@
//! The core data structure of this module is the [PusScheduler]. This structure can be used
//! to perform the scheduling of telecommands like specified in the ECSS standard.
use arbitrary_int::{u11, u14};
use core::fmt::Debug;
use core::fmt::{Debug, Display, Formatter};
use core::time::Duration;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
@@ -12,6 +12,8 @@ use spacepackets::ecss::tc::{GenericPusTcSecondaryHeader, IsPusTelecommand, PusT
use spacepackets::ecss::{PusError, PusPacket, WritablePusPacket};
use spacepackets::time::{CcsdsTimeProvider, TimeReader, TimeWriter, TimestampError, UnixTime};
use spacepackets::{ByteConversionError, CcsdsPacket};
#[cfg(feature = "std")]
use std::error::Error;
use crate::pool::{PoolError, PoolProvider};
#[cfg(feature = "alloc")]
@@ -23,7 +25,6 @@ pub use alloc_mod::*;
/// the source ID found in the secondary header of PUS telecommands.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RequestId {
pub(crate) source_id: u16,
pub(crate) apid: u11,
@@ -56,6 +57,7 @@ impl RequestId {
}
}
#[inline]
pub const fn as_u64(&self) -> u64 {
((self.source_id as u64) << 32)
| ((self.apid.value() as u64) << 16)
@@ -142,39 +144,107 @@ impl<TimeProvider: CcsdsTimeProvider + Clone> TimeWindow<TimeProvider> {
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ScheduleError {
#[error("pus error: {0}")]
PusError(#[from] PusError),
PusError(PusError),
/// The release time is within the time-margin added on top of the current time.
/// The first parameter is the current time, the second one the time margin, and the third one
/// the release time.
#[error("release time in margin")]
ReleaseTimeInTimeMargin {
current_time: UnixTime,
time_margin: Duration,
release_time: UnixTime,
},
/// Nested time-tagged commands are not allowed.
#[error("nested scheduled tc")]
NestedScheduledTc,
#[error("store error")]
Pool(#[from] PoolError),
#[error("tc data empty")]
StoreError(PoolError),
TcDataEmpty,
#[error("timestamp error: {0}")]
TimestampError(#[from] TimestampError),
#[error("wrong subservice number {0}")]
TimestampError(TimestampError),
WrongSubservice(u8),
#[error("wrong service number {0}")]
WrongService(u8),
#[error("byte conversion error: {0}")]
ByteConversionError(#[from] ByteConversionError),
ByteConversionError(ByteConversionError),
}
impl Display for ScheduleError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
ScheduleError::PusError(e) => {
write!(f, "Pus Error: {e}")
}
ScheduleError::ReleaseTimeInTimeMargin {
current_time,
time_margin,
release_time,
} => {
write!(
f,
"time margin too short, current time: {current_time:?}, time margin: {time_margin:?}, release time: {release_time:?}"
)
}
ScheduleError::NestedScheduledTc => {
write!(f, "nested scheduling is not allowed")
}
ScheduleError::StoreError(e) => {
write!(f, "pus scheduling: {e}")
}
ScheduleError::TcDataEmpty => {
write!(f, "empty TC data field")
}
ScheduleError::TimestampError(e) => {
write!(f, "pus scheduling: {e}")
}
ScheduleError::WrongService(srv) => {
write!(f, "pus scheduling: wrong service number {srv}")
}
ScheduleError::WrongSubservice(subsrv) => {
write!(f, "pus scheduling: wrong subservice number {subsrv}")
}
ScheduleError::ByteConversionError(e) => {
write!(f, "pus scheduling: {e}")
}
}
}
}
impl From<PusError> for ScheduleError {
fn from(e: PusError) -> Self {
Self::PusError(e)
}
}
impl From<PoolError> for ScheduleError {
fn from(e: PoolError) -> Self {
Self::StoreError(e)
}
}
impl From<TimestampError> for ScheduleError {
fn from(e: TimestampError) -> Self {
Self::TimestampError(e)
}
}
impl From<ByteConversionError> for ScheduleError {
fn from(e: ByteConversionError) -> Self {
Self::ByteConversionError(e)
}
}
#[cfg(feature = "std")]
impl Error for ScheduleError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
ScheduleError::PusError(e) => Some(e),
ScheduleError::StoreError(e) => Some(e),
ScheduleError::TimestampError(e) => Some(e),
ScheduleError::ByteConversionError(e) => Some(e),
_ => None,
}
}
}
/// Generic trait for scheduler objects which are able to schedule ECSS PUS C packets.
pub trait PusScheduler {
pub trait PusSchedulerProvider {
type TimeProvider: CcsdsTimeProvider + TimeReader;
fn reset(&mut self, store: &mut (impl PoolProvider + ?Sized)) -> Result<(), PoolError>;
@@ -331,7 +401,7 @@ pub mod alloc_mod {
///
/// Currently, sub-schedules and groups are not supported.
#[derive(Debug)]
pub struct PusSchedulerAlloc {
pub struct PusScheduler {
// TODO: Use MonotonicTime from tai-time crate instead of UnixTime and cache leap seconds.
// TODO: Introduce optional limit of commands stored in the TC map. If a limit is set,
// there will be a check for each insertion whether the map is full, making the memory
@@ -341,8 +411,7 @@ pub mod alloc_mod {
time_margin: Duration,
enabled: bool,
}
impl PusSchedulerAlloc {
impl PusScheduler {
/// Create a new PUS scheduler.
///
/// # Arguments
@@ -354,7 +423,7 @@ pub mod alloc_mod {
/// * `tc_buf_size` - Buffer for temporary storage of telecommand packets. This buffer
/// should be large enough to accomodate the largest expected TC packets.
pub fn new(init_current_time: UnixTime, time_margin: Duration) -> Self {
PusSchedulerAlloc {
PusScheduler {
tc_map: Default::default(),
current_time: init_current_time,
time_margin,
@@ -376,12 +445,10 @@ pub mod alloc_mod {
num_entries
}
#[inline]
pub fn update_time(&mut self, current_time: UnixTime) {
self.current_time = current_time;
}
#[inline]
pub fn current_time(&self) -> &UnixTime {
&self.current_time
}
@@ -725,7 +792,7 @@ pub mod alloc_mod {
}
}
impl PusScheduler for PusSchedulerAlloc {
impl PusSchedulerProvider for PusScheduler {
type TimeProvider = cds::CdsTime;
/// This will disable the scheduler and clear the schedule as specified in 6.11.4.4.
@@ -795,8 +862,7 @@ mod tests {
PoolAddr, PoolError, PoolProvider, StaticMemoryPool, StaticPoolAddr, StaticPoolConfig,
};
use alloc::collections::btree_map::Range;
use arbitrary_int::traits::Integer;
use arbitrary_int::{u11, u14};
use arbitrary_int::traits::Integer as _;
use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader};
use spacepackets::ecss::{CreatorConfig, WritablePusPacket};
use spacepackets::time::{TimeWriter, UnixTime, cds};
@@ -806,6 +872,8 @@ mod tests {
#[allow(unused_imports)]
use std::{println, vec};
const ZERO_SEQ: u14 = u14::ZERO;
fn pus_tc_base(timestamp: UnixTime, buf: &mut [u8]) -> (SpHeader, usize) {
let cds_time =
cds::CdsTime::from_unix_time_with_u16_days(&timestamp, cds::SubmillisPrecision::Absent)
@@ -881,8 +949,7 @@ mod tests {
#[test]
fn test_enable_api() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
assert!(scheduler.is_enabled());
scheduler.disable();
assert!(!scheduler.is_enabled());
@@ -896,8 +963,7 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
@@ -939,8 +1005,7 @@ mod tests {
#[test]
fn insert_multi_with_same_time() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
scheduler
.insert_unwrapped_and_stored_tc(
@@ -952,7 +1017,7 @@ mod tests {
}),
RequestId {
seq_count: u14::new(1),
apid: u11::ZERO,
apid: u11::new(0),
source_id: 0,
},
),
@@ -999,8 +1064,7 @@ mod tests {
#[test]
fn test_time_update() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let time = UnixTime::new(1, 2_000_000);
scheduler.update_time(time);
assert_eq!(scheduler.current_time(), &time);
@@ -1030,22 +1094,20 @@ mod tests {
#[test]
fn test_request_id() {
let src_id_to_set = 12;
let apid_to_set = u11::new(0x22);
let seq_count = u14::new(105);
let sp_header = SpHeader::new_for_unseg_tc(apid_to_set, u14::new(105), 0);
let apid_to_set = 0x22;
let seq_count = 105;
let sp_header = SpHeader::new_for_unseg_tc(u11::new(apid_to_set), u14::new(105), 0);
let mut sec_header = PusTcSecondaryHeader::new_simple(17, 1);
sec_header.source_id = src_id_to_set;
let ping_tc =
PusTcCreator::new_no_app_data(sp_header, sec_header, CreatorConfig::default());
let req_id = RequestId::from_tc(&ping_tc);
assert_eq!(req_id.source_id(), src_id_to_set);
assert_eq!(req_id.apid(), apid_to_set);
assert_eq!(req_id.seq_count(), seq_count);
assert_eq!(req_id.apid().value(), apid_to_set);
assert_eq!(req_id.seq_count().value(), seq_count);
assert_eq!(
req_id.as_u64(),
((src_id_to_set as u64) << 32)
| (apid_to_set.value() as u64) << 16
| seq_count.value() as u64
((src_id_to_set as u64) << 32) | (apid_to_set as u64) << 16 | seq_count as u64
);
}
#[test]
@@ -1054,11 +1116,10 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::ZERO, &[]);
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
scheduler
.insert_unwrapped_and_stored_tc(UnixTime::new_only_secs(100), tc_info_0)
@@ -1123,11 +1184,10 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::ZERO, &[]);
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
scheduler
.insert_unwrapped_and_stored_tc(UnixTime::new_only_secs(100), tc_info_0)
@@ -1184,13 +1244,12 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
scheduler.disable();
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::ZERO, &[]);
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
scheduler
.insert_unwrapped_and_stored_tc(UnixTime::new_only_secs(100), tc_info_0)
@@ -1250,15 +1309,14 @@ mod tests {
#[test]
fn insert_unwrapped_tc() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new_from_subpool_cfg_tuples(
vec![(10, 32), (5, 64)],
false,
));
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::ZERO, &[]);
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
let info = scheduler
.insert_unwrapped_tc(
@@ -1273,7 +1331,7 @@ mod tests {
let mut read_buf: [u8; 64] = [0; 64];
pool.read(&tc_info_0.addr(), &mut read_buf).unwrap();
let check_tc = PusTcReader::new(&read_buf).expect("incorrect Pus tc raw data");
assert_eq!(check_tc, base_ping_tc_simple_ctor(u14::ZERO, &[]));
assert_eq!(check_tc, base_ping_tc_simple_ctor(u14::new(0), &[]));
assert_eq!(scheduler.num_scheduled_telecommands(), 1);
@@ -1301,8 +1359,7 @@ mod tests {
#[test]
fn insert_wrapped_tc() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new_from_subpool_cfg_tuples(
vec![(10, 32), (5, 64)],
@@ -1324,7 +1381,7 @@ mod tests {
let read_len = pool.read(&info.addr, &mut buf).unwrap();
let check_tc = PusTcReader::new(&buf).expect("incorrect Pus tc raw data");
assert_eq!(read_len, check_tc.packet_len());
assert_eq!(check_tc, base_ping_tc_simple_ctor(u14::ZERO, &[]));
assert_eq!(check_tc, base_ping_tc_simple_ctor(u14::new(0), &[]));
assert_eq!(scheduler.num_scheduled_telecommands(), 1);
@@ -1354,8 +1411,7 @@ mod tests {
#[test]
fn insert_wrong_service() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new_from_subpool_cfg_tuples(
vec![(10, 32), (5, 64)],
@@ -1380,8 +1436,7 @@ mod tests {
#[test]
fn insert_wrong_subservice() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new_from_subpool_cfg_tuples(
vec![(10, 32), (5, 64)],
@@ -1406,8 +1461,7 @@ mod tests {
#[test]
fn insert_wrapped_tc_faulty_app_data() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new_from_subpool_cfg_tuples(
vec![(10, 32), (5, 64)],
false,
@@ -1424,8 +1478,7 @@ mod tests {
#[test]
fn insert_doubly_wrapped_time_tagged_cmd() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new_from_subpool_cfg_tuples(
vec![(10, 32), (5, 64)],
false,
@@ -1443,7 +1496,7 @@ mod tests {
#[test]
fn test_ctor_from_current() {
let scheduler = PusSchedulerAlloc::new_with_current_init_time(Duration::from_secs(5))
let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5))
.expect("creation from current time failed");
let current_time = scheduler.current_time;
assert!(current_time.as_secs() > 0);
@@ -1451,8 +1504,7 @@ mod tests {
#[test]
fn test_update_from_current() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
assert_eq!(scheduler.current_time.as_secs(), 0);
scheduler
.update_time_from_now()
@@ -1462,8 +1514,7 @@ mod tests {
#[test]
fn release_time_within_time_margin() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new_from_subpool_cfg_tuples(
vec![(10, 32), (5, 64)],
@@ -1496,10 +1547,9 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::ZERO, &[]);
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
scheduler
.insert_unwrapped_and_stored_tc(UnixTime::new_only_secs(100), tc_info_0)
.expect("insertion failed");
@@ -1534,10 +1584,9 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::ZERO, &[]);
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
scheduler
.insert_unwrapped_and_stored_tc(UnixTime::new_only_secs(100), tc_info_0)
.expect("insertion failed");
@@ -1561,10 +1610,9 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::ZERO, &[]);
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
scheduler
.insert_unwrapped_and_stored_tc(UnixTime::new_only_secs(100), tc_info_0)
.expect("inserting tc failed");
@@ -1583,10 +1631,9 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::ZERO, &[]);
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
scheduler
.insert_unwrapped_and_stored_tc(UnixTime::new_only_secs(100), tc_info_0)
.expect("inserting tc failed");
@@ -1605,10 +1652,9 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::ZERO, &[]);
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
scheduler
.insert_unwrapped_and_stored_tc(UnixTime::new_only_secs(100), tc_info_0)
.expect("inserting tc failed");
@@ -1648,8 +1694,7 @@ mod tests {
#[test]
fn insert_full_store_test() {
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new_from_subpool_cfg_tuples(
vec![(1, 64)],
@@ -1665,7 +1710,7 @@ mod tests {
assert!(insert_res.is_err());
let err = insert_res.unwrap_err();
match err {
ScheduleError::Pool(e) => match e {
ScheduleError::StoreError(e) => match e {
PoolError::StoreFull(_) => {}
_ => panic!("unexpected store error {e}"),
},
@@ -1675,7 +1720,7 @@ mod tests {
fn insert_command_with_release_time(
pool: &mut StaticMemoryPool,
scheduler: &mut PusSchedulerAlloc,
scheduler: &mut PusScheduler,
seq_count: u14,
release_secs: u64,
) -> TcInfo {
@@ -1694,10 +1739,11 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let tc_info_0 = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 50);
let tc_info_1 = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 100);
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let tc_info_0 =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::new(0), 50);
let tc_info_1 =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::new(0), 100);
assert_eq!(scheduler.num_scheduled_telecommands(), 2);
let check_range = |range: Range<UnixTime, Vec<TcInfo>>| {
let mut tcs_in_range = 0;
@@ -1727,11 +1773,12 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let _ = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 50);
let tc_info_1 = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 100);
let tc_info_2 = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 150);
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let _ = insert_command_with_release_time(&mut pool, &mut scheduler, u14::new(0), 50);
let tc_info_1 =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::new(0), 100);
let tc_info_2 =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::new(0), 150);
let start_stamp = cds::CdsTime::from_unix_time_with_u16_days(
&UnixTime::new_only_secs(100),
cds::SubmillisPrecision::Absent,
@@ -1763,11 +1810,12 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let tc_info_0 = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 50);
let tc_info_1 = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 100);
let _ = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 150);
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let tc_info_0 =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::new(0), 50);
let tc_info_1 =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::new(0), 100);
let _ = insert_command_with_release_time(&mut pool, &mut scheduler, u14::new(0), 150);
assert_eq!(scheduler.num_scheduled_telecommands(), 3);
let end_stamp = cds::CdsTime::from_unix_time_with_u16_days(
@@ -1799,12 +1847,11 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let _ = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 50);
let tc_info_1 = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 100);
let tc_info_2 = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 150);
let _ = insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 200);
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let _ = insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 50);
let tc_info_1 = insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 100);
let tc_info_2 = insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 150);
let _ = insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 200);
assert_eq!(scheduler.num_scheduled_telecommands(), 4);
let start_stamp = cds::CdsTime::from_unix_time_with_u16_days(
@@ -1841,10 +1888,9 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 50);
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 100);
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 50);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 100);
assert_eq!(scheduler.num_scheduled_telecommands(), 2);
let del_res = scheduler.delete_all(&mut pool);
assert!(del_res.is_ok());
@@ -1853,8 +1899,8 @@ mod tests {
// Contrary to reset, this does not disable the scheduler.
assert!(scheduler.is_enabled());
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 50);
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 100);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 50);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 100);
assert_eq!(scheduler.num_scheduled_telecommands(), 2);
let del_res = scheduler
.delete_by_time_filter(TimeWindow::<cds::CdsTime>::new_select_all(), &mut pool);
@@ -1871,13 +1917,12 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 50);
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 50);
let cmd_0_to_delete =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 100);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 100);
let cmd_1_to_delete =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 150);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 150);
assert_eq!(scheduler.num_scheduled_telecommands(), 3);
let start_stamp = cds::CdsTime::from_unix_time_with_u16_days(
&UnixTime::new_only_secs(100),
@@ -1899,13 +1944,12 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let cmd_0_to_delete =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 50);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 50);
let cmd_1_to_delete =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 100);
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 150);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 100);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 150);
assert_eq!(scheduler.num_scheduled_telecommands(), 3);
let end_stamp = cds::CdsTime::from_unix_time_with_u16_days(
@@ -1928,16 +1972,15 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let cmd_out_of_range_0 =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 50);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 50);
let cmd_0_to_delete =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 100);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 100);
let cmd_1_to_delete =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 150);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 150);
let cmd_out_of_range_1 =
insert_command_with_release_time(&mut pool, &mut scheduler, u14::ZERO, 200);
insert_command_with_release_time(&mut pool, &mut scheduler, ZERO_SEQ, 200);
assert_eq!(scheduler.num_scheduled_telecommands(), 4);
let start_stamp = cds::CdsTime::from_unix_time_with_u16_days(
@@ -1967,11 +2010,10 @@ mod tests {
vec![(10, 32), (5, 64)],
false,
));
let mut scheduler =
PusSchedulerAlloc::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut scheduler = PusScheduler::new(UnixTime::new_only_secs(0), Duration::from_secs(5));
let mut buf: [u8; 32] = [0; 32];
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::ZERO, &[]);
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, u14::new(0), &[]);
scheduler
.insert_unwrapped_and_stored_tc(UnixTime::new_only_secs(100), tc_info_0)

View File

@@ -1,4 +1,4 @@
use super::scheduler::PusScheduler;
use super::scheduler::PusSchedulerProvider;
use super::verification::{VerificationReporter, VerificationReportingProvider};
use super::{
CacheAndReadRawEcssTc, DirectPusPacketHandlerResult, EcssTcInSharedPoolCacher, EcssTcReceiver,
@@ -26,11 +26,11 @@ pub struct PusSchedServiceHandler<
TmSender: EcssTmSender,
TcInMemConverter: CacheAndReadRawEcssTc,
VerificationReporter: VerificationReportingProvider,
PusSchedulerInstance: PusScheduler,
PusScheduler: PusSchedulerProvider,
> {
pub service_helper:
PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
scheduler: PusSchedulerInstance,
scheduler: PusScheduler,
}
impl<
@@ -38,7 +38,7 @@ impl<
TmSender: EcssTmSender,
TcInMemConverter: CacheAndReadRawEcssTc,
VerificationReporter: VerificationReportingProvider,
Scheduler: PusScheduler,
Scheduler: PusSchedulerProvider,
> PusSchedServiceHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter, Scheduler>
{
pub fn new(
@@ -254,13 +254,13 @@ mod tests {
use crate::pus::{DirectPusPacketHandlerResult, MpscTcReceiver, PusPacketHandlingError};
use crate::pus::{
EcssTcInSharedPoolCacher,
scheduler::{self, PusScheduler, TcInfo},
scheduler::{self, PusSchedulerProvider, TcInfo},
tests::PusServiceHandlerWithSharedStoreCommon,
verification::{RequestId, TcStateAccepted, VerificationToken},
};
use crate::tmtc::PacketSenderWithSharedPool;
use alloc::collections::VecDeque;
use arbitrary_int::traits::Integer as _;
use arbitrary_int::traits::Integer;
use arbitrary_int::u14;
use delegate::delegate;
use spacepackets::SpHeader;
@@ -349,7 +349,7 @@ mod tests {
inserted_tcs: VecDeque<TcInfo>,
}
impl PusScheduler for TestScheduler {
impl PusSchedulerProvider for TestScheduler {
type TimeProvider = cds::CdsTime;
fn reset(
@@ -446,7 +446,7 @@ mod tests {
let ping_raw = ping_tc.to_vec().expect("generating raw tc failed");
sched_app_data[written_len..written_len + ping_raw.len()].copy_from_slice(&ping_raw);
written_len += ping_raw.len();
reply_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
reply_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::new(1), 0);
sec_header = PusTcSecondaryHeader::new_simple(11, Subservice::TcInsertActivity as u8);
let enable_scheduling = PusTcCreator::new(
reply_header,

View File

@@ -2,7 +2,6 @@ use crate::pus::{
DirectPusPacketHandlerResult, PartialPusHandlingError, PusPacketHandlingError, PusTmVariant,
};
use crate::tmtc::{PacketAsVec, PacketSenderWithSharedPool};
use arbitrary_int::traits::Integer as _;
use arbitrary_int::u14;
use spacepackets::SpHeader;
use spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader};
@@ -79,7 +78,7 @@ impl<
// the unchecked API here.
let reply_header = SpHeader::new_for_unseg_tm(
self.service_helper.verif_reporter().apid(),
u14::ZERO,
u14::new(0),
0,
);
let tc_header = PusTmSecondaryHeader::new_simple(17, 2, time_stamp);
@@ -154,7 +153,6 @@ mod tests {
PartialPusHandlingError, PusPacketHandlingError,
};
use crate::tmtc::PacketSenderWithSharedPool;
use arbitrary_int::traits::Integer as _;
use arbitrary_int::u14;
use delegate::delegate;
use spacepackets::SpHeader;
@@ -291,7 +289,7 @@ mod tests {
fn ping_test(test_harness: &mut (impl PusTestHarness + SimplePusPacketHandler)) {
// Create a ping TC, verify acceptance.
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::new(0), 0);
let sec_header = PusTcSecondaryHeader::new_simple(17, 1);
let ping_tc =
PusTcCreator::new_no_app_data(sp_header, sec_header, CreatorConfig::default());
@@ -347,7 +345,7 @@ mod tests {
#[test]
fn test_sending_unsupported_service() {
let mut test_harness = Pus17HandlerWithStoreTester::new(0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::new(0), 0);
let sec_header = PusTcSecondaryHeader::new_simple(3, 1);
let ping_tc =
PusTcCreator::new_no_app_data(sp_header, sec_header, CreatorConfig::default());
@@ -369,7 +367,7 @@ mod tests {
#[test]
fn test_sending_custom_subservice() {
let mut test_harness = Pus17HandlerWithStoreTester::new(0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::ZERO, 0);
let sp_header = SpHeader::new_for_unseg_tc(TEST_APID, u14::new(0), 0);
let sec_header = PusTcSecondaryHeader::new_simple(17, 200);
let ping_tc =
PusTcCreator::new_no_app_data(sp_header, sec_header, CreatorConfig::default());

View File

@@ -20,15 +20,15 @@
//! VerificationReportingProvider, VerificationReporterConfig, VerificationReporter
//! };
//! use satrs::tmtc::{SharedStaticMemoryPool, PacketSenderWithSharedPool};
//! use satrs::spacepackets::seq_count::SeqCountProviderSimple;
//! use satrs::request::UniqueApidTargetId;
//! use spacepackets::ecss::PusPacket;
//! use spacepackets::SpHeader;
//! use spacepackets::ecss::tc::{PusTcCreator, PusTcSecondaryHeader, CreatorConfig};
//! use spacepackets::ecss::tc::{PusTcCreator, PusTcSecondaryHeader};
//! use spacepackets::ecss::tm::PusTmReader;
//! use arbitrary_int::u11;
//!
//! const EMPTY_STAMP: [u8; 7] = [0; 7];
//! const TEST_APID: u11 = u11::new(0x02);
//! const TEST_APID: u16 = 0x02;
//! const TEST_COMPONENT_ID: UniqueApidTargetId = UniqueApidTargetId::new(TEST_APID, 0x05);
//!
//! let pool_cfg = StaticPoolConfig::new_from_subpool_cfg_tuples(
@@ -38,14 +38,14 @@
//! let shared_tm_pool = SharedStaticMemoryPool::new(RwLock::new(tm_pool));
//! let (verif_tx, verif_rx) = mpsc::sync_channel(10);
//! let sender = PacketSenderWithSharedPool::new_with_shared_packet_pool(verif_tx, &shared_tm_pool);
//! let cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, 8);
//! let cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, 8).unwrap();
//! let mut reporter = VerificationReporter::new(TEST_COMPONENT_ID.id(), &cfg);
//!
//! let tc_header = PusTcSecondaryHeader::new_simple(17, 1);
//! let pus_tc_0 = PusTcCreator::new_no_app_data(
//! SpHeader::new_from_apid(TEST_APID),
//! tc_header,
//! CreatorConfig::default()
//! true
//! );
//! let init_token = reporter.start_verification(&pus_tc_0);
//!
@@ -82,6 +82,7 @@
//! context involving multiple threads
use crate::params::{Params, WritableToBeBytes};
use crate::pus::{EcssTmSender, EcssTmtcError, source_buffer_large_enough};
use arbitrary_int::traits::Integer as _;
use arbitrary_int::{u3, u11, u14};
use core::fmt::{Debug, Display, Formatter};
use core::hash::{Hash, Hasher};
@@ -91,14 +92,13 @@ use core::mem::size_of;
use delegate::delegate;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use spacepackets::SpHeader;
use spacepackets::ecss::tc::IsPusTelecommand;
use spacepackets::ecss::tm::{PusTmCreator, PusTmSecondaryHeader};
use spacepackets::ecss::{CreatorConfig, EcssEnumeration};
use spacepackets::{ByteConversionError, CcsdsPacket, PacketId, PacketSequenceControl};
use spacepackets::{MAX_APID, SpHeader};
pub use spacepackets::ecss::verification::*;
pub use spacepackets::seq_count::SequenceCounterSimple;
#[cfg(feature = "alloc")]
pub use alloc_mod::*;
@@ -158,18 +158,16 @@ impl RequestId {
}
pub fn raw(&self) -> u32 {
((self.version_number.value() as u32) << 29)
((self.version_number.as_u32()) << 29)
| ((self.packet_id.raw() as u32) << 16)
| self.psc.raw() as u32
}
#[inline]
pub const fn packet_id(&self) -> PacketId {
pub fn packet_id(&self) -> PacketId {
self.packet_id
}
#[inline]
pub const fn packet_seq_ctrl(&self) -> PacketSequenceControl {
pub fn packet_sequence_control(&self) -> PacketSequenceControl {
self.psc
}
@@ -835,7 +833,7 @@ impl VerificationReportCreator {
#[cfg(feature = "alloc")]
pub mod alloc_mod {
use arbitrary_int::traits::Integer as _;
use arbitrary_int::u11;
use spacepackets::ecss::PusError;
use super::*;
@@ -856,13 +854,16 @@ pub mod alloc_mod {
step_field_width: usize,
fail_code_field_width: usize,
max_fail_data_len: usize,
) -> Self {
Self {
) -> Option<Self> {
if apid > MAX_APID {
return None;
}
Some(Self {
apid,
step_field_width,
fail_code_field_width,
max_fail_data_len,
}
})
}
}
@@ -874,7 +875,7 @@ pub mod alloc_mod {
fn modify_tm(&self, tm: &mut PusTmCreator);
}
/// [VerificationHook] which does nothing. This is the default hook variant for
/// [VerificationHookProvider] which does nothing. This is the default hook variant for
/// the [VerificationReporter], assuming that any necessary packet manipulation is performed by
/// a centralized TM funnel or inlet.
#[derive(Default, Copy, Clone)]
@@ -920,7 +921,7 @@ pub mod alloc_mod {
}
impl<VerificationHookInstance: VerificationHook> VerificationReporter<VerificationHookInstance> {
/// The provided [VerificationHook] can be used to modify a verification packet
/// The provided [VerificationHookProvider] can be used to modify a verification packet
/// before it is sent.
pub fn new_with_hook(
owner_id: ComponentId,
@@ -1006,7 +1007,7 @@ pub mod alloc_mod {
.acceptance_success(
source_data_buf.as_mut_slice(),
&token.request_id(),
u14::ZERO,
u14::new(0),
0,
time_stamp,
)
@@ -1029,7 +1030,7 @@ pub mod alloc_mod {
.acceptance_failure(
buf.as_mut_slice(),
&token.request_id(),
u14::ZERO,
u14::new(0),
0,
params,
)
@@ -1054,7 +1055,7 @@ pub mod alloc_mod {
.start_success(
buf.as_mut_slice(),
&token.request_id(),
u14::ZERO,
u14::new(0),
0,
time_stamp,
)
@@ -1080,7 +1081,7 @@ pub mod alloc_mod {
.start_failure(
buf.as_mut_slice(),
&token.request_id(),
u14::ZERO,
u14::new(0),
0,
params,
)
@@ -1106,7 +1107,7 @@ pub mod alloc_mod {
.step_success(
buf.as_mut_slice(),
&token.request_id(),
u14::ZERO,
u14::new(0),
0,
time_stamp,
step,
@@ -1130,7 +1131,7 @@ pub mod alloc_mod {
let mut buf = self.source_data_buf.borrow_mut();
let mut tm_creator = self
.reporter_creator
.step_failure(buf.as_mut_slice(), token, u14::ZERO, 0, params)
.step_failure(buf.as_mut_slice(), token, u14::new(0), 0, params)
.map_err(PusError::ByteConversion)?;
self.tm_hook.modify_tm(&mut tm_creator);
sender.send_tm(self.owner_id(), PusTmVariant::Direct(tm_creator))?;
@@ -1154,7 +1155,7 @@ pub mod alloc_mod {
.completion_success(
buf.as_mut_slice(),
&token.request_id(),
u14::ZERO,
u14::new(0),
0,
time_stamp,
)
@@ -1180,7 +1181,7 @@ pub mod alloc_mod {
.completion_failure(
buf.as_mut_slice(),
&token.request_id(),
u14::ZERO,
u14::new(0),
0,
params,
)
@@ -1333,7 +1334,7 @@ pub fn handle_step_failure_with_generic_params(
#[cfg(any(feature = "test_util", test))]
pub mod test_util {
use alloc::vec::Vec;
use arbitrary_int::traits::Integer;
use arbitrary_int::u11;
use core::cell::RefCell;
use std::collections::VecDeque;
@@ -1395,7 +1396,7 @@ pub mod test_util {
fn set_apid(&mut self, _apid: Apid) {}
fn apid(&self) -> Apid {
Apid::ZERO
u11::new(0)
}
fn acceptance_success(
@@ -1727,13 +1728,13 @@ pub mod tests {
use crate::tmtc::{PacketSenderWithSharedPool, SharedPacketPool};
use alloc::format;
use alloc::string::ToString;
use arbitrary_int::traits::Integer;
use arbitrary_int::{u11, u14};
use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader};
use spacepackets::ecss::{
CreatorConfig, EcssEnumU8, EcssEnumU16, EcssEnumU32, EcssEnumeration, PusError, PusPacket,
WritablePusPacket,
};
use spacepackets::seq_count::SequenceCounterSimple;
use spacepackets::util::UnsignedEnum;
use spacepackets::{ByteConversionError, SpHeader};
use std::cell::RefCell;
@@ -1743,8 +1744,8 @@ pub mod tests {
use std::vec::Vec;
use super::{
DummyVerificationHook, FailParamHelper, SequenceCounterSimple, TcStateAccepted,
TcStateStarted, VerificationHook, VerificationReportingProvider, WasAtLeastAccepted,
DummyVerificationHook, FailParamHelper, TcStateAccepted, TcStateStarted, VerificationHook,
VerificationReportingProvider, WasAtLeastAccepted,
handle_completion_failure_with_generic_params,
};
@@ -1832,7 +1833,7 @@ pub mod tests {
}
fn base_reporter(id: ComponentId, max_fail_data_len: usize) -> VerificationReporter {
let cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, max_fail_data_len);
let cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, max_fail_data_len).unwrap();
VerificationReporter::new(id, &cfg)
}
@@ -1840,7 +1841,7 @@ pub mod tests {
id: ComponentId,
hook: VerificationHookInstance,
) -> VerificationReporter<VerificationHookInstance> {
let cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, 8);
let cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, 8).unwrap();
VerificationReporter::new_with_hook(id, &cfg, hook)
}
@@ -1942,7 +1943,7 @@ pub mod tests {
common: CommonTmInfo::new(
1,
TEST_APID,
u14::ZERO,
u14::new(0),
0,
self.reporter.dest_id(),
timestamp,
@@ -2009,7 +2010,7 @@ pub mod tests {
common: CommonTmInfo::new(
2,
TEST_APID,
u14::ZERO,
u14::new(0),
0,
self.reporter.dest_id(),
timestamp,
@@ -2274,7 +2275,7 @@ pub mod tests {
.expect("step 1 failed");
assert_eq!(testbench.sender.service_queue.borrow().len(), 4);
testbench.check_acceptance_success(&EMPTY_STAMP);
testbench.check_start_success(u14::ZERO, 0, &EMPTY_STAMP);
testbench.check_start_success(u14::new(0), 0, &EMPTY_STAMP);
testbench.check_step_success(0, &EMPTY_STAMP);
testbench.check_step_success(1, &EMPTY_STAMP);
}
@@ -2308,7 +2309,7 @@ pub mod tests {
.step_failure(started_token, fail_params)
.expect("Step failure failed");
testbench.check_acceptance_success(&EMPTY_STAMP);
testbench.check_start_success(u14::ZERO, 0, DUMMY_STAMP);
testbench.check_start_success(u14::new(0), 0, DUMMY_STAMP);
testbench.check_step_success(0, &EMPTY_STAMP);
testbench.check_step_failure(&fail_step, &fail_code, &fail_data_raw);
}
@@ -2330,7 +2331,7 @@ pub mod tests {
.completion_failure(started_token, fail_params)
.expect("Completion failure");
testbench.check_acceptance_success(&EMPTY_STAMP);
testbench.check_start_success(u14::ZERO, 0, DUMMY_STAMP);
testbench.check_start_success(u14::new(0), 0, DUMMY_STAMP);
testbench.check_completion_failure(&fail_code, &[]);
}
@@ -2350,8 +2351,8 @@ pub mod tests {
.completion_success(started_token, &EMPTY_STAMP)
.expect("Sending completion success failed");
testbench.check_acceptance_success(&EMPTY_STAMP);
testbench.check_start_success(u14::ZERO, 0, DUMMY_STAMP);
testbench.check_completion_success(u14::ZERO, 0);
testbench.check_start_success(u14::new(0), 0, DUMMY_STAMP);
testbench.check_completion_success(u14::new(0), 0);
}
#[test]
@@ -2432,7 +2433,7 @@ pub mod tests {
);
assert!(result.unwrap());
testbench.check_acceptance_success(&EMPTY_STAMP);
testbench.check_start_success(u14::ZERO, 0, &EMPTY_STAMP);
testbench.check_start_success(u14::new(0), 0, &EMPTY_STAMP);
testbench.check_step_failure(&step, &fail_code, fail_data.as_bytes());
}

View File

@@ -1,4 +1,4 @@
use arbitrary_int::u11;
use arbitrary_int::{traits::Integer as _, u11};
use core::{fmt, marker::PhantomData};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
@@ -23,7 +23,7 @@ use crate::{
/// for them. This can be useful for tasks like tracking their progress.
pub type RequestId = u32;
/// CCSDS APID type definition. Please note that the APID is a 14 bit value.
/// CCSDS APID type definition. Please note that the APID is a 11 bit value.
pub type Apid = u11;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -41,7 +41,7 @@ impl UniqueApidTargetId {
}
pub fn raw(&self) -> ComponentId {
((self.apid.value() as u64) << 32) | (self.unique_id as u64)
((self.apid.as_u64()) << 32) | (self.unique_id as u64)
}
pub fn id(&self) -> ComponentId {
@@ -496,6 +496,10 @@ pub mod std_mod {
mod tests {
use std::sync::mpsc;
use crate::{
queue::{GenericReceiveError, GenericSendError},
request::{MessageMetadata, MessageSenderMap, MessageSenderStoreProvider},
};
use alloc::string::ToString;
use arbitrary_int::{u11, u14};
use spacepackets::{
@@ -506,11 +510,6 @@ mod tests {
},
};
use crate::{
queue::{GenericReceiveError, GenericSendError},
request::{Apid, MessageMetadata, MessageSenderMap, MessageSenderStoreProvider},
};
use super::{GenericMessage, MessageReceiverWithId, UniqueApidTargetId};
const TEST_CHANNEL_ID_0: u64 = 1;
@@ -519,7 +518,7 @@ mod tests {
#[test]
fn test_basic_target_id_with_apid() {
let id = UniqueApidTargetId::new(Apid::new(0x111), 0x01);
let id = UniqueApidTargetId::new(u11::new(0x111), 0x01);
assert_eq!(id.apid.value(), 0x111);
assert_eq!(id.unique_id, 0x01);
assert_eq!(id.id(), id.raw());

View File

@@ -62,10 +62,9 @@ impl PusTmWithCdsShortHelper {
#[cfg(test)]
mod tests {
use arbitrary_int::{u11, u14};
use spacepackets::{CcsdsPacket, ecss::PusPacket, time::cds::CdsTime};
use super::PusTmWithCdsShortHelper;
use super::*;
#[test]
fn test_helper_with_stamper() {

View File

@@ -0,0 +1,94 @@
#![allow(dead_code, unused_imports)]
use satrs::events::{
EventU32, EventU32TypedSev, GenericEvent, HasSeverity, LargestEventRaw, LargestGroupIdRaw,
Severity, SeverityInfo, SeverityLow, SeverityMedium,
};
use std::convert::AsRef;
#[derive(Debug)]
struct GroupIdIntrospection {
name: &'static str,
id: LargestGroupIdRaw,
}
#[derive(Debug)]
struct EventIntrospection {
name: &'static str,
group_id: GroupIdIntrospection,
event: &'static EventU32,
info: &'static str,
}
//#[event(descr="This is some info event")]
const INFO_EVENT_0: EventU32TypedSev<SeverityInfo> = EventU32TypedSev::new(0, 0);
const INFO_EVENT_0_ERASED: EventU32 = EventU32::const_from_info(INFO_EVENT_0);
// This is ideally auto-generated
const INFO_EVENT_0_INTROSPECTION: EventIntrospection = EventIntrospection {
name: "INFO_EVENT_0",
group_id: GroupIdIntrospection {
id: 0,
name: "Group ID 0 without name",
},
event: &INFO_EVENT_0_ERASED,
info: "This is some info event",
};
//#[event(descr="This is some low severity event")]
const SOME_LOW_SEV_EVENT: EventU32TypedSev<SeverityLow> = EventU32TypedSev::new(0, 12);
//const EVENT_LIST: [&'static Event; 2] = [&INFO_EVENT_0, &SOME_LOW_SEV_EVENT];
//#[event_group]
const TEST_GROUP_NAME: u16 = 1;
// Auto-generated?
const TEST_GROUP_NAME_NAME: &str = "TEST_GROUP_NAME";
//#[event(desc="Some medium severity event")]
const MEDIUM_SEV_EVENT_IN_OTHER_GROUP: EventU32TypedSev<SeverityMedium> =
EventU32TypedSev::new(TEST_GROUP_NAME, 0);
const MEDIUM_SEV_EVENT_IN_OTHER_GROUP_REDUCED: EventU32 =
EventU32::const_from_medium(MEDIUM_SEV_EVENT_IN_OTHER_GROUP);
// Also auto-generated
const MEDIUM_SEV_EVENT_IN_OTHER_GROUP_INTROSPECTION: EventIntrospection = EventIntrospection {
name: "MEDIUM_SEV_EVENT_IN_OTHER_GROUP",
group_id: GroupIdIntrospection {
name: TEST_GROUP_NAME_NAME,
id: TEST_GROUP_NAME,
},
event: &MEDIUM_SEV_EVENT_IN_OTHER_GROUP_REDUCED,
info: "Some medium severity event",
};
const CONST_SLICE: &[u8] = &[0, 1, 2, 3];
const INTROSPECTION_FOR_TEST_GROUP_0: [&EventIntrospection; 2] =
[&INFO_EVENT_0_INTROSPECTION, &INFO_EVENT_0_INTROSPECTION];
//const INTROSPECTION_FOR_TABLE: &'static [&EventIntrospection] = &INTROSPECTION_FOR_TEST_GROUP_0;
const INTROSPECTION_FOR_TEST_GROUP_NAME: [&EventIntrospection; 1] =
[&MEDIUM_SEV_EVENT_IN_OTHER_GROUP_INTROSPECTION];
//const BLAH: &'static [&EventIntrospection] = &INTROSPECTION_FOR_TEST_GROUP_NAME;
const ALL_EVENTS: [&[&EventIntrospection]; 2] = [
&INTROSPECTION_FOR_TEST_GROUP_0,
&INTROSPECTION_FOR_TEST_GROUP_NAME,
];
#[test]
fn main() {
//let test = stringify!(INFO_EVENT);
//println!("{:?}", test);
//for event in EVENT_LIST {
// println!("{:?}", event);
//}
//for events in ALL_EVENTS.into_iter().flatten() {
// dbg!("{:?}", events);
//}
//for introspection_info in INTROSPECTION_FOR_TEST_GROUP {
// dbg!("{:?}", introspection_info);
//}
//let test_struct =
}

View File

@@ -1,9 +1,9 @@
use arbitrary_int::u11;
use satrs::event_man_legacy::{
use satrs::event_man::{
EventManagerWithMpsc, EventMessage, EventMessageU32, EventRoutingError, EventSendProvider,
EventU32SenderMpsc,
};
use satrs::events_legacy::{EventU32, EventU32TypedSev, Severity, SeverityInfo};
use satrs::events::{EventU32, EventU32TypedSev, Severity, SeverityInfo};
use satrs::params::U32Pair;
use satrs::params::{Params, ParamsHeapless, WritableToBeBytes};
use satrs::pus::event_man::{DefaultPusEventReportingMap, EventReporter, PusEventTmCreatorWithMap};
@@ -36,7 +36,8 @@ fn test_threaded_usage() {
event_man.subscribe_all(pus_event_man_send_provider.target_id());
event_man.add_sender(pus_event_man_send_provider);
let (event_packet_tx, event_packet_rx) = mpsc::channel::<PacketAsVec>();
let reporter = EventReporter::new(TEST_ID.raw(), u11::new(0x02), 0, 128);
let reporter = EventReporter::new(TEST_ID.raw(), u11::new(0x02), 0, 128)
.expect("Creating event reporter failed");
let pus_event_man =
PusEventTmCreatorWithMap::new(reporter, DefaultPusEventReportingMap::default());
let error_handler = |event_msg: &EventMessageU32, error: EventRoutingError| {

View File

@@ -33,7 +33,7 @@ pub mod crossbeam_test {
// We use a synced sequence count provider here because both verification reporters have the
// the same APID. If they had distinct APIDs, the more correct approach would be to have
// each reporter have an own sequence count provider.
let cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, 8);
let cfg = VerificationReporterConfig::new(TEST_APID, 1, 2, 8).unwrap();
// Shared pool object to store the verification PUS telemetry
let pool_cfg = StaticPoolConfig::new_from_subpool_cfg_tuples(
vec![(10, 32), (10, 64), (10, 128), (10, 1024)],

View File

@@ -21,7 +21,7 @@ use std::{
thread,
};
use arbitrary_int::{u11, u14};
use arbitrary_int::{traits::Integer, u11, u14};
use hashbrown::HashSet;
use satrs::{
ComponentId,
@@ -268,7 +268,7 @@ fn test_ccsds_server() {
.expect("setting reas timeout failed");
// Send ping telecommand.
let sph = SpHeader::new_for_unseg_tc(TEST_APID_0, u14::new(0), 0);
let sph = SpHeader::new_for_unseg_tc(TEST_APID_0, u14::ZERO, 0);
let ping_tc = PusTcCreator::new_simple(sph, 17, 1, &[], CreatorConfig::default());
let tc_0 = ping_tc.to_vec().expect("packet creation failed");
stream