continue CCSDS scheduler
This commit is contained in:
6
justfile
6
justfile
@@ -14,12 +14,12 @@ test:
|
|||||||
embedded:
|
embedded:
|
||||||
cargo check -p satrs --target=thumbv7em-none-eabihf --no-default-features
|
cargo check -p satrs --target=thumbv7em-none-eabihf --no-default-features
|
||||||
|
|
||||||
fmt:
|
|
||||||
cargo fmt --all
|
|
||||||
|
|
||||||
check-fmt:
|
check-fmt:
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
cargo fmt --all
|
||||||
|
|
||||||
clippy:
|
clippy:
|
||||||
cargo clippy -- -D warnings
|
cargo clippy -- -D warnings
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use core::{hash::Hash, time::Duration};
|
|||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub use alloc_mod::*;
|
pub use alloc_mod::*;
|
||||||
use spacepackets::{
|
use spacepackets::{
|
||||||
ByteConversionError, PacketId, PacketSequenceControl,
|
ByteConversionError, CcsdsPacketIdAndPsc,
|
||||||
time::{TimestampError, UnixTime},
|
time::{TimestampError, UnixTime},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -24,6 +24,8 @@ pub enum ScheduleError {
|
|||||||
NestedScheduledTc,
|
NestedScheduledTc,
|
||||||
#[error("tc data empty")]
|
#[error("tc data empty")]
|
||||||
TcDataEmpty,
|
TcDataEmpty,
|
||||||
|
#[error("scheduler is full")]
|
||||||
|
Full,
|
||||||
#[error("timestamp error: {0}")]
|
#[error("timestamp error: {0}")]
|
||||||
TimestampError(#[from] TimestampError),
|
TimestampError(#[from] TimestampError),
|
||||||
#[error("wrong subservice number {0}")]
|
#[error("wrong subservice number {0}")]
|
||||||
@@ -36,33 +38,32 @@ pub enum ScheduleError {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct CcsdsPacketId {
|
pub struct CcsdsSchedulePacketId {
|
||||||
pub packet_id: PacketId,
|
pub base: CcsdsPacketIdAndPsc,
|
||||||
pub psc: PacketSequenceControl,
|
pub crc16: Option<u16>,
|
||||||
pub crc16: u16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for CcsdsPacketId {
|
impl Hash for CcsdsSchedulePacketId {
|
||||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.packet_id.hash(state);
|
self.base.hash(state);
|
||||||
self.psc.raw().hash(state);
|
|
||||||
self.crc16.hash(state);
|
self.crc16.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
pub mod alloc_mod {
|
pub mod alloc_mod {
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::time::SystemTimeError;
|
use std::time::SystemTimeError;
|
||||||
|
|
||||||
use spacepackets::time::UnixTime;
|
use spacepackets::{CcsdsPacketIdAndPsc, CcsdsPacketReader, time::UnixTime};
|
||||||
|
|
||||||
use crate::ccsds::scheduler::CcsdsPacketId;
|
use crate::ccsds::scheduler::CcsdsSchedulePacketId;
|
||||||
|
|
||||||
pub struct CcsdsScheduler {
|
pub struct CcsdsScheduler {
|
||||||
tc_map: alloc::collections::BTreeMap<
|
tc_map: alloc::collections::BTreeMap<
|
||||||
UnixTime,
|
UnixTime,
|
||||||
alloc::vec::Vec<(CcsdsPacketId, alloc::vec::Vec<u8>)>,
|
alloc::vec::Vec<(CcsdsSchedulePacketId, alloc::vec::Vec<u8>)>,
|
||||||
>,
|
>,
|
||||||
packet_limit: usize,
|
packet_limit: usize,
|
||||||
pub(crate) current_time: UnixTime,
|
pub(crate) current_time: UnixTime,
|
||||||
@@ -117,13 +118,30 @@ pub mod alloc_mod {
|
|||||||
&self.current_time
|
&self.current_time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_telecommand_with_reader(
|
||||||
|
&mut self,
|
||||||
|
reader: &CcsdsPacketReader,
|
||||||
|
release_time: UnixTime,
|
||||||
|
) -> Result<(), super::ScheduleError> {
|
||||||
|
if self.num_of_entries() + 1 >= self.packet_limit {
|
||||||
|
return Err(super::ScheduleError::Full);
|
||||||
|
}
|
||||||
|
let base_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(reader);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Implementation
|
// TODO: Implementation
|
||||||
pub fn insert_telecommand(
|
pub fn insert_telecommand(
|
||||||
&mut self,
|
&mut self,
|
||||||
packet_id: CcsdsPacketId,
|
packet_id: CcsdsSchedulePacketId,
|
||||||
packet: alloc::vec::Vec<u8>,
|
raw_packet: &[u8],
|
||||||
release_time: UnixTime,
|
release_time: UnixTime,
|
||||||
) {
|
) -> Result<(), super::ScheduleError> {
|
||||||
|
if self.num_of_entries() + 1 >= self.packet_limit {
|
||||||
|
return Err(super::ScheduleError::Full);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ extern crate downcast_rs;
|
|||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
pub mod action;
|
pub mod action;
|
||||||
|
pub mod ccsds;
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub mod dev_mgmt;
|
pub mod dev_mgmt;
|
||||||
pub mod encoding;
|
pub mod encoding;
|
||||||
@@ -51,7 +52,6 @@ pub mod scheduling;
|
|||||||
pub mod subsystem;
|
pub mod subsystem;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod tmtc;
|
pub mod tmtc;
|
||||||
pub mod ccsds;
|
|
||||||
|
|
||||||
pub use spacepackets;
|
pub use spacepackets;
|
||||||
|
|
||||||
|
|||||||
@@ -155,73 +155,34 @@ impl Display for StoreIdError {
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl Error for StoreIdError {}
|
impl Error for StoreIdError {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum PoolError {
|
pub enum PoolError {
|
||||||
/// Requested data block is too large
|
/// Requested data block is too large
|
||||||
|
#[error("data to store with size {0} is too large")]
|
||||||
DataTooLarge(usize),
|
DataTooLarge(usize),
|
||||||
/// The store is full. Contains the index of the full subpool
|
/// The store is full. Contains the index of the full subpool
|
||||||
|
#[error("store does not have any capacity")]
|
||||||
StoreFull(u16),
|
StoreFull(u16),
|
||||||
/// The store can not hold any data.
|
/// The store can not hold any data.
|
||||||
|
#[error("store does not have any capacity")]
|
||||||
NoCapacity,
|
NoCapacity,
|
||||||
/// Store ID is invalid. This also includes partial errors where only the subpool is invalid
|
/// Store ID is invalid. This also includes partial errors where only the subpool is invalid
|
||||||
|
#[error("invalid store ID: {0}, address: {1:?}")]
|
||||||
InvalidStoreId(StoreIdError, Option<PoolAddr>),
|
InvalidStoreId(StoreIdError, Option<PoolAddr>),
|
||||||
/// Valid subpool and packet index, but no data is stored at the given address
|
/// Valid subpool and packet index, but no data is stored at the given address
|
||||||
|
#[error("no data exists at address {0:?}")]
|
||||||
DataDoesNotExist(PoolAddr),
|
DataDoesNotExist(PoolAddr),
|
||||||
ByteConversionError(spacepackets::ByteConversionError),
|
#[error("byte conversion error: {0}")]
|
||||||
|
ByteConversion(#[from] spacepackets::ByteConversionError),
|
||||||
|
#[error("lock error")]
|
||||||
LockError,
|
LockError,
|
||||||
/// Internal or configuration errors
|
/// Internal or configuration errors
|
||||||
|
#[error("lock error")]
|
||||||
InternalError(u32),
|
InternalError(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for PoolError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
|
||||||
match self {
|
|
||||||
PoolError::DataTooLarge(size) => {
|
|
||||||
write!(f, "data to store with size {size} is too large")
|
|
||||||
}
|
|
||||||
PoolError::NoCapacity => {
|
|
||||||
write!(f, "store does not have any capacity")
|
|
||||||
}
|
|
||||||
PoolError::StoreFull(u16) => {
|
|
||||||
write!(f, "store is too full. index for full subpool: {u16}")
|
|
||||||
}
|
|
||||||
PoolError::InvalidStoreId(id_e, addr) => {
|
|
||||||
write!(f, "invalid store ID: {id_e}, address: {addr:?}")
|
|
||||||
}
|
|
||||||
PoolError::DataDoesNotExist(addr) => {
|
|
||||||
write!(f, "no data exists at address {addr:?}")
|
|
||||||
}
|
|
||||||
PoolError::InternalError(e) => {
|
|
||||||
write!(f, "internal error: {e}")
|
|
||||||
}
|
|
||||||
PoolError::ByteConversionError(e) => {
|
|
||||||
write!(f, "store error: {e}")
|
|
||||||
}
|
|
||||||
PoolError::LockError => {
|
|
||||||
write!(f, "lock error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ByteConversionError> for PoolError {
|
|
||||||
fn from(value: ByteConversionError) -> Self {
|
|
||||||
Self::ByteConversionError(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl Error for PoolError {
|
|
||||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
|
||||||
if let PoolError::InvalidStoreId(e, _) = self {
|
|
||||||
return Some(e);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generic trait for pool providers which provide memory pools for variable sized packet data.
|
/// Generic trait for pool providers which provide memory pools for variable sized packet data.
|
||||||
///
|
///
|
||||||
/// It specifies a basic API to [Self::add], [Self::modify], [Self::read] and [Self::delete] data
|
/// It specifies a basic API to [Self::add], [Self::modify], [Self::read] and [Self::delete] data
|
||||||
|
|||||||
Reference in New Issue
Block a user