3 Commits

Author SHA1 Message Date
3edf13cca2 small fix for serde
Some checks failed
Rust/spacepackets/pipeline/head There was a failure building this commit
Rust/spacepackets/pipeline/pr-main There was a failure building this commit
2024-03-29 13:49:21 +01:00
01168d8ab2 Merge remote-tracking branch 'origin/main' into update-ecss-code 2024-03-29 13:45:00 +01:00
1426cb514b update ECSS code
Some checks failed
Rust/spacepackets/pipeline/head There was a failure building this commit
2024-03-29 13:24:49 +01:00
26 changed files with 175 additions and 765 deletions

View File

@ -27,7 +27,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.65.0 toolchain: 1.61.0
override: true override: true
profile: minimal profile: minimal
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1

View File

@ -8,47 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased] # [unreleased]
# [v0.11.1] 2024-04-22
## Fixed
- The default data length for for `SpHeader` constructors where the data field length is not
specified is now 0.
- The `SpHeader::new_from_fields` is public now.
## Added
- `SpHeader::to_vec` method.
# [v0.11.0] 2024-04-16
## Changed
- Moved `CCSDS_HEADER_LEN` constant to the crate root.
## Added
- Added `SpacePacketHeader` type alias for `SpHeader` type.
# [v0.11.0-rc.2] 2024-04-04
## Changed
- Renamed `PacketId` and `PacketSequenceCtrl` `new` method to `new_checked` and former
`new_const` method to `new`.
- Renamed `tc`, `tm`, `tc_unseg` and `tm_unseg` variants for `PacketId` and `SpHeader`
to `new_for_tc_checked`, `new_for_tm_checked`, `new_for_unseg_tc_checked` and
`new_for_unseg_tm_checked`.
- `PusTmCreator` and `PusTcCreator` now expect a regular instance of `SpHeader` instead of
a mutable reference.
## Added
- `SpHeader::new_from_apid` and `SpHeader::new_from_apid_checked` constructor.
- `#[inline]` attribute for a lot of small functions.
# [v0.11.0-rc.1] 2024-04-03
Major API changes for the time API. If you are using the time API, it is strongly recommended Major API changes for the time API. If you are using the time API, it is strongly recommended
to check all the API changes in the **Changed** chapter. to check all the API changes in the **Changed** chapter.
@ -65,14 +24,9 @@ to check all the API changes in the **Changed** chapter.
- Added basic support conversions to the `time` library. Introduce new `chrono` and `timelib` - Added basic support conversions to the `time` library. Introduce new `chrono` and `timelib`
feature gate. feature gate.
- Added `CcsdsTimeProvider::timelib_date_time`. - Added `CcsdsTimeProvider::timelib_date_time`.
- Optional support for `defmt` by adding optional `defmt::Format` derives for common types.
## Changed ## Changed
- `PusTcCreator::new_simple` now expects a valid slice for the source data instead of an optional
slice. For telecommands without application data, `&[]` can be passed.
- `PusTmSecondaryHeader` constructors now expects a valid slice for the time stamp instead of an
optional slice.
- Renamed `CcsdsTimeProvider::date_time` to `CcsdsTimeProvider::chrono_date_time` - Renamed `CcsdsTimeProvider::date_time` to `CcsdsTimeProvider::chrono_date_time`
- Renamed `CcsdsTimeCodes` to `CcsdsTimeCode` - Renamed `CcsdsTimeCodes` to `CcsdsTimeCode`
- Renamed `cds::TimeProvider` to `cds::CdsTime` - Renamed `cds::TimeProvider` to `cds::CdsTime`

View File

@ -1,8 +1,8 @@
[package] [package]
name = "spacepackets" name = "spacepackets"
version = "0.11.1" version = "0.11.0-rc.0"
edition = "2021" edition = "2021"
rust-version = "1.65" rust-version = "1.61"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"] authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
description = "Generic implementations for various CCSDS and ECSS packet standards" description = "Generic implementations for various CCSDS and ECSS packet standards"
homepage = "https://egit.irs.uni-stuttgart.de/rust/spacepackets" homepage = "https://egit.irs.uni-stuttgart.de/rust/spacepackets"
@ -48,10 +48,6 @@ optional = true
version = "0.2" version = "0.2"
default-features = false default-features = false
[dependencies.defmt]
version = "0.3"
optional = true
[dev-dependencies] [dev-dependencies]
postcard = "1" postcard = "1"
chrono = "0.4" chrono = "0.4"
@ -63,8 +59,7 @@ serde = ["dep:serde", "chrono/serde"]
alloc = ["postcard/alloc", "chrono/alloc"] alloc = ["postcard/alloc", "chrono/alloc"]
chrono = ["dep:chrono"] chrono = ["dep:chrono"]
timelib = ["dep:time"] timelib = ["dep:time"]
defmt = ["dep:defmt"]
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true
rustdoc-args = ["--cfg", "docs_rs", "--generate-link-to-definition"] rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"]

View File

@ -29,6 +29,10 @@ Currently, this includes the following components:
`spacepackets` supports various runtime environments and is also suitable for `no_std` environments. `spacepackets` supports various runtime environments and is also suitable for `no_std` environments.
It also offers optional support for [`serde`](https://serde.rs/). This allows serializing and
deserializing them with an appropriate `serde` provider like
[`postcard`](https://github.com/jamesmunns/postcard).
## Default features ## Default features
- [`std`](https://doc.rust-lang.org/std/): Enables functionality relying on the standard library. - [`std`](https://doc.rust-lang.org/std/): Enables functionality relying on the standard library.
@ -41,8 +45,6 @@ Currently, this includes the following components:
- [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and `Deserialize` `derive`s - [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and `Deserialize` `derive`s
- [`chrono`](https://crates.io/crates/chrono): Add basic support for the `chrono` time library. - [`chrono`](https://crates.io/crates/chrono): Add basic support for the `chrono` time library.
- [`timelib`](https://crates.io/crates/time): Add basic support for the `time` time library. - [`timelib`](https://crates.io/crates/time): Add basic support for the `time` time library.
- [`defmt`](https://defmt.ferrous-systems.com/): Add support for the `defmt` by adding the
[`defmt::Format`](https://defmt.ferrous-systems.com/format) derive on many types.
# Examples # Examples

View File

@ -15,10 +15,7 @@ RUN rustup install nightly && \
rustup target add thumbv7em-none-eabihf armv7-unknown-linux-gnueabihf && \ rustup target add thumbv7em-none-eabihf armv7-unknown-linux-gnueabihf && \
rustup component add rustfmt clippy llvm-tools-preview rustup component add rustfmt clippy llvm-tools-preview
# Get grcov
RUN curl -sSL https://github.com/mozilla/grcov/releases/download/v0.8.19/grcov-x86_64-unknown-linux-gnu.tar.bz2 | tar -xj --directory /usr/local/bin RUN curl -sSL https://github.com/mozilla/grcov/releases/download/v0.8.19/grcov-x86_64-unknown-linux-gnu.tar.bz2 | tar -xj --directory /usr/local/bin
# Get nextest
RUN curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
# SSH stuff to allow deployment to doc server # SSH stuff to allow deployment to doc server
RUN adduser --uid 114 jenkins RUN adduser --uid 114 jenkins

View File

@ -31,8 +31,7 @@ pipeline {
} }
stage('Test') { stage('Test') {
steps { steps {
sh 'cargo nextest r --all-features' sh 'cargo test --all-features'
sh 'cargo test --doc'
} }
} }
stage('Check with all features') { stage('Check with all features') {

View File

@ -4,12 +4,11 @@ Checklist for new releases
# Pre-Release # Pre-Release
1. Make sure any new modules are documented sufficiently enough and check docs with 1. Make sure any new modules are documented sufficiently enough and check docs with
`cargo +nightly doc --all-features --config 'build.rustdocflags=["--cfg", "docs_rs"]' --open`. `cargo +nightly doc --all-features --config 'build.rustdocflags=["--cfg", "docsrs"]' --open`.
2. Bump version specifier in `Cargo.toml`. 2. Bump version specifier in `Cargo.toml`.
3. Update `CHANGELOG.md`: Convert `unreleased` section into version section with date and add new 3. Update `CHANGELOG.md`: Convert `unreleased` section into version section with date and add new
`unreleased` section. `unreleased` section.
4. Run `cargo test --all-features` or `cargo nextest r --all-features` together with 4. Run `cargo test --all-features`.
`cargo test --doc`.
5. Run `cargo fmt` and `cargo clippy`. Check `cargo msrv` against MSRV in `Cargo.toml`. 5. Run `cargo fmt` and `cargo clippy`. Check `cargo msrv` against MSRV in `Cargo.toml`.
6. Wait for CI/CD results for EGit and Github. These also check cross-compilation for bare-metal 6. Wait for CI/CD results for EGit and Github. These also check cross-compilation for bare-metal
targets. targets.

View File

@ -20,7 +20,6 @@ pub const MIN_LV_LEN: usize = 1;
/// this will be the lifetime of that data reference. /// this will be the lifetime of that data reference.
#[derive(Debug, Copy, Clone, Eq)] #[derive(Debug, Copy, Clone, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Lv<'data> { pub struct Lv<'data> {
data: &'data [u8], data: &'data [u8],
// If the LV was generated from a raw bytestream, this will contain the start of the // If the LV was generated from a raw bytestream, this will contain the start of the
@ -62,7 +61,6 @@ pub(crate) fn generic_len_check_deserialization(
} }
impl<'data> Lv<'data> { impl<'data> Lv<'data> {
#[inline]
pub fn new(data: &[u8]) -> Result<Lv, TlvLvError> { pub fn new(data: &[u8]) -> Result<Lv, TlvLvError> {
if data.len() > u8::MAX as usize { if data.len() > u8::MAX as usize {
return Err(TlvLvError::DataTooLarge(data.len())); return Err(TlvLvError::DataTooLarge(data.len()));
@ -74,7 +72,6 @@ impl<'data> Lv<'data> {
} }
/// Creates a LV with an empty value field. /// Creates a LV with an empty value field.
#[inline]
pub fn new_empty() -> Lv<'data> { pub fn new_empty() -> Lv<'data> {
Lv { Lv {
data: &[], data: &[],
@ -84,7 +81,6 @@ impl<'data> Lv<'data> {
/// Helper function to build a string LV. This is especially useful for the file or directory /// Helper function to build a string LV. This is especially useful for the file or directory
/// path LVs /// path LVs
#[inline]
pub fn new_from_str(str_slice: &str) -> Result<Lv, TlvLvError> { pub fn new_from_str(str_slice: &str) -> Result<Lv, TlvLvError> {
Self::new(str_slice.as_bytes()) Self::new(str_slice.as_bytes())
} }
@ -92,44 +88,37 @@ impl<'data> Lv<'data> {
/// Helper function to build a string LV. This is especially useful for the file or directory /// Helper function to build a string LV. This is especially useful for the file or directory
/// path LVs /// path LVs
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[inline]
pub fn new_from_string(string: &'data String) -> Result<Lv<'data>, TlvLvError> { pub fn new_from_string(string: &'data String) -> Result<Lv<'data>, TlvLvError> {
Self::new(string.as_bytes()) Self::new(string.as_bytes())
} }
/// Returns the length of the value part, not including the length byte. /// Returns the length of the value part, not including the length byte.
#[inline]
pub fn len_value(&self) -> usize { pub fn len_value(&self) -> usize {
self.data.len() self.data.len()
} }
/// Returns the full raw length, including the length byte. /// Returns the full raw length, including the length byte.
#[inline]
pub fn len_full(&self) -> usize { pub fn len_full(&self) -> usize {
self.len_value() + 1 self.len_value() + 1
} }
/// Checks whether the value field is empty. /// Checks whether the value field is empty.
#[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.data.len() == 0 self.data.len() == 0
} }
#[inline]
pub fn value(&self) -> &[u8] { pub fn value(&self) -> &[u8] {
self.data self.data
} }
/// If the LV was generated from a raw bytestream using [Self::from_bytes], the raw start /// If the LV was generated from a raw bytestream using [Self::from_bytes], the raw start
/// of the LV can be retrieved with this method. /// of the LV can be retrieved with this method.
#[inline]
pub fn raw_data(&self) -> Option<&[u8]> { pub fn raw_data(&self) -> Option<&[u8]> {
self.raw_data self.raw_data
} }
/// Convenience function to extract the value as a [str]. This is useful if the LV is /// Convenience function to extract the value as a [str]. This is useful if the LV is
/// known to contain a [str], for example being a file name. /// known to contain a [str], for example being a file name.
#[inline]
pub fn value_as_str(&self) -> Option<Result<&'data str, Utf8Error>> { pub fn value_as_str(&self) -> Option<Result<&'data str, Utf8Error>> {
if self.is_empty() { if self.is_empty() {
return None; return None;
@ -145,7 +134,6 @@ impl<'data> Lv<'data> {
} }
/// Reads a LV from a raw buffer. /// Reads a LV from a raw buffer.
#[inline]
pub fn from_bytes(buf: &'data [u8]) -> Result<Lv<'data>, ByteConversionError> { pub fn from_bytes(buf: &'data [u8]) -> Result<Lv<'data>, ByteConversionError> {
generic_len_check_deserialization(buf, MIN_LV_LEN)?; generic_len_check_deserialization(buf, MIN_LV_LEN)?;
Self::from_be_bytes_no_len_check(buf) Self::from_be_bytes_no_len_check(buf)
@ -162,7 +150,6 @@ impl<'data> Lv<'data> {
MIN_LV_LEN + self.data.len() MIN_LV_LEN + self.data.len()
} }
#[inline]
pub(crate) fn from_be_bytes_no_len_check( pub(crate) fn from_be_bytes_no_len_check(
buf: &'data [u8], buf: &'data [u8],
) -> Result<Lv<'data>, ByteConversionError> { ) -> Result<Lv<'data>, ByteConversionError> {

View File

@ -18,7 +18,6 @@ pub const CFDP_VERSION_2: u8 = 0b001;
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum PduType { pub enum PduType {
FileDirective = 0, FileDirective = 0,
@ -27,7 +26,6 @@ pub enum PduType {
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum Direction { pub enum Direction {
TowardsReceiver = 0, TowardsReceiver = 0,
@ -36,7 +34,6 @@ pub enum Direction {
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum TransmissionMode { pub enum TransmissionMode {
Acknowledged = 0, Acknowledged = 0,
@ -45,7 +42,6 @@ pub enum TransmissionMode {
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum CrcFlag { pub enum CrcFlag {
NoCrc = 0, NoCrc = 0,
@ -73,7 +69,6 @@ impl From<CrcFlag> for bool {
/// Always 0 and ignored for File Directive PDUs (CCSDS 727.0-B-5 P.75) /// Always 0 and ignored for File Directive PDUs (CCSDS 727.0-B-5 P.75)
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum SegmentMetadataFlag { pub enum SegmentMetadataFlag {
NotPresent = 0, NotPresent = 0,
@ -83,7 +78,6 @@ pub enum SegmentMetadataFlag {
/// Always 0 and ignored for File Directive PDUs (CCSDS 727.0-B-5 P.75) /// Always 0 and ignored for File Directive PDUs (CCSDS 727.0-B-5 P.75)
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum SegmentationControl { pub enum SegmentationControl {
NoRecordBoundaryPreservation = 0, NoRecordBoundaryPreservation = 0,
@ -92,7 +86,6 @@ pub enum SegmentationControl {
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum FaultHandlerCode { pub enum FaultHandlerCode {
NoticeOfCancellation = 0b0001, NoticeOfCancellation = 0b0001,
@ -103,7 +96,6 @@ pub enum FaultHandlerCode {
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum ConditionCode { pub enum ConditionCode {
/// This is not an error condition for which a faulty handler override can be specified /// This is not an error condition for which a faulty handler override can be specified
@ -126,7 +118,6 @@ pub enum ConditionCode {
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum LargeFileFlag { pub enum LargeFileFlag {
/// 32 bit maximum file size and FSS size /// 32 bit maximum file size and FSS size
@ -138,7 +129,6 @@ pub enum LargeFileFlag {
/// Transaction status for the ACK PDU field according to chapter 5.2.4 of the CFDP standard. /// Transaction status for the ACK PDU field according to chapter 5.2.4 of the CFDP standard.
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum TransactionStatus { pub enum TransactionStatus {
/// Transaction is not currently active and the CFDP implementation does not retain a /// Transaction is not currently active and the CFDP implementation does not retain a
@ -156,7 +146,6 @@ pub enum TransactionStatus {
/// [SANA Checksum Types registry](https://sanaregistry.org/r/checksum_identifiers/) /// [SANA Checksum Types registry](https://sanaregistry.org/r/checksum_identifiers/)
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum ChecksumType { pub enum ChecksumType {
/// Modular legacy checksum /// Modular legacy checksum
@ -178,7 +167,6 @@ pub const NULL_CHECKSUM_U32: [u8; 4] = [0; 4];
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TlvLvError { pub enum TlvLvError {
DataTooLarge(usize), DataTooLarge(usize),
ByteConversion(ByteConversionError), ByteConversion(ByteConversionError),

View File

@ -15,7 +15,6 @@ use serde::{Deserialize, Serialize};
/// For more information, refer to CFDP chapter 5.2.4. /// For more information, refer to CFDP chapter 5.2.4.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AckPdu { pub struct AckPdu {
pdu_header: PduHeader, pdu_header: PduHeader,
directive_code_of_acked_pdu: FileDirectiveType, directive_code_of_acked_pdu: FileDirectiveType,

View File

@ -15,7 +15,6 @@ use super::{CfdpPdu, WritablePduPacket};
/// For more information, refer to CFDP chapter 5.2.2. /// For more information, refer to CFDP chapter 5.2.2.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct EofPdu { pub struct EofPdu {
pdu_header: PduHeader, pdu_header: PduHeader,
condition_code: ConditionCode, condition_code: ConditionCode,

View File

@ -14,7 +14,6 @@ use super::{CfdpPdu, WritablePduPacket};
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum DeliveryCode { pub enum DeliveryCode {
Complete = 0, Complete = 0,
@ -23,7 +22,6 @@ pub enum DeliveryCode {
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum FileStatus { pub enum FileStatus {
DiscardDeliberately = 0b00, DiscardDeliberately = 0b00,
@ -36,7 +34,6 @@ pub enum FileStatus {
/// ///
/// For more information, refer to CFDP chapter 5.2.3. /// For more information, refer to CFDP chapter 5.2.3.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FinishedPduCreator<'fs_responses> { pub struct FinishedPduCreator<'fs_responses> {
pdu_header: PduHeader, pdu_header: PduHeader,
condition_code: ConditionCode, condition_code: ConditionCode,
@ -222,7 +219,6 @@ impl<'buf> Iterator for FilestoreResponseIterator<'buf> {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FinishedPduReader<'buf> { pub struct FinishedPduReader<'buf> {
pdu_header: PduHeader, pdu_header: PduHeader,
condition_code: ConditionCode, condition_code: ConditionCode,

View File

@ -15,7 +15,6 @@ use super::{CfdpPdu, WritablePduPacket};
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct MetadataGenericParams { pub struct MetadataGenericParams {
pub closure_requested: bool, pub closure_requested: bool,
pub checksum_type: ChecksumType, pub checksum_type: ChecksumType,
@ -56,7 +55,6 @@ pub fn build_metadata_opts_from_vec(
/// This abstraction exposes a specialized API for creating metadata PDUs as specified in /// This abstraction exposes a specialized API for creating metadata PDUs as specified in
/// CFDP chapter 5.2.5. /// CFDP chapter 5.2.5.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct MetadataPduCreator<'src_name, 'dest_name, 'opts> { pub struct MetadataPduCreator<'src_name, 'dest_name, 'opts> {
pdu_header: PduHeader, pdu_header: PduHeader,
metadata_params: MetadataGenericParams, metadata_params: MetadataGenericParams,
@ -243,7 +241,6 @@ impl<'opts> Iterator for OptionsIter<'opts> {
/// involved. /// involved.
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct MetadataPduReader<'buf> { pub struct MetadataPduReader<'buf> {
pdu_header: PduHeader, pdu_header: PduHeader,
metadata_params: MetadataGenericParams, metadata_params: MetadataGenericParams,

View File

@ -18,7 +18,6 @@ pub mod nak;
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum FileDirectiveType { pub enum FileDirectiveType {
EofPdu = 0x04, EofPdu = 0x04,
@ -150,14 +149,12 @@ impl Error for PduError {
} }
impl From<ByteConversionError> for PduError { impl From<ByteConversionError> for PduError {
#[inline]
fn from(value: ByteConversionError) -> Self { fn from(value: ByteConversionError) -> Self {
Self::ByteConversion(value) Self::ByteConversion(value)
} }
} }
impl From<TlvLvError> for PduError { impl From<TlvLvError> for PduError {
#[inline]
fn from(e: TlvLvError) -> Self { fn from(e: TlvLvError) -> Self {
Self::TlvLvError(e) Self::TlvLvError(e)
} }
@ -181,42 +178,33 @@ pub trait WritablePduPacket {
pub trait CfdpPdu { pub trait CfdpPdu {
fn pdu_header(&self) -> &PduHeader; fn pdu_header(&self) -> &PduHeader;
#[inline]
fn source_id(&self) -> UnsignedByteField { fn source_id(&self) -> UnsignedByteField {
self.pdu_header().common_pdu_conf().source_entity_id self.pdu_header().common_pdu_conf().source_entity_id
} }
#[inline]
fn dest_id(&self) -> UnsignedByteField { fn dest_id(&self) -> UnsignedByteField {
self.pdu_header().common_pdu_conf().dest_entity_id self.pdu_header().common_pdu_conf().dest_entity_id
} }
#[inline]
fn transaction_seq_num(&self) -> UnsignedByteField { fn transaction_seq_num(&self) -> UnsignedByteField {
self.pdu_header().common_pdu_conf().transaction_seq_num self.pdu_header().common_pdu_conf().transaction_seq_num
} }
#[inline]
fn transmission_mode(&self) -> TransmissionMode { fn transmission_mode(&self) -> TransmissionMode {
self.pdu_header().common_pdu_conf().trans_mode self.pdu_header().common_pdu_conf().trans_mode
} }
#[inline]
fn direction(&self) -> Direction { fn direction(&self) -> Direction {
self.pdu_header().common_pdu_conf().direction self.pdu_header().common_pdu_conf().direction
} }
#[inline]
fn crc_flag(&self) -> CrcFlag { fn crc_flag(&self) -> CrcFlag {
self.pdu_header().common_pdu_conf().crc_flag self.pdu_header().common_pdu_conf().crc_flag
} }
#[inline]
fn file_flag(&self) -> LargeFileFlag { fn file_flag(&self) -> LargeFileFlag {
self.pdu_header().common_pdu_conf().file_flag self.pdu_header().common_pdu_conf().file_flag
} }
#[inline]
fn pdu_type(&self) -> PduType { fn pdu_type(&self) -> PduType {
self.pdu_header().pdu_type() self.pdu_header().pdu_type()
} }
@ -232,7 +220,6 @@ pub trait CfdpPdu {
/// same. /// same.
#[derive(Debug, Copy, Clone, Eq)] #[derive(Debug, Copy, Clone, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CommonPduConfig { pub struct CommonPduConfig {
source_entity_id: UnsignedByteField, source_entity_id: UnsignedByteField,
dest_entity_id: UnsignedByteField, dest_entity_id: UnsignedByteField,
@ -245,7 +232,6 @@ pub struct CommonPduConfig {
// TODO: Builder pattern might be applicable here.. // TODO: Builder pattern might be applicable here..
impl CommonPduConfig { impl CommonPduConfig {
#[inline]
pub fn new( pub fn new(
source_id: impl Into<UnsignedByteField>, source_id: impl Into<UnsignedByteField>,
dest_id: impl Into<UnsignedByteField>, dest_id: impl Into<UnsignedByteField>,
@ -277,7 +263,6 @@ impl CommonPduConfig {
}) })
} }
#[inline]
pub fn new_with_byte_fields( pub fn new_with_byte_fields(
source_id: impl Into<UnsignedByteField>, source_id: impl Into<UnsignedByteField>,
dest_id: impl Into<UnsignedByteField>, dest_id: impl Into<UnsignedByteField>,
@ -294,12 +279,10 @@ impl CommonPduConfig {
) )
} }
#[inline]
pub fn source_id(&self) -> UnsignedByteField { pub fn source_id(&self) -> UnsignedByteField {
self.source_entity_id self.source_entity_id
} }
#[inline]
fn source_dest_id_check( fn source_dest_id_check(
source_id: impl Into<UnsignedByteField>, source_id: impl Into<UnsignedByteField>,
dest_id: impl Into<UnsignedByteField>, dest_id: impl Into<UnsignedByteField>,
@ -322,7 +305,6 @@ impl CommonPduConfig {
Ok((source_id, dest_id)) Ok((source_id, dest_id))
} }
#[inline]
pub fn set_source_and_dest_id( pub fn set_source_and_dest_id(
&mut self, &mut self,
source_id: impl Into<UnsignedByteField>, source_id: impl Into<UnsignedByteField>,
@ -334,7 +316,6 @@ impl CommonPduConfig {
Ok(()) Ok(())
} }
#[inline]
pub fn dest_id(&self) -> UnsignedByteField { pub fn dest_id(&self) -> UnsignedByteField {
self.dest_entity_id self.dest_entity_id
} }
@ -343,7 +324,6 @@ impl CommonPduConfig {
impl Default for CommonPduConfig { impl Default for CommonPduConfig {
/// The defaults for the source ID, destination ID and the transaction sequence number is the /// The defaults for the source ID, destination ID and the transaction sequence number is the
/// [UnsignedByteFieldU8] with an intitial value of 0 /// [UnsignedByteFieldU8] with an intitial value of 0
#[inline]
fn default() -> Self { fn default() -> Self {
// The new function can not fail for these input parameters. // The new function can not fail for these input parameters.
Self::new( Self::new(
@ -360,7 +340,6 @@ impl Default for CommonPduConfig {
} }
impl PartialEq for CommonPduConfig { impl PartialEq for CommonPduConfig {
#[inline]
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.source_entity_id.value() == other.source_entity_id.value() self.source_entity_id.value() == other.source_entity_id.value()
&& self.dest_entity_id.value() == other.dest_entity_id.value() && self.dest_entity_id.value() == other.dest_entity_id.value()
@ -379,7 +358,6 @@ pub const FIXED_HEADER_LEN: usize = 4;
/// For detailed information, refer to chapter 5.1 of the CFDP standard. /// For detailed information, refer to chapter 5.1 of the CFDP standard.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PduHeader { pub struct PduHeader {
pdu_type: PduType, pdu_type: PduType,
pdu_conf: CommonPduConfig, pdu_conf: CommonPduConfig,
@ -389,7 +367,6 @@ pub struct PduHeader {
} }
impl PduHeader { impl PduHeader {
#[inline]
pub fn new_for_file_data( pub fn new_for_file_data(
pdu_conf: CommonPduConfig, pdu_conf: CommonPduConfig,
pdu_datafield_len: u16, pdu_datafield_len: u16,
@ -405,7 +382,6 @@ impl PduHeader {
) )
} }
#[inline]
pub fn new_for_file_data_default(pdu_conf: CommonPduConfig, pdu_datafield_len: u16) -> Self { pub fn new_for_file_data_default(pdu_conf: CommonPduConfig, pdu_datafield_len: u16) -> Self {
Self::new_generic( Self::new_generic(
PduType::FileData, PduType::FileData,
@ -415,7 +391,6 @@ impl PduHeader {
SegmentationControl::NoRecordBoundaryPreservation, SegmentationControl::NoRecordBoundaryPreservation,
) )
} }
#[inline]
pub fn new_no_file_data(pdu_conf: CommonPduConfig, pdu_datafield_len: u16) -> Self { pub fn new_no_file_data(pdu_conf: CommonPduConfig, pdu_datafield_len: u16) -> Self {
Self::new_generic( Self::new_generic(
PduType::FileDirective, PduType::FileDirective,
@ -426,7 +401,6 @@ impl PduHeader {
) )
} }
#[inline]
pub fn new_generic( pub fn new_generic(
pdu_type: PduType, pdu_type: PduType,
pdu_conf: CommonPduConfig, pdu_conf: CommonPduConfig,
@ -444,7 +418,6 @@ impl PduHeader {
} }
/// Returns only the length of the PDU header when written to a raw buffer. /// Returns only the length of the PDU header when written to a raw buffer.
#[inline]
pub fn header_len(&self) -> usize { pub fn header_len(&self) -> usize {
FIXED_HEADER_LEN FIXED_HEADER_LEN
+ self.pdu_conf.source_entity_id.size() + self.pdu_conf.source_entity_id.size()
@ -452,14 +425,12 @@ impl PduHeader {
+ self.pdu_conf.dest_entity_id.size() + self.pdu_conf.dest_entity_id.size()
} }
#[inline]
pub fn pdu_datafield_len(&self) -> usize { pub fn pdu_datafield_len(&self) -> usize {
self.pdu_datafield_len.into() self.pdu_datafield_len.into()
} }
/// Returns the full length of the PDU when written to a raw buffer, which is the header length /// Returns the full length of the PDU when written to a raw buffer, which is the header length
/// plus the PDU datafield length. /// plus the PDU datafield length.
#[inline]
pub fn pdu_len(&self) -> usize { pub fn pdu_len(&self) -> usize {
self.header_len() + self.pdu_datafield_len as usize self.header_len() + self.pdu_datafield_len as usize
} }
@ -632,13 +603,10 @@ impl PduHeader {
current_idx, current_idx,
)) ))
} }
#[inline]
pub fn pdu_type(&self) -> PduType { pub fn pdu_type(&self) -> PduType {
self.pdu_type self.pdu_type
} }
#[inline]
pub fn common_pdu_conf(&self) -> &CommonPduConfig { pub fn common_pdu_conf(&self) -> &CommonPduConfig {
&self.pdu_conf &self.pdu_conf
} }
@ -646,8 +614,6 @@ impl PduHeader {
pub fn seg_metadata_flag(&self) -> SegmentMetadataFlag { pub fn seg_metadata_flag(&self) -> SegmentMetadataFlag {
self.seg_metadata_flag self.seg_metadata_flag
} }
#[inline]
pub fn seg_ctrl(&self) -> SegmentationControl { pub fn seg_ctrl(&self) -> SegmentationControl {
self.seg_ctrl self.seg_ctrl
} }

View File

@ -12,7 +12,6 @@ use super::{
/// Helper type to encapsulate both normal file size segment requests and large file size segment /// Helper type to encapsulate both normal file size segment requests and large file size segment
/// requests. /// requests.
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SegmentRequests<'a> { pub enum SegmentRequests<'a> {
U32Pairs(&'a [(u32, u32)]), U32Pairs(&'a [(u32, u32)]),
U64Pairs(&'a [(u64, u64)]), U64Pairs(&'a [(u64, u64)]),
@ -32,7 +31,6 @@ impl SegmentRequests<'_> {
/// It exposes a specialized API which simplifies to generate these NAK PDUs with the /// It exposes a specialized API which simplifies to generate these NAK PDUs with the
/// format according to CFDP chapter 5.2.6. /// format according to CFDP chapter 5.2.6.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct NakPduCreator<'seg_reqs> { pub struct NakPduCreator<'seg_reqs> {
pdu_header: PduHeader, pdu_header: PduHeader,
start_of_scope: u64, start_of_scope: u64,
@ -355,7 +353,6 @@ impl<T: SegReqFromBytes> SegmentRequestIter<'_, T> {
/// ///
/// The NAK format is expected to be conforming to CFDP chapter 5.2.6. /// The NAK format is expected to be conforming to CFDP chapter 5.2.6.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct NakPduReader<'seg_reqs> { pub struct NakPduReader<'seg_reqs> {
pdu_header: PduHeader, pdu_header: PduHeader,
start_of_scope: u64, start_of_scope: u64,

View File

@ -52,7 +52,6 @@ pub trait WritableTlv {
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum TlvType { pub enum TlvType {
FilestoreRequest = 0x00, FilestoreRequest = 0x00,
@ -65,7 +64,6 @@ pub enum TlvType {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TlvTypeField { pub enum TlvTypeField {
Standard(TlvType), Standard(TlvType),
Custom(u8), Custom(u8),
@ -73,7 +71,6 @@ pub enum TlvTypeField {
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum FilestoreActionCode { pub enum FilestoreActionCode {
CreateFile = 0b0000, CreateFile = 0b0000,
@ -121,7 +118,6 @@ impl From<TlvTypeField> for u8 {
/// this will be the lifetime of that data reference. /// this will be the lifetime of that data reference.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Tlv<'data> { pub struct Tlv<'data> {
tlv_type_field: TlvTypeField, tlv_type_field: TlvTypeField,
#[cfg_attr(feature = "serde", serde(borrow))] #[cfg_attr(feature = "serde", serde(borrow))]
@ -228,7 +224,6 @@ pub(crate) fn verify_tlv_type(raw_type: u8, expected_tlv_type: TlvType) -> Resul
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct EntityIdTlv { pub struct EntityIdTlv {
entity_id: UnsignedByteField, entity_id: UnsignedByteField,
} }
@ -353,7 +348,6 @@ pub fn fs_request_has_second_filename(action_code: FilestoreActionCode) -> bool
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
struct FilestoreTlvBase<'first_name, 'second_name> { struct FilestoreTlvBase<'first_name, 'second_name> {
pub action_code: FilestoreActionCode, pub action_code: FilestoreActionCode,
#[cfg_attr(feature = "serde", serde(borrow))] #[cfg_attr(feature = "serde", serde(borrow))]
@ -567,7 +561,6 @@ impl GenericTlv for FilestoreRequestTlv<'_, '_> {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FilestoreResponseTlv<'first_name, 'second_name, 'fs_msg> { pub struct FilestoreResponseTlv<'first_name, 'second_name, 'fs_msg> {
#[cfg_attr(feature = "serde", serde(borrow))] #[cfg_attr(feature = "serde", serde(borrow))]
base: FilestoreTlvBase<'first_name, 'second_name>, base: FilestoreTlvBase<'first_name, 'second_name>,

View File

@ -5,7 +5,6 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Eq, PartialEq, Copy, Clone, IntoPrimitive, TryFromPrimitive)] #[derive(Debug, Eq, PartialEq, Copy, Clone, IntoPrimitive, TryFromPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
pub enum Subservice { pub enum Subservice {
// Regular HK // Regular HK

View File

@ -1,8 +1,8 @@
//! Common definitions and helpers required to create PUS TMTC packets according to //! Common definitions and helpers required to create PUS TMTC packets according to
//! [ECSS-E-ST-70-41C](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/) //! [ECSS-E-ST-70-41C](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/)
//! //!
//! You can find the PUS telecommand types in the [tc] module and the the PUS telemetry //! You can find the PUS telecommand definitions in the [tc] module and ithe PUS telemetry definitions
//! types inside the [tm] module. //! inside the [tm] module.
use crate::{ByteConversionError, CcsdsPacket, CRC_CCITT_FALSE}; use crate::{ByteConversionError, CcsdsPacket, CRC_CCITT_FALSE};
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use alloc::vec::Vec; use alloc::vec::Vec;
@ -22,6 +22,7 @@ pub mod tm;
pub mod verification; pub mod verification;
pub type CrcType = u16; pub type CrcType = u16;
pub const CCSDS_HEADER_LEN: usize = size_of::<crate::zc::SpHeader>();
#[derive(Debug, Copy, Clone, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] #[derive(Debug, Copy, Clone, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -73,7 +74,6 @@ pub enum PusServiceId {
/// All PUS versions. Only PUS C is supported by this library. /// All PUS versions. Only PUS C is supported by this library.
#[derive(PartialEq, Eq, Copy, Clone, Debug)] #[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub enum PusVersion { pub enum PusVersion {
EsaPus = 0, EsaPus = 0,
@ -150,7 +150,6 @@ pub enum PfcReal {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PusError { pub enum PusError {
VersionNotSupported(PusVersion), VersionNotSupported(PusVersion),
ChecksumFailure(u16), ChecksumFailure(u16),
@ -245,7 +244,7 @@ pub(crate) fn verify_crc16_ccitt_false_from_raw_to_pus_error(
crc16: u16, crc16: u16,
) -> Result<(), PusError> { ) -> Result<(), PusError> {
verify_crc16_ccitt_false_from_raw(raw_data) verify_crc16_ccitt_false_from_raw(raw_data)
.then_some(()) .then(|| ())
.ok_or(PusError::ChecksumFailure(crc16)) .ok_or(PusError::ChecksumFailure(crc16))
} }
@ -261,13 +260,9 @@ pub(crate) fn verify_crc16_ccitt_false_from_raw(raw_data: &[u8]) -> bool {
macro_rules! ccsds_impl { macro_rules! ccsds_impl {
() => { () => {
delegate!(to self.sp_header { delegate!(to self.sp_header {
#[inline]
fn ccsds_version(&self) -> u8; fn ccsds_version(&self) -> u8;
#[inline]
fn packet_id(&self) -> crate::PacketId; fn packet_id(&self) -> crate::PacketId;
#[inline]
fn psc(&self) -> crate::PacketSequenceCtrl; fn psc(&self) -> crate::PacketSequenceCtrl;
#[inline]
fn data_len(&self) -> u16; fn data_len(&self) -> u16;
}); });
} }
@ -276,11 +271,8 @@ macro_rules! ccsds_impl {
macro_rules! sp_header_impls { macro_rules! sp_header_impls {
() => { () => {
delegate!(to self.sp_header { delegate!(to self.sp_header {
#[inline]
pub fn set_apid(&mut self, apid: u16) -> bool; pub fn set_apid(&mut self, apid: u16) -> bool;
#[inline]
pub fn set_seq_count(&mut self, seq_count: u16) -> bool; pub fn set_seq_count(&mut self, seq_count: u16) -> bool;
#[inline]
pub fn set_seq_flags(&mut self, seq_flag: SequenceFlags); pub fn set_seq_flags(&mut self, seq_flag: SequenceFlags);
}); });
} }

View File

@ -54,7 +54,6 @@ pub enum SchedStatus {
} }
impl From<bool> for SchedStatus { impl From<bool> for SchedStatus {
#[inline]
fn from(value: bool) -> Self { fn from(value: bool) -> Self {
if value { if value {
SchedStatus::Enabled SchedStatus::Enabled

View File

@ -9,11 +9,9 @@
//! use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader}; //! use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader};
//! //!
//! // Create a ping telecommand with no user application data //! // Create a ping telecommand with no user application data
//! let pus_tc = PusTcCreator::new_no_app_data( //! let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap();
//! SpHeader::new_from_apid(0x02), //! let tc_header = PusTcSecondaryHeader::new_simple(17, 1);
//! PusTcSecondaryHeader::new_simple(17, 1), //! let pus_tc = PusTcCreator::new_no_app_data(&mut sph, tc_header, true);
//! true
//! );
//! println!("{:?}", pus_tc); //! println!("{:?}", pus_tc);
//! assert_eq!(pus_tc.service(), 17); //! assert_eq!(pus_tc.service(), 17);
//! assert_eq!(pus_tc.subservice(), 1); //! assert_eq!(pus_tc.subservice(), 1);
@ -61,7 +59,6 @@ pub trait IsPusTelecommand {}
#[derive(Debug, Eq, PartialEq, Copy, Clone, IntoPrimitive, TryFromPrimitive)] #[derive(Debug, Eq, PartialEq, Copy, Clone, IntoPrimitive, TryFromPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)] #[repr(u8)]
enum AckOpts { enum AckOpts {
Acceptance = 0b1000, Acceptance = 0b1000,
@ -113,27 +110,22 @@ pub mod zc {
} }
impl GenericPusTcSecondaryHeader for PusTcSecondaryHeader { impl GenericPusTcSecondaryHeader for PusTcSecondaryHeader {
#[inline]
fn pus_version(&self) -> PusVersion { fn pus_version(&self) -> PusVersion {
PusVersion::try_from(self.version_ack >> 4 & 0b1111).unwrap_or(PusVersion::Invalid) PusVersion::try_from(self.version_ack >> 4 & 0b1111).unwrap_or(PusVersion::Invalid)
} }
#[inline]
fn ack_flags(&self) -> u8 { fn ack_flags(&self) -> u8 {
self.version_ack & 0b1111 self.version_ack & 0b1111
} }
#[inline]
fn service(&self) -> u8 { fn service(&self) -> u8 {
self.service self.service
} }
#[inline]
fn subservice(&self) -> u8 { fn subservice(&self) -> u8 {
self.subservice self.subservice
} }
#[inline]
fn source_id(&self) -> u16 { fn source_id(&self) -> u16 {
self.source_id.get() self.source_id.get()
} }
@ -152,7 +144,6 @@ pub mod zc {
#[derive(PartialEq, Eq, Copy, Clone, Debug)] #[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PusTcSecondaryHeader { pub struct PusTcSecondaryHeader {
pub service: u8, pub service: u8,
pub subservice: u8, pub subservice: u8,
@ -162,27 +153,22 @@ pub struct PusTcSecondaryHeader {
} }
impl GenericPusTcSecondaryHeader for PusTcSecondaryHeader { impl GenericPusTcSecondaryHeader for PusTcSecondaryHeader {
#[inline]
fn pus_version(&self) -> PusVersion { fn pus_version(&self) -> PusVersion {
self.version self.version
} }
#[inline]
fn ack_flags(&self) -> u8 { fn ack_flags(&self) -> u8 {
self.ack self.ack
} }
#[inline]
fn service(&self) -> u8 { fn service(&self) -> u8 {
self.service self.service
} }
#[inline]
fn subservice(&self) -> u8 { fn subservice(&self) -> u8 {
self.subservice self.subservice
} }
#[inline]
fn source_id(&self) -> u16 { fn source_id(&self) -> u16 {
self.source_id self.source_id
} }
@ -203,7 +189,6 @@ impl TryFrom<zc::PusTcSecondaryHeader> for PusTcSecondaryHeader {
} }
impl PusTcSecondaryHeader { impl PusTcSecondaryHeader {
#[inline]
pub fn new_simple(service: u8, subservice: u8) -> Self { pub fn new_simple(service: u8, subservice: u8) -> Self {
PusTcSecondaryHeader { PusTcSecondaryHeader {
service, service,
@ -214,7 +199,6 @@ impl PusTcSecondaryHeader {
} }
} }
#[inline]
pub fn new(service: u8, subservice: u8, ack: u8, source_id: u16) -> Self { pub fn new(service: u8, subservice: u8, ack: u8, source_id: u16) -> Self {
PusTcSecondaryHeader { PusTcSecondaryHeader {
service, service,
@ -236,37 +220,35 @@ impl PusTcSecondaryHeader {
/// There is no spare bytes support yet. /// There is no spare bytes support yet.
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PusTcCreator<'raw_data> {
pub struct PusTcCreator<'app_data> {
sp_header: SpHeader, sp_header: SpHeader,
pub sec_header: PusTcSecondaryHeader, pub sec_header: PusTcSecondaryHeader,
app_data: &'app_data [u8], app_data: &'raw_data [u8],
} }
impl<'app_data> PusTcCreator<'app_data> { impl<'raw_data> PusTcCreator<'raw_data> {
/// Generates a new struct instance. /// Generates a new struct instance.
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `sp_header` - Space packet header information. The correct packet type and the secondary /// * `sp_header` - Space packet header information. The correct packet type will be set
/// header flag are set correctly by the constructor. /// automatically
/// * `sec_header` - Information contained in the data field header, including the service /// * `sec_header` - Information contained in the data field header, including the service
/// and subservice type /// and subservice type
/// * `app_data` - Custom application data /// * `app_data` - Custom application data
/// * `set_ccsds_len` - Can be used to automatically update the CCSDS space packet data length /// * `set_ccsds_len` - Can be used to automatically update the CCSDS space packet data length
/// field. If this is not set to true, [Self::update_ccsds_data_len] can be called to set /// field. If this is not set to true, [PusTc::update_ccsds_data_len] can be called to set
/// the correct value to this field manually /// the correct value to this field manually
#[inline]
pub fn new( pub fn new(
mut sp_header: SpHeader, sp_header: &mut SpHeader,
sec_header: PusTcSecondaryHeader, sec_header: PusTcSecondaryHeader,
app_data: &'app_data [u8], app_data: &'raw_data [u8],
set_ccsds_len: bool, set_ccsds_len: bool,
) -> Self { ) -> Self {
sp_header.set_packet_type(PacketType::Tc); sp_header.set_packet_type(PacketType::Tc);
sp_header.set_sec_header_flag(); sp_header.set_sec_header_flag();
let mut pus_tc = Self { let mut pus_tc = Self {
sp_header, sp_header: *sp_header,
app_data, app_data,
sec_header, sec_header,
}; };
@ -276,44 +258,35 @@ impl<'app_data> PusTcCreator<'app_data> {
pus_tc pus_tc
} }
/// Simplified version of the [Self::new] function which allows to only specify service /// Simplified version of the [PusTcCreator::new] function which allows to only specify service
/// and subservice instead of the full PUS TC secondary header. /// and subservice instead of the full PUS TC secondary header.
#[inline]
pub fn new_simple( pub fn new_simple(
sph: SpHeader, sph: &mut SpHeader,
service: u8, service: u8,
subservice: u8, subservice: u8,
app_data: &'app_data [u8], app_data: Option<&'raw_data [u8]>,
set_ccsds_len: bool, set_ccsds_len: bool,
) -> Self { ) -> Self {
Self::new( Self::new(
sph, sph,
PusTcSecondaryHeader::new(service, subservice, ACK_ALL, 0), PusTcSecondaryHeader::new(service, subservice, ACK_ALL, 0),
app_data, app_data.unwrap_or(&[]),
set_ccsds_len, set_ccsds_len,
) )
} }
#[inline]
pub fn new_no_app_data( pub fn new_no_app_data(
sp_header: SpHeader, sp_header: &mut SpHeader,
sec_header: PusTcSecondaryHeader, sec_header: PusTcSecondaryHeader,
set_ccsds_len: bool, set_ccsds_len: bool,
) -> Self { ) -> Self {
Self::new(sp_header, sec_header, &[], set_ccsds_len) Self::new(sp_header, sec_header, &[], set_ccsds_len)
} }
#[inline]
pub fn sp_header(&self) -> &SpHeader { pub fn sp_header(&self) -> &SpHeader {
&self.sp_header &self.sp_header
} }
#[inline]
pub fn sp_header_mut(&mut self) -> &mut SpHeader {
&mut self.sp_header
}
#[inline]
pub fn set_ack_field(&mut self, ack: u8) -> bool { pub fn set_ack_field(&mut self, ack: u8) -> bool {
if ack > 0b1111 { if ack > 0b1111 {
return false; return false;
@ -322,7 +295,6 @@ impl<'app_data> PusTcCreator<'app_data> {
true true
} }
#[inline]
pub fn set_source_id(&mut self, source_id: u16) { pub fn set_source_id(&mut self, source_id: u16) {
self.sec_header.source_id = source_id; self.sec_header.source_id = source_id;
} }
@ -330,18 +302,18 @@ impl<'app_data> PusTcCreator<'app_data> {
sp_header_impls!(); sp_header_impls!();
/// Calculate the CCSDS space packet data length field and sets it /// Calculate the CCSDS space packet data length field and sets it
/// This is called automatically if the `set_ccsds_len` argument in the [Self::new] call was /// This is called automatically if the `set_ccsds_len` argument in the [PusTc::new] call was
/// used. /// used.
/// If this was not done or the application data is set or changed after construction, /// If this was not done or the application data is set or changed after construction,
/// this function needs to be called to ensure that the data length field of the CCSDS header /// this function needs to be called to ensure that the data length field of the CCSDS header
/// is set correctly. /// is set correctly.
#[inline]
pub fn update_ccsds_data_len(&mut self) { pub fn update_ccsds_data_len(&mut self) {
self.sp_header.data_len = self.sp_header.data_len =
self.len_written() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1; self.len_written() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
} }
/// This function calculates and returns the CRC16 for the current packet. /// This function should be called before the TC packet is serialized if
/// [PusTc::calc_crc_on_serialization] is set to False. It will calculate and cache the CRC16.
pub fn calc_own_crc16(&self) -> u16 { pub fn calc_own_crc16(&self) -> u16 {
let mut digest = CRC_CCITT_FALSE.digest(); let mut digest = CRC_CCITT_FALSE.digest();
let sph_zc = crate::zc::SpHeader::from(self.sp_header); let sph_zc = crate::zc::SpHeader::from(self.sp_header);
@ -371,7 +343,6 @@ impl<'app_data> PusTcCreator<'app_data> {
} }
impl WritablePusPacket for PusTcCreator<'_> { impl WritablePusPacket for PusTcCreator<'_> {
#[inline]
fn len_written(&self) -> usize { fn len_written(&self) -> usize {
PUS_TC_MIN_LEN_WITHOUT_APP_DATA + self.app_data.len() PUS_TC_MIN_LEN_WITHOUT_APP_DATA + self.app_data.len()
} }
@ -412,20 +383,15 @@ impl CcsdsPacket for PusTcCreator<'_> {
impl PusPacket for PusTcCreator<'_> { impl PusPacket for PusTcCreator<'_> {
delegate!(to self.sec_header { delegate!(to self.sec_header {
#[inline]
fn pus_version(&self) -> PusVersion; fn pus_version(&self) -> PusVersion;
#[inline]
fn service(&self) -> u8; fn service(&self) -> u8;
#[inline]
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
}); });
#[inline]
fn user_data(&self) -> &[u8] { fn user_data(&self) -> &[u8] {
self.app_data self.app_data
} }
#[inline]
fn crc16(&self) -> Option<u16> { fn crc16(&self) -> Option<u16> {
Some(self.calc_own_crc16()) Some(self.calc_own_crc16())
} }
@ -433,15 +399,10 @@ impl PusPacket for PusTcCreator<'_> {
impl GenericPusTcSecondaryHeader for PusTcCreator<'_> { impl GenericPusTcSecondaryHeader for PusTcCreator<'_> {
delegate!(to self.sec_header { delegate!(to self.sec_header {
#[inline]
fn pus_version(&self) -> PusVersion; fn pus_version(&self) -> PusVersion;
#[inline]
fn service(&self) -> u8; fn service(&self) -> u8;
#[inline]
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
#[inline]
fn source_id(&self) -> u16; fn source_id(&self) -> u16;
#[inline]
fn ack_flags(&self) -> u8; fn ack_flags(&self) -> u8;
}); });
} }
@ -461,7 +422,6 @@ impl IsPusTelecommand for PusTcCreator<'_> {}
/// * `'raw_data` - Lifetime of the provided raw slice. /// * `'raw_data` - Lifetime of the provided raw slice.
#[derive(Eq, Copy, Clone, Debug)] #[derive(Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PusTcReader<'raw_data> { pub struct PusTcReader<'raw_data> {
#[cfg_attr(feature = "serde", serde(skip))] #[cfg_attr(feature = "serde", serde(skip))]
raw_data: &'raw_data [u8], raw_data: &'raw_data [u8],
@ -519,29 +479,24 @@ impl<'raw_data> PusTcReader<'raw_data> {
Ok((pus_tc, total_len)) Ok((pus_tc, total_len))
} }
#[inline]
pub fn app_data(&self) -> &[u8] { pub fn app_data(&self) -> &[u8] {
self.user_data() self.user_data()
} }
#[inline]
pub fn raw_data(&self) -> &[u8] { pub fn raw_data(&self) -> &[u8] {
self.raw_data self.raw_data
} }
#[inline]
pub fn len_packed(&self) -> usize { pub fn len_packed(&self) -> usize {
self.sp_header.total_len() self.sp_header.total_len()
} }
#[inline]
pub fn sp_header(&self) -> &SpHeader { pub fn sp_header(&self) -> &SpHeader {
&self.sp_header &self.sp_header
} }
} }
impl PartialEq for PusTcReader<'_> { impl PartialEq for PusTcReader<'_> {
#[inline]
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.raw_data == other.raw_data self.raw_data == other.raw_data
} }
@ -553,20 +508,15 @@ impl CcsdsPacket for PusTcReader<'_> {
impl PusPacket for PusTcReader<'_> { impl PusPacket for PusTcReader<'_> {
delegate!(to self.sec_header { delegate!(to self.sec_header {
#[inline]
fn pus_version(&self) -> PusVersion; fn pus_version(&self) -> PusVersion;
#[inline]
fn service(&self) -> u8; fn service(&self) -> u8;
#[inline]
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
}); });
#[inline]
fn user_data(&self) -> &[u8] { fn user_data(&self) -> &[u8] {
self.app_data self.app_data
} }
#[inline]
fn crc16(&self) -> Option<u16> { fn crc16(&self) -> Option<u16> {
Some(self.crc16) Some(self.crc16)
} }
@ -574,15 +524,10 @@ impl PusPacket for PusTcReader<'_> {
impl GenericPusTcSecondaryHeader for PusTcReader<'_> { impl GenericPusTcSecondaryHeader for PusTcReader<'_> {
delegate!(to self.sec_header { delegate!(to self.sec_header {
#[inline]
fn pus_version(&self) -> PusVersion; fn pus_version(&self) -> PusVersion;
#[inline]
fn service(&self) -> u8; fn service(&self) -> u8;
#[inline]
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
#[inline]
fn source_id(&self) -> u16; fn source_id(&self) -> u16;
#[inline]
fn ack_flags(&self) -> u8; fn ack_flags(&self) -> u8;
}); });
} }
@ -620,19 +565,19 @@ mod tests {
use postcard::{from_bytes, to_allocvec}; use postcard::{from_bytes, to_allocvec};
fn base_ping_tc_full_ctor() -> PusTcCreator<'static> { fn base_ping_tc_full_ctor() -> PusTcCreator<'static> {
let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap();
let tc_header = PusTcSecondaryHeader::new_simple(17, 1); let tc_header = PusTcSecondaryHeader::new_simple(17, 1);
PusTcCreator::new_no_app_data(sph, tc_header, true) PusTcCreator::new_no_app_data(&mut sph, tc_header, true)
} }
fn base_ping_tc_simple_ctor() -> PusTcCreator<'static> { fn base_ping_tc_simple_ctor() -> PusTcCreator<'static> {
let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap();
PusTcCreator::new_simple(sph, 17, 1, &[], true) PusTcCreator::new_simple(&mut sph, 17, 1, None, true)
} }
fn base_ping_tc_simple_ctor_with_app_data(app_data: &'static [u8]) -> PusTcCreator<'static> { fn base_ping_tc_simple_ctor_with_app_data(app_data: &'static [u8]) -> PusTcCreator<'static> {
let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap();
PusTcCreator::new_simple(sph, 17, 1, app_data, true) PusTcCreator::new_simple(&mut sph, 17, 1, Some(app_data), true)
} }
#[test] #[test]
@ -688,8 +633,8 @@ mod tests {
#[test] #[test]
fn test_update_func() { fn test_update_func() {
let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap();
let mut tc = PusTcCreator::new_simple(sph, 17, 1, &[], false); let mut tc = PusTcCreator::new_simple(&mut sph, 17, 1, None, false);
assert_eq!(tc.data_len(), 0); assert_eq!(tc.data_len(), 0);
tc.update_ccsds_data_len(); tc.update_ccsds_data_len();
assert_eq!(tc.data_len(), 6); assert_eq!(tc.data_len(), 6);
@ -861,8 +806,7 @@ mod tests {
if !has_user_data { if !has_user_data {
assert!(tc.user_data().is_empty()); assert!(tc.user_data().is_empty());
} }
let mut comp_header = let mut comp_header = SpHeader::tc_unseg(0x02, 0x34, exp_full_len as u16 - 7).unwrap();
SpHeader::new_for_unseg_tc_checked(0x02, 0x34, exp_full_len as u16 - 7).unwrap();
comp_header.set_sec_header_flag(); comp_header.set_sec_header_flag();
assert_eq!(*tc.sp_header(), comp_header); assert_eq!(*tc.sp_header(), comp_header);
} }
@ -873,8 +817,7 @@ mod tests {
assert!(tc.user_data().is_empty()); assert!(tc.user_data().is_empty());
} }
assert_eq!(tc.len_packed(), exp_full_len); assert_eq!(tc.len_packed(), exp_full_len);
let mut comp_header = let mut comp_header = SpHeader::tc_unseg(0x02, 0x34, exp_full_len as u16 - 7).unwrap();
SpHeader::new_for_unseg_tc_checked(0x02, 0x34, exp_full_len as u16 - 7).unwrap();
comp_header.set_sec_header_flag(); comp_header.set_sec_header_flag();
assert_eq!(*tc.sp_header(), comp_header); assert_eq!(*tc.sp_header(), comp_header);
} }

View File

@ -1,47 +1,5 @@
//! This module contains all components required to create a ECSS PUS C telemetry packets according //! This module contains all components required to create a ECSS PUS C telemetry packets according
//! to [ECSS-E-ST-70-41C](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/). //! to [ECSS-E-ST-70-41C](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/).
//!
//! # Examples
//!
//! ```rust
//! use spacepackets::time::TimeWriter;
//! use spacepackets::time::cds::CdsTime;
//! use spacepackets::{CcsdsPacket, SpHeader};
//! use spacepackets::ecss::{PusPacket, WritablePusPacket};
//! use spacepackets::ecss::tm::{PusTmCreator, PusTmReader, PusTmSecondaryHeader};
//!
//! let mut time_buf: [u8; 7] = [0; 7];
//! let time_now = CdsTime::now_with_u16_days().expect("creating CDS timestamp failed");
//! // This can definitely hold the timestamp, so it is okay to unwrap.
//! time_now.write_to_bytes(&mut time_buf).unwrap();
//!
//! // Create a ping telemetry with no user source data
//! let ping_tm = PusTmCreator::new_no_source_data(
//! SpHeader::new_from_apid(0x02),
//! PusTmSecondaryHeader::new_simple(17, 2, &time_buf),
//! true
//! );
//! println!("{:?}", ping_tm);
//! assert_eq!(ping_tm.service(), 17);
//! assert_eq!(ping_tm.subservice(), 2);
//! assert_eq!(ping_tm.apid(), 0x02);
//!
//! // Serialize TM into a raw buffer
//! let mut test_buf: [u8; 32] = [0; 32];
//! let written_size = ping_tm
//! .write_to_bytes(test_buf.as_mut_slice())
//! .expect("Error writing TC to buffer");
//! assert_eq!(written_size, 22);
//! println!("{:?}", &test_buf[0..written_size]);
//!
//! // Deserialize from the raw byte representation
//! let (ping_tm_reader, read_size) = PusTmReader::new(&test_buf, 7).expect("Deserialization failed");
//! assert_eq!(written_size, read_size);
//! assert_eq!(ping_tm_reader.service(), 17);
//! assert_eq!(ping_tm_reader.subservice(), 2);
//! assert_eq!(ping_tm_reader.apid(), 0x02);
//! assert_eq!(ping_tm_reader.timestamp(), &time_buf);
//! ```
use crate::ecss::{ use crate::ecss::{
calc_pus_crc16, ccsds_impl, crc_from_raw_data, sp_header_impls, user_data_from_raw, calc_pus_crc16, ccsds_impl, crc_from_raw_data, sp_header_impls, user_data_from_raw,
verify_crc16_ccitt_false_from_raw_to_pus_error, CrcType, PusError, PusPacket, PusVersion, verify_crc16_ccitt_false_from_raw_to_pus_error, CrcType, PusError, PusPacket, PusVersion,
@ -128,33 +86,27 @@ pub mod zc {
} }
impl GenericPusTmSecondaryHeader for PusTmSecHeaderWithoutTimestamp { impl GenericPusTmSecondaryHeader for PusTmSecHeaderWithoutTimestamp {
#[inline]
fn pus_version(&self) -> PusVersion { fn pus_version(&self) -> PusVersion {
PusVersion::try_from(self.pus_version_and_sc_time_ref_status >> 4 & 0b1111) PusVersion::try_from(self.pus_version_and_sc_time_ref_status >> 4 & 0b1111)
.unwrap_or(PusVersion::Invalid) .unwrap_or(PusVersion::Invalid)
} }
#[inline]
fn sc_time_ref_status(&self) -> u8 { fn sc_time_ref_status(&self) -> u8 {
self.pus_version_and_sc_time_ref_status & 0b1111 self.pus_version_and_sc_time_ref_status & 0b1111
} }
#[inline]
fn service(&self) -> u8 { fn service(&self) -> u8 {
self.service self.service
} }
#[inline]
fn subservice(&self) -> u8 { fn subservice(&self) -> u8 {
self.subservice self.subservice
} }
#[inline]
fn msg_counter(&self) -> u16 { fn msg_counter(&self) -> u16 {
self.msg_counter.get() self.msg_counter.get()
} }
#[inline]
fn dest_id(&self) -> u16 { fn dest_id(&self) -> u16 {
self.dest_id.get() self.dest_id.get()
} }
@ -163,7 +115,6 @@ pub mod zc {
#[derive(PartialEq, Eq, Copy, Clone, Debug)] #[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PusTmSecondaryHeader<'stamp> { pub struct PusTmSecondaryHeader<'stamp> {
pus_version: PusVersion, pus_version: PusVersion,
pub sc_time_ref_status: u8, pub sc_time_ref_status: u8,
@ -175,24 +126,21 @@ pub struct PusTmSecondaryHeader<'stamp> {
} }
impl<'stamp> PusTmSecondaryHeader<'stamp> { impl<'stamp> PusTmSecondaryHeader<'stamp> {
#[inline]
pub fn new_simple(service: u8, subservice: u8, timestamp: &'stamp [u8]) -> Self { pub fn new_simple(service: u8, subservice: u8, timestamp: &'stamp [u8]) -> Self {
Self::new(service, subservice, 0, 0, timestamp) Self::new(service, subservice, 0, 0, Some(timestamp))
} }
/// Like [Self::new_simple] but without a timestamp. /// Like [Self::new_simple] but without a timestamp.
#[inline]
pub fn new_simple_no_timestamp(service: u8, subservice: u8) -> Self { pub fn new_simple_no_timestamp(service: u8, subservice: u8) -> Self {
Self::new(service, subservice, 0, 0, &[]) Self::new(service, subservice, 0, 0, None)
} }
#[inline]
pub fn new( pub fn new(
service: u8, service: u8,
subservice: u8, subservice: u8,
msg_counter: u16, msg_counter: u16,
dest_id: u16, dest_id: u16,
timestamp: &'stamp [u8], timestamp: Option<&'stamp [u8]>,
) -> Self { ) -> Self {
PusTmSecondaryHeader { PusTmSecondaryHeader {
pus_version: PusVersion::PusC, pus_version: PusVersion::PusC,
@ -201,38 +149,32 @@ impl<'stamp> PusTmSecondaryHeader<'stamp> {
subservice, subservice,
msg_counter, msg_counter,
dest_id, dest_id,
timestamp, timestamp: timestamp.unwrap_or(&[]),
} }
} }
} }
impl GenericPusTmSecondaryHeader for PusTmSecondaryHeader<'_> { impl GenericPusTmSecondaryHeader for PusTmSecondaryHeader<'_> {
#[inline]
fn pus_version(&self) -> PusVersion { fn pus_version(&self) -> PusVersion {
self.pus_version self.pus_version
} }
#[inline]
fn sc_time_ref_status(&self) -> u8 { fn sc_time_ref_status(&self) -> u8 {
self.sc_time_ref_status self.sc_time_ref_status
} }
#[inline]
fn service(&self) -> u8 { fn service(&self) -> u8 {
self.service self.service
} }
#[inline]
fn subservice(&self) -> u8 { fn subservice(&self) -> u8 {
self.subservice self.subservice
} }
#[inline]
fn msg_counter(&self) -> u16 { fn msg_counter(&self) -> u16 {
self.msg_counter self.msg_counter
} }
#[inline]
fn dest_id(&self) -> u16 { fn dest_id(&self) -> u16 {
self.dest_id self.dest_id
} }
@ -241,7 +183,6 @@ impl GenericPusTmSecondaryHeader for PusTmSecondaryHeader<'_> {
impl<'slice> TryFrom<zc::PusTmSecHeader<'slice>> for PusTmSecondaryHeader<'slice> { impl<'slice> TryFrom<zc::PusTmSecHeader<'slice>> for PusTmSecondaryHeader<'slice> {
type Error = (); type Error = ();
#[inline]
fn try_from(sec_header: zc::PusTmSecHeader<'slice>) -> Result<Self, Self::Error> { fn try_from(sec_header: zc::PusTmSecHeader<'slice>) -> Result<Self, Self::Error> {
Ok(PusTmSecondaryHeader { Ok(PusTmSecondaryHeader {
pus_version: sec_header.zc_header.pus_version(), pus_version: sec_header.zc_header.pus_version(),
@ -266,45 +207,42 @@ impl<'slice> TryFrom<zc::PusTmSecHeader<'slice>> for PusTmSecondaryHeader<'slice
/// ///
/// # Lifetimes /// # Lifetimes
/// ///
/// * `'time` - This is the lifetime of the user provided timestamp. /// * `'raw_data` - This is the lifetime of the user provided time stamp and source data.
/// * `'src_data` - This is the lifetime of the user provided source data.
#[derive(Eq, Debug, Copy, Clone)] #[derive(Eq, Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PusTmCreator<'time, 'raw_data> {
pub struct PusTmCreator<'time, 'src_data> {
pub sp_header: SpHeader, pub sp_header: SpHeader,
#[cfg_attr(feature = "serde", serde(borrow))] #[cfg_attr(feature="serde", serde(borrow))]
pub sec_header: PusTmSecondaryHeader<'time>, pub sec_header: PusTmSecondaryHeader<'time>,
source_data: &'src_data [u8], source_data: &'raw_data [u8],
/// If this is set to false, a manual call to [Self::calc_own_crc16] or /// If this is set to false, a manual call to [PusTm::calc_own_crc16] or
/// [Self::update_packet_fields] is necessary for the serialized or cached CRC16 to be valid. /// [PusTm::update_packet_fields] is necessary for the serialized or cached CRC16 to be valid.
pub calc_crc_on_serialization: bool, pub calc_crc_on_serialization: bool,
} }
impl<'time, 'src_data> PusTmCreator<'time, 'src_data> { impl<'time, 'raw_data> PusTmCreator<'time, 'raw_data> {
/// Generates a new struct instance. /// Generates a new struct instance.
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `sp_header` - Space packet header information. The correct packet type and the secondary /// * `sp_header` - Space packet header information. The correct packet type will be set
/// header flag are set correctly by the constructor. /// automatically
/// * `sec_header` - Information contained in the secondary header, including the service /// * `sec_header` - Information contained in the secondary header, including the service
/// and subservice type /// and subservice type
/// * `source_data` - Custom application data /// * `source_data` - Custom application data
/// * `set_ccsds_len` - Can be used to automatically update the CCSDS space packet data length /// * `set_ccsds_len` - Can be used to automatically update the CCSDS space packet data length
/// field. If this is not set to true, [Self::update_ccsds_data_len] can be called to set /// field. If this is not set to true, [PusTm::update_ccsds_data_len] can be called to set
/// the correct value to this field manually /// the correct value to this field manually
#[inline]
pub fn new( pub fn new(
mut sp_header: SpHeader, sp_header: &mut SpHeader,
sec_header: PusTmSecondaryHeader<'time>, sec_header: PusTmSecondaryHeader<'time>,
source_data: &'src_data [u8], source_data: &'raw_data [u8],
set_ccsds_len: bool, set_ccsds_len: bool,
) -> Self { ) -> Self {
sp_header.set_packet_type(PacketType::Tm); sp_header.set_packet_type(PacketType::Tm);
sp_header.set_sec_header_flag(); sp_header.set_sec_header_flag();
let mut pus_tm = Self { let mut pus_tm = Self {
sp_header, sp_header: *sp_header,
source_data, source_data,
sec_header, sec_header,
calc_crc_on_serialization: true, calc_crc_on_serialization: true,
@ -315,71 +253,68 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
pus_tm pus_tm
} }
#[inline]
pub fn new_simple( pub fn new_simple(
sp_header: SpHeader, sp_header: &mut SpHeader,
service: u8, service: u8,
subservice: u8, subservice: u8,
time_provider: &impl TimeWriter, time_provider: &impl TimeWriter,
stamp_buf: &'time mut [u8], stamp_buf: &'time mut [u8],
source_data: &'src_data [u8], source_data: Option<&'raw_data [u8]>,
set_ccsds_len: bool, set_ccsds_len: bool,
) -> Result<Self, TimestampError> { ) -> Result<Self, TimestampError> {
let stamp_size = time_provider.write_to_bytes(stamp_buf)?; let stamp_size = time_provider.write_to_bytes(stamp_buf)?;
let sec_header = let sec_header =
PusTmSecondaryHeader::new_simple(service, subservice, &stamp_buf[0..stamp_size]); PusTmSecondaryHeader::new_simple(service, subservice, &stamp_buf[0..stamp_size]);
Ok(Self::new(sp_header, sec_header, source_data, set_ccsds_len)) Ok(Self::new(
sp_header,
sec_header,
source_data.unwrap_or(&[]),
set_ccsds_len,
))
} }
#[inline]
pub fn new_no_source_data( pub fn new_no_source_data(
sp_header: SpHeader, sp_header: &mut SpHeader,
sec_header: PusTmSecondaryHeader<'time>, sec_header: PusTmSecondaryHeader<'time>,
set_ccsds_len: bool, set_ccsds_len: bool,
) -> Self { ) -> Self {
Self::new(sp_header, sec_header, &[], set_ccsds_len) Self::new(sp_header, sec_header, &[], set_ccsds_len)
} }
#[inline]
pub fn timestamp(&self) -> &[u8] { pub fn timestamp(&self) -> &[u8] {
self.sec_header.timestamp self.sec_header.timestamp
} }
#[inline]
pub fn source_data(&self) -> &[u8] { pub fn source_data(&self) -> &[u8] {
self.source_data self.source_data
} }
#[inline]
pub fn set_dest_id(&mut self, dest_id: u16) { pub fn set_dest_id(&mut self, dest_id: u16) {
self.sec_header.dest_id = dest_id; self.sec_header.dest_id = dest_id;
} }
#[inline]
pub fn set_msg_counter(&mut self, msg_counter: u16) { pub fn set_msg_counter(&mut self, msg_counter: u16) {
self.sec_header.msg_counter = msg_counter self.sec_header.msg_counter = msg_counter
} }
#[inline]
pub fn set_sc_time_ref_status(&mut self, sc_time_ref_status: u8) { pub fn set_sc_time_ref_status(&mut self, sc_time_ref_status: u8) {
self.sec_header.sc_time_ref_status = sc_time_ref_status & 0b1111; self.sec_header.sc_time_ref_status = sc_time_ref_status & 0b1111;
} }
sp_header_impls!(); sp_header_impls!();
/// This is called automatically if the `set_ccsds_len` argument in the [Self::new] call was /// This is called automatically if the `set_ccsds_len` argument in the [PusTm::new] call was
/// used. /// used.
/// If this was not done or the time stamp or source data is set or changed after construction, /// If this was not done or the time stamp or source data is set or changed after construction,
/// this function needs to be called to ensure that the data length field of the CCSDS header /// this function needs to be called to ensure that the data length field of the CCSDS header
/// is set correctly /// is set correctly
#[inline]
pub fn update_ccsds_data_len(&mut self) { pub fn update_ccsds_data_len(&mut self) {
self.sp_header.data_len = self.sp_header.data_len =
self.len_written() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1; self.len_written() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
} }
/// This function should be called before the TM packet is serialized if /// This function should be called before the TM packet is serialized if
/// [Self::calc_crc_on_serialization] is set to False. It will calculate and cache the CRC16. /// [PusTm.calc_crc_on_serialization] is set to False. It will calculate and cache the CRC16.
pub fn calc_own_crc16(&self) -> u16 { pub fn calc_own_crc16(&self) -> u16 {
let mut digest = CRC_CCITT_FALSE.digest(); let mut digest = CRC_CCITT_FALSE.digest();
let sph_zc = crate::zc::SpHeader::from(self.sp_header); let sph_zc = crate::zc::SpHeader::from(self.sp_header);
@ -391,8 +326,7 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
digest.finalize() digest.finalize()
} }
/// This helper function calls both [Self::update_ccsds_data_len] and [Self::calc_own_crc16] /// This helper function calls both [PusTm.update_ccsds_data_len] and [PusTm.calc_own_crc16]
#[inline]
pub fn update_packet_fields(&mut self) { pub fn update_packet_fields(&mut self) {
self.update_ccsds_data_len(); self.update_ccsds_data_len();
} }
@ -449,7 +383,6 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
} }
impl WritablePusPacket for PusTmCreator<'_, '_> { impl WritablePusPacket for PusTmCreator<'_, '_> {
#[inline]
fn len_written(&self) -> usize { fn len_written(&self) -> usize {
PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA
+ self.sec_header.timestamp.len() + self.sec_header.timestamp.len()
@ -475,20 +408,15 @@ impl CcsdsPacket for PusTmCreator<'_, '_> {
impl PusPacket for PusTmCreator<'_, '_> { impl PusPacket for PusTmCreator<'_, '_> {
delegate!(to self.sec_header { delegate!(to self.sec_header {
#[inline]
fn pus_version(&self) -> PusVersion; fn pus_version(&self) -> PusVersion;
#[inline]
fn service(&self) -> u8; fn service(&self) -> u8;
#[inline]
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
}); });
#[inline]
fn user_data(&self) -> &[u8] { fn user_data(&self) -> &[u8] {
self.source_data self.source_data
} }
#[inline]
fn crc16(&self) -> Option<u16> { fn crc16(&self) -> Option<u16> {
Some(self.calc_own_crc16()) Some(self.calc_own_crc16())
} }
@ -496,17 +424,11 @@ impl PusPacket for PusTmCreator<'_, '_> {
impl GenericPusTmSecondaryHeader for PusTmCreator<'_, '_> { impl GenericPusTmSecondaryHeader for PusTmCreator<'_, '_> {
delegate!(to self.sec_header { delegate!(to self.sec_header {
#[inline]
fn pus_version(&self) -> PusVersion; fn pus_version(&self) -> PusVersion;
#[inline]
fn service(&self) -> u8; fn service(&self) -> u8;
#[inline]
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
#[inline]
fn dest_id(&self) -> u16; fn dest_id(&self) -> u16;
#[inline]
fn msg_counter(&self) -> u16; fn msg_counter(&self) -> u16;
#[inline]
fn sc_time_ref_status(&self) -> u8; fn sc_time_ref_status(&self) -> u8;
}); });
} }
@ -527,7 +449,6 @@ impl IsPusTelemetry for PusTmCreator<'_, '_> {}
/// * `'raw_data` - Lifetime of the raw slice this class is constructed from. /// * `'raw_data` - Lifetime of the raw slice this class is constructed from.
#[derive(Eq, Debug, Copy, Clone)] #[derive(Eq, Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PusTmReader<'raw_data> { pub struct PusTmReader<'raw_data> {
pub sp_header: SpHeader, pub sp_header: SpHeader,
pub sec_header: PusTmSecondaryHeader<'raw_data>, pub sec_header: PusTmSecondaryHeader<'raw_data>,
@ -593,23 +514,19 @@ impl<'raw_data> PusTmReader<'raw_data> {
Ok((pus_tm, total_len)) Ok((pus_tm, total_len))
} }
#[inline]
pub fn len_packed(&self) -> usize { pub fn len_packed(&self) -> usize {
self.sp_header.total_len() self.sp_header.total_len()
} }
#[inline]
pub fn source_data(&self) -> &[u8] { pub fn source_data(&self) -> &[u8] {
self.user_data() self.user_data()
} }
#[inline]
pub fn timestamp(&self) -> &[u8] { pub fn timestamp(&self) -> &[u8] {
self.sec_header.timestamp self.sec_header.timestamp
} }
/// This function will return the slice [Self] was constructed from. /// This function will return the slice [Self] was constructed from.
#[inline]
pub fn raw_data(&self) -> &[u8] { pub fn raw_data(&self) -> &[u8] {
self.raw_data self.raw_data
} }
@ -630,20 +547,15 @@ impl CcsdsPacket for PusTmReader<'_> {
impl PusPacket for PusTmReader<'_> { impl PusPacket for PusTmReader<'_> {
delegate!(to self.sec_header { delegate!(to self.sec_header {
#[inline]
fn pus_version(&self) -> PusVersion; fn pus_version(&self) -> PusVersion;
#[inline]
fn service(&self) -> u8; fn service(&self) -> u8;
#[inline]
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
}); });
#[inline]
fn user_data(&self) -> &[u8] { fn user_data(&self) -> &[u8] {
self.source_data self.source_data
} }
#[inline]
fn crc16(&self) -> Option<u16> { fn crc16(&self) -> Option<u16> {
Some(self.crc16) Some(self.crc16)
} }
@ -651,17 +563,11 @@ impl PusPacket for PusTmReader<'_> {
impl GenericPusTmSecondaryHeader for PusTmReader<'_> { impl GenericPusTmSecondaryHeader for PusTmReader<'_> {
delegate!(to self.sec_header { delegate!(to self.sec_header {
#[inline]
fn pus_version(&self) -> PusVersion; fn pus_version(&self) -> PusVersion;
#[inline]
fn service(&self) -> u8; fn service(&self) -> u8;
#[inline]
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
#[inline]
fn dest_id(&self) -> u16; fn dest_id(&self) -> u16;
#[inline]
fn msg_counter(&self) -> u16; fn msg_counter(&self) -> u16;
#[inline]
fn sc_time_ref_status(&self) -> u8; fn sc_time_ref_status(&self) -> u8;
}); });
} }
@ -723,7 +629,6 @@ impl<'raw> PusTmZeroCopyWriter<'raw> {
/// Set the sequence count. Returns false and does not update the value if the passed value /// Set the sequence count. Returns false and does not update the value if the passed value
/// exceeds [MAX_APID]. /// exceeds [MAX_APID].
#[inline]
pub fn set_apid(&mut self, apid: u16) -> bool { pub fn set_apid(&mut self, apid: u16) -> bool {
if apid > MAX_APID { if apid > MAX_APID {
return false; return false;
@ -736,13 +641,11 @@ impl<'raw> PusTmZeroCopyWriter<'raw> {
} }
/// This function sets the message counter in the PUS TM secondary header. /// This function sets the message counter in the PUS TM secondary header.
#[inline]
pub fn set_msg_count(&mut self, msg_count: u16) { pub fn set_msg_count(&mut self, msg_count: u16) {
self.raw_tm[9..11].copy_from_slice(&msg_count.to_be_bytes()); self.raw_tm[9..11].copy_from_slice(&msg_count.to_be_bytes());
} }
/// This function sets the destination ID in the PUS TM secondary header. /// This function sets the destination ID in the PUS TM secondary header.
#[inline]
pub fn set_destination_id(&mut self, dest_id: u16) { pub fn set_destination_id(&mut self, dest_id: u16) {
self.raw_tm[11..13].copy_from_slice(&dest_id.to_be_bytes()) self.raw_tm[11..13].copy_from_slice(&dest_id.to_be_bytes())
} }
@ -767,7 +670,6 @@ impl<'raw> PusTmZeroCopyWriter<'raw> {
/// Set the sequence count. Returns false and does not update the value if the passed value /// Set the sequence count. Returns false and does not update the value if the passed value
/// exceeds [MAX_SEQ_COUNT]. /// exceeds [MAX_SEQ_COUNT].
#[inline]
pub fn set_seq_count(&mut self, seq_count: u16) -> bool { pub fn set_seq_count(&mut self, seq_count: u16) -> bool {
if seq_count > MAX_SEQ_COUNT { if seq_count > MAX_SEQ_COUNT {
return false; return false;
@ -882,20 +784,20 @@ mod tests {
const DUMMY_DATA: &[u8] = &[0, 1, 2]; const DUMMY_DATA: &[u8] = &[0, 1, 2];
fn base_ping_reply_full_ctor(timestamp: &[u8]) -> PusTmCreator { fn base_ping_reply_full_ctor(timestamp: &[u8]) -> PusTmCreator {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
PusTmCreator::new_no_source_data(sph, tm_header, true) PusTmCreator::new_no_source_data(&mut sph, tm_header, true)
} }
fn ping_reply_with_data(timestamp: &[u8]) -> PusTmCreator { fn ping_reply_with_data(timestamp: &[u8]) -> PusTmCreator {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
PusTmCreator::new(sph, tm_header, DUMMY_DATA, true) PusTmCreator::new(&mut sph, tm_header, DUMMY_DATA, true)
} }
fn base_hk_reply<'a, 'b>(timestamp: &'a [u8], src_data: &'b [u8]) -> PusTmCreator<'a, 'b> { fn base_hk_reply<'a, 'b>(timestamp: &'a [u8], src_data: &'b [u8]) -> PusTmCreator<'a, 'b> {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
let tc_header = PusTmSecondaryHeader::new_simple(3, 5, timestamp); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, timestamp);
PusTmCreator::new(sph, tc_header, src_data, true) PusTmCreator::new(&mut sph, tc_header, src_data, true)
} }
fn dummy_timestamp() -> &'static [u8] { fn dummy_timestamp() -> &'static [u8] {
@ -910,11 +812,11 @@ mod tests {
} }
#[test] #[test]
fn test_basic_simple_api() { fn test_basic_simple_api() {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
let time_provider = CdsTime::new_with_u16_days(0, 0); let time_provider = CdsTime::new_with_u16_days(0, 0);
let mut stamp_buf: [u8; 8] = [0; 8]; let mut stamp_buf: [u8; 8] = [0; 8];
let pus_tm = let pus_tm =
PusTmCreator::new_simple(sph, 17, 2, &time_provider, &mut stamp_buf, &[], true) PusTmCreator::new_simple(&mut sph, 17, 2, &time_provider, &mut stamp_buf, None, true)
.unwrap(); .unwrap();
verify_ping_reply(&pus_tm, false, 22, &[64, 0, 0, 0, 0, 0, 0]); verify_ping_reply(&pus_tm, false, 22, &[64, 0, 0, 0, 0, 0, 0]);
} }
@ -1011,9 +913,9 @@ mod tests {
#[test] #[test]
fn test_manual_field_update() { fn test_manual_field_update() {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
let tc_header = PusTmSecondaryHeader::new_simple(17, 2, dummy_timestamp()); let tc_header = PusTmSecondaryHeader::new_simple(17, 2, dummy_timestamp());
let mut tm = PusTmCreator::new_no_source_data(sph, tc_header, false); let mut tm = PusTmCreator::new_no_source_data(&mut sph, tc_header, false);
tm.calc_crc_on_serialization = false; tm.calc_crc_on_serialization = false;
assert_eq!(tm.data_len(), 0x00); assert_eq!(tm.data_len(), 0x00);
let mut buf: [u8; 32] = [0; 32]; let mut buf: [u8; 32] = [0; 32];
@ -1301,11 +1203,11 @@ mod tests {
#[test] #[test]
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
fn test_serialization_creator_serde() { fn test_serialization_creator_serde() {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
let time_provider = CdsTime::new_with_u16_days(0, 0); let time_provider = CdsTime::new_with_u16_days(0, 0);
let mut stamp_buf: [u8; 8] = [0; 8]; let mut stamp_buf: [u8; 8] = [0; 8];
let pus_tm = let pus_tm =
PusTmCreator::new_simple(sph, 17, 2, &time_provider, &mut stamp_buf, &[], true) PusTmCreator::new_simple(&mut sph, 17, 2, &time_provider, &mut stamp_buf, None, true)
.unwrap(); .unwrap();
let output = to_allocvec(&pus_tm).unwrap(); let output = to_allocvec(&pus_tm).unwrap();
@ -1316,11 +1218,11 @@ mod tests {
#[test] #[test]
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
fn test_serialization_reader_serde() { fn test_serialization_reader_serde() {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
let time_provider = CdsTime::new_with_u16_days(0, 0); let time_provider = CdsTime::new_with_u16_days(0, 0);
let mut stamp_buf: [u8; 8] = [0; 8]; let mut stamp_buf: [u8; 8] = [0; 8];
let pus_tm = let pus_tm =
PusTmCreator::new_simple(sph, 17, 2, &time_provider, &mut stamp_buf, &[], true) PusTmCreator::new_simple(&mut sph, 17, 2, &time_provider, &mut stamp_buf, None, true)
.unwrap(); .unwrap();
let pus_tm_vec = pus_tm.to_vec().unwrap(); let pus_tm_vec = pus_tm.to_vec().unwrap();
let (tm_reader, _) = PusTmReader::new(&pus_tm_vec, time_provider.len_as_bytes()).unwrap(); let (tm_reader, _) = PusTmReader::new(&pus_tm_vec, time_provider.len_as_bytes()).unwrap();

View File

@ -22,6 +22,10 @@
//! //!
//! `spacepackets` supports various runtime environments and is also suitable for `no_std` environments. //! `spacepackets` supports various runtime environments and is also suitable for `no_std` environments.
//! //!
//! It also offers optional support for [`serde`](https://serde.rs/). This allows serializing and
//! deserializing them with an appropriate `serde` provider like
//! [`postcard`](https://github.com/jamesmunns/postcard).
//!
//! ### Default features //! ### Default features
//! //!
//! - [`std`](https://doc.rust-lang.org/std/): Enables functionality relying on the standard library. //! - [`std`](https://doc.rust-lang.org/std/): Enables functionality relying on the standard library.
@ -32,11 +36,7 @@
//! ### Optional features //! ### Optional features
//! //!
//! - [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and //! - [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and
//! `Deserialize` `derives. //! `Deserialize` `derive`s
//! - [`chrono`](https://crates.io/crates/chrono): Add basic support for the `chrono` time library.
//! - [`timelib`](https://crates.io/crates/time): Add basic support for the `time` time library.
//! - [`defmt`](https://defmt.ferrous-systems.com/): Add support for the `defmt` by adding the
//! [`defmt::Format`](https://defmt.ferrous-systems.com/format) derive on many types.
//! //!
//! ## Module //! ## Module
//! //!
@ -48,19 +48,20 @@
//! //!
//! ```rust //! ```rust
//! use spacepackets::SpHeader; //! use spacepackets::SpHeader;
//! let sp_header = SpHeader::new_for_unseg_tc_checked(0x42, 12, 1).expect("error creating CCSDS TC header"); //! let sp_header = SpHeader::tc_unseg(0x42, 12, 1).expect("Error creating CCSDS TC header");
//! println!("{:?}", sp_header); //! println!("{:?}", sp_header);
//! let mut ccsds_buf: [u8; 32] = [0; 32]; //! let mut ccsds_buf: [u8; 32] = [0; 32];
//! sp_header.write_to_be_bytes(&mut ccsds_buf).expect("Writing CCSDS TC header failed"); //! sp_header.write_to_be_bytes(&mut ccsds_buf).expect("Writing CCSDS TC header failed");
//! println!("{:x?}", &ccsds_buf[0..6]); //! println!("{:x?}", &ccsds_buf[0..6]);
//! ``` //! ```
#![no_std] #![no_std]
#![cfg_attr(docs_rs, feature(doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
extern crate alloc; extern crate alloc;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
extern crate std; extern crate std;
use crate::ecss::CCSDS_HEADER_LEN;
use core::{ use core::{
fmt::{Debug, Display, Formatter}, fmt::{Debug, Display, Formatter},
hash::Hash, hash::Hash,
@ -83,8 +84,6 @@ mod private {
pub trait Sealed {} pub trait Sealed {}
} }
pub const CCSDS_HEADER_LEN: usize = core::mem::size_of::<crate::zc::SpHeader>();
/// CRC algorithm used by the PUS standard, the CCSDS TC standard and the CFDP standard. /// CRC algorithm used by the PUS standard, the CCSDS TC standard and the CFDP standard.
pub const CRC_CCITT_FALSE: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_3740); pub const CRC_CCITT_FALSE: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_3740);
@ -94,7 +93,6 @@ pub const MAX_SEQ_COUNT: u16 = 2u16.pow(14) - 1;
/// Generic error type when converting to and from raw byte slices. /// Generic error type when converting to and from raw byte slices.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ByteConversionError { pub enum ByteConversionError {
/// The passed slice is too small. Returns the passed slice length and expected minimum size /// The passed slice is too small. Returns the passed slice length and expected minimum size
ToSliceTooSmall { ToSliceTooSmall {
@ -144,7 +142,6 @@ impl Error for ByteConversionError {}
/// CCSDS packet type enumeration. /// CCSDS packet type enumeration.
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PacketType { pub enum PacketType {
Tm = 0, Tm = 0,
Tc = 1, Tc = 1,
@ -168,7 +165,6 @@ pub fn packet_type_in_raw_packet_id(packet_id: u16) -> PacketType {
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SequenceFlags { pub enum SequenceFlags {
ContinuationSegment = 0b00, ContinuationSegment = 0b00,
FirstSegment = 0b01, FirstSegment = 0b01,
@ -196,7 +192,6 @@ impl TryFrom<u8> for SequenceFlags {
/// of the first two bytes in the CCSDS primary header. /// of the first two bytes in the CCSDS primary header.
#[derive(Debug, Eq, Copy, Clone)] #[derive(Debug, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PacketId { pub struct PacketId {
pub ptype: PacketType, pub ptype: PacketType,
pub sec_header_flag: bool, pub sec_header_flag: bool,
@ -204,21 +199,18 @@ pub struct PacketId {
} }
impl PartialEq for PacketId { impl PartialEq for PacketId {
#[inline]
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.raw().eq(&other.raw()) self.raw().eq(&other.raw())
} }
} }
impl PartialOrd for PacketId { impl PartialOrd for PacketId {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
} }
impl Ord for PacketId { impl Ord for PacketId {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering { fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.raw().cmp(&other.raw()) self.raw().cmp(&other.raw())
} }
@ -232,7 +224,6 @@ impl Hash for PacketId {
} }
impl Default for PacketId { impl Default for PacketId {
#[inline]
fn default() -> Self { fn default() -> Self {
PacketId { PacketId {
ptype: PacketType::Tm, ptype: PacketType::Tm,
@ -243,34 +234,23 @@ impl Default for PacketId {
} }
impl PacketId { impl PacketId {
/// This constructor will panic if the passed APID exceeds [MAX_APID]. pub const fn const_tc(sec_header: bool, apid: u16) -> Self {
/// Use the checked constructor variants to avoid panics. Self::const_new(PacketType::Tc, sec_header, apid)
#[inline] }
pub const fn new_for_tc(sec_header: bool, apid: u16) -> Self {
pub const fn const_tm(sec_header: bool, apid: u16) -> Self {
Self::const_new(PacketType::Tm, sec_header, apid)
}
pub fn tc(sec_header: bool, apid: u16) -> Option<Self> {
Self::new(PacketType::Tc, sec_header, apid) Self::new(PacketType::Tc, sec_header, apid)
} }
/// This constructor will panic if the passed APID exceeds [MAX_APID]. pub fn tm(sec_header: bool, apid: u16) -> Option<Self> {
/// Use the checked constructor variants to avoid panics.
#[inline]
pub const fn new_for_tm(sec_header: bool, apid: u16) -> Self {
Self::new(PacketType::Tm, sec_header, apid) Self::new(PacketType::Tm, sec_header, apid)
} }
#[inline] pub const fn const_new(ptype: PacketType, sec_header: bool, apid: u16) -> Self {
pub fn new_for_tc_checked(sec_header: bool, apid: u16) -> Option<Self> {
Self::new_checked(PacketType::Tc, sec_header, apid)
}
#[inline]
pub fn new_for_tm_checked(sec_header: bool, apid: u16) -> Option<Self> {
Self::new_checked(PacketType::Tm, sec_header, apid)
}
/// This constructor will panic if the passed APID exceeds [MAX_APID].
/// Use the checked variants to avoid panics.
#[inline]
pub const fn new(ptype: PacketType, sec_header: bool, apid: u16) -> Self {
if apid > MAX_APID { if apid > MAX_APID {
panic!("APID too large"); panic!("APID too large");
} }
@ -281,18 +261,16 @@ impl PacketId {
} }
} }
#[inline] pub fn new(ptype: PacketType, sec_header_flag: bool, apid: u16) -> Option<PacketId> {
pub fn new_checked(ptype: PacketType, sec_header_flag: bool, apid: u16) -> Option<PacketId> {
if apid > MAX_APID { if apid > MAX_APID {
return None; return None;
} }
Some(PacketId::new(ptype, sec_header_flag, apid)) Some(PacketId::const_new(ptype, sec_header_flag, apid))
} }
/// Set a new Application Process ID (APID). If the passed number is invalid, the APID will /// Set a new Application Process ID (APID). If the passed number is invalid, the APID will
/// not be set and false will be returned. The maximum allowed value for the 11-bit field is /// not be set and false will be returned. The maximum allowed value for the 11-bit field is
/// 2047 /// 2047
#[inline]
pub fn set_apid(&mut self, apid: u16) -> bool { pub fn set_apid(&mut self, apid: u16) -> bool {
if apid > MAX_APID { if apid > MAX_APID {
return false; return false;
@ -301,7 +279,6 @@ impl PacketId {
true true
} }
#[inline]
pub fn apid(&self) -> u16 { pub fn apid(&self) -> u16 {
self.apid self.apid
} }
@ -326,17 +303,15 @@ impl From<u16> for PacketId {
/// third and the fourth byte in the CCSDS primary header. /// third and the fourth byte in the CCSDS primary header.
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PacketSequenceCtrl { pub struct PacketSequenceCtrl {
pub seq_flags: SequenceFlags, pub seq_flags: SequenceFlags,
seq_count: u16, seq_count: u16,
} }
impl PacketSequenceCtrl { impl PacketSequenceCtrl {
/// This constructor panics if the sequence count exceeds [MAX_SEQ_COUNT]. /// const variant of [PacketSequenceCtrl::new], but panics if the sequence count exceeds
/// Use [Self::new_checked] to avoid panics. /// [MAX_SEQ_COUNT].
#[inline] pub const fn const_new(seq_flags: SequenceFlags, seq_count: u16) -> PacketSequenceCtrl {
pub const fn new(seq_flags: SequenceFlags, seq_count: u16) -> PacketSequenceCtrl {
if seq_count > MAX_SEQ_COUNT { if seq_count > MAX_SEQ_COUNT {
panic!("Sequence count too large"); panic!("Sequence count too large");
} }
@ -347,22 +322,18 @@ impl PacketSequenceCtrl {
} }
/// Returns [None] if the passed sequence count exceeds [MAX_SEQ_COUNT]. /// Returns [None] if the passed sequence count exceeds [MAX_SEQ_COUNT].
#[inline] pub fn new(seq_flags: SequenceFlags, seq_count: u16) -> Option<PacketSequenceCtrl> {
pub fn new_checked(seq_flags: SequenceFlags, seq_count: u16) -> Option<PacketSequenceCtrl> {
if seq_count > MAX_SEQ_COUNT { if seq_count > MAX_SEQ_COUNT {
return None; return None;
} }
Some(PacketSequenceCtrl::new(seq_flags, seq_count)) Some(PacketSequenceCtrl::const_new(seq_flags, seq_count))
} }
#[inline]
pub fn raw(&self) -> u16 { pub fn raw(&self) -> u16 {
((self.seq_flags as u16) << 14) | self.seq_count ((self.seq_flags as u16) << 14) | self.seq_count
} }
/// Set a new sequence count. If the passed number is invalid, the sequence count will not be /// Set a new sequence count. If the passed number is invalid, the sequence count will not be
/// set and false will be returned. The maximum allowed value for the 14-bit field is 16383. /// set and false will be returned. The maximum allowed value for the 14-bit field is 16383.
#[inline]
pub fn set_seq_count(&mut self, ssc: u16) -> bool { pub fn set_seq_count(&mut self, ssc: u16) -> bool {
if ssc > MAX_SEQ_COUNT { if ssc > MAX_SEQ_COUNT {
return false; return false;
@ -371,7 +342,6 @@ impl PacketSequenceCtrl {
true true
} }
#[inline]
pub fn seq_count(&self) -> u16 { pub fn seq_count(&self) -> u16 {
self.seq_count self.seq_count
} }
@ -413,7 +383,6 @@ pub trait CcsdsPacket {
/// Retrieve data length field /// Retrieve data length field
fn data_len(&self) -> u16; fn data_len(&self) -> u16;
/// Retrieve the total packet size based on the data length field /// Retrieve the total packet size based on the data length field
#[inline]
fn total_len(&self) -> usize { fn total_len(&self) -> usize {
usize::from(self.data_len()) + CCSDS_HEADER_LEN + 1 usize::from(self.data_len()) + CCSDS_HEADER_LEN + 1
} }
@ -494,7 +463,6 @@ pub trait CcsdsPrimaryHeader {
/// * `data_len` - Data length field occupies the fifth and the sixth byte of the raw header /// * `data_len` - Data length field occupies the fifth and the sixth byte of the raw header
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SpHeader { pub struct SpHeader {
pub version: u8, pub version: u8,
pub packet_id: PacketId, pub packet_id: PacketId,
@ -502,12 +470,9 @@ pub struct SpHeader {
pub data_len: u16, pub data_len: u16,
} }
pub type SpacePacketHeader = SpHeader;
impl Default for SpHeader { impl Default for SpHeader {
/// The default function sets the sequence flag field to [SequenceFlags::Unsegmented] and the /// The default function sets the sequence flag field to [SequenceFlags::Unsegmented]. The data
/// data length to 0. /// length field is set to 1, which denotes an empty space packets.
#[inline]
fn default() -> Self { fn default() -> Self {
SpHeader { SpHeader {
version: 0, version: 0,
@ -516,13 +481,12 @@ impl Default for SpHeader {
seq_flags: SequenceFlags::Unsegmented, seq_flags: SequenceFlags::Unsegmented,
seq_count: 0, seq_count: 0,
}, },
data_len: 0, data_len: 1,
} }
} }
} }
impl SpHeader { impl SpHeader {
#[inline]
pub const fn new(packet_id: PacketId, psc: PacketSequenceCtrl, data_len: u16) -> Self { pub const fn new(packet_id: PacketId, psc: PacketSequenceCtrl, data_len: u16) -> Self {
Self { Self {
version: 0, version: 0,
@ -532,43 +496,9 @@ impl SpHeader {
} }
} }
/// This constructor sets the sequence flag field to [SequenceFlags::Unsegmented] and the data /// const variant of the [SpHeader::new_fron_single_fields] function. Panics if the passed
/// length to 0. /// APID exceeds [MAX_APID] or the passed packet sequence count exceeds [MAX_SEQ_COUNT].
/// const fn const_new_from_single_fields(
/// This constructor will panic if the APID exceeds [MAX_APID].
#[inline]
pub const fn new_from_apid(apid: u16) -> Self {
SpHeader {
version: 0,
packet_id: PacketId::new(PacketType::Tm, false, apid),
psc: PacketSequenceCtrl {
seq_flags: SequenceFlags::Unsegmented,
seq_count: 0,
},
data_len: 0,
}
}
/// Checked variant of [Self::new_from_apid].
#[inline]
pub fn new_from_apid_checked(apid: u16) -> Option<Self> {
Some(SpHeader {
version: 0,
packet_id: PacketId::new_checked(PacketType::Tm, false, apid)?,
psc: PacketSequenceCtrl {
seq_flags: SequenceFlags::Unsegmented,
seq_count: 0,
},
data_len: 0,
})
}
/// This constructor panics if the passed APID exceeds [MAX_APID] or the passed packet sequence
/// count exceeds [MAX_SEQ_COUNT].
///
/// The checked constructor variants can be used to avoid panics.
#[inline]
pub const fn new_from_fields(
ptype: PacketType, ptype: PacketType,
sec_header: bool, sec_header: bool,
apid: u16, apid: u16,
@ -583,20 +513,17 @@ impl SpHeader {
panic!("APID is too large"); panic!("APID is too large");
} }
Self { Self {
psc: PacketSequenceCtrl::new(seq_flags, seq_count), psc: PacketSequenceCtrl::const_new(seq_flags, seq_count),
packet_id: PacketId::new(ptype, sec_header, apid), packet_id: PacketId::const_new(ptype, sec_header, apid),
data_len, data_len,
version: 0, version: 0,
} }
} }
/// Create a new Space Packet Header instance which can be used to create generic /// Create a new Space Packet Header instance which can be used to create generic
/// Space Packets. /// Space Packets. This will return [None] if the APID or sequence count argument
///
/// This will return [None] if the APID or sequence count argument
/// exceed [MAX_APID] or [MAX_SEQ_COUNT] respectively. The version field is set to 0b000. /// exceed [MAX_APID] or [MAX_SEQ_COUNT] respectively. The version field is set to 0b000.
#[inline] pub fn new_from_single_fields(
pub fn new_from_fields_checked(
ptype: PacketType, ptype: PacketType,
sec_header: bool, sec_header: bool,
apid: u16, apid: u16,
@ -607,117 +534,56 @@ impl SpHeader {
if seq_count > MAX_SEQ_COUNT || apid > MAX_APID { if seq_count > MAX_SEQ_COUNT || apid > MAX_APID {
return None; return None;
} }
Some(SpHeader::new_from_fields( Some(SpHeader::const_new_from_single_fields(
ptype, sec_header, apid, seq_flags, seq_count, data_len, ptype, sec_header, apid, seq_flags, seq_count, data_len,
)) ))
} }
/// Helper function for telemetry space packet headers. The packet type field will be /// Helper function for telemetry space packet headers. The packet type field will be
/// set accordingly. The secondary header flag field is set to false. /// set accordingly. The secondary header flag field is set to false.
#[inline] pub fn tm(apid: u16, seq_flags: SequenceFlags, seq_count: u16, data_len: u16) -> Option<Self> {
pub fn new_for_tm_checked( Self::new_from_single_fields(PacketType::Tm, false, apid, seq_flags, seq_count, data_len)
apid: u16,
seq_flags: SequenceFlags,
seq_count: u16,
data_len: u16,
) -> Option<Self> {
Self::new_from_fields_checked(PacketType::Tm, false, apid, seq_flags, seq_count, data_len)
} }
/// Helper function for telemetry space packet headers. The packet type field will be /// Helper function for telemetry space packet headers. The packet type field will be
/// set accordingly. The secondary header flag field is set to false. /// set accordingly. The secondary header flag field is set to false.
#[inline] pub fn tc(apid: u16, seq_flags: SequenceFlags, seq_count: u16, data_len: u16) -> Option<Self> {
pub fn new_for_tc_checked( Self::new_from_single_fields(PacketType::Tc, false, apid, seq_flags, seq_count, data_len)
apid: u16,
seq_flags: SequenceFlags,
seq_count: u16,
data_len: u16,
) -> Option<Self> {
Self::new_from_fields_checked(PacketType::Tc, false, apid, seq_flags, seq_count, data_len)
} }
/// This is an unchecked constructor which can panic on invalid input. /// Variant of [SpHeader::tm] which sets the sequence flag field to [SequenceFlags::Unsegmented]
#[inline] pub fn tm_unseg(apid: u16, seq_count: u16, data_len: u16) -> Option<Self> {
pub const fn new_for_tm( Self::tm(apid, SequenceFlags::Unsegmented, seq_count, data_len)
apid: u16,
seq_flags: SequenceFlags,
seq_count: u16,
data_len: u16,
) -> Self {
Self::new_from_fields(PacketType::Tm, false, apid, seq_flags, seq_count, data_len)
} }
/// This is an unchecked constructor which can panic on invalid input. /// Variant of [SpHeader::tc] which sets the sequence flag field to [SequenceFlags::Unsegmented]
#[inline] pub fn tc_unseg(apid: u16, seq_count: u16, data_len: u16) -> Option<Self> {
pub const fn new_for_tc( Self::tc(apid, SequenceFlags::Unsegmented, seq_count, data_len)
apid: u16,
seq_flags: SequenceFlags,
seq_count: u16,
data_len: u16,
) -> Self {
Self::new_from_fields(PacketType::Tc, false, apid, seq_flags, seq_count, data_len)
} }
/// Variant of [SpHeader::new_for_tm_checked] which sets the sequence flag field to [SequenceFlags::Unsegmented] //noinspection RsTraitImplementation
#[inline] delegate!(to self.packet_id {
pub fn new_for_unseg_tm_checked(apid: u16, seq_count: u16, data_len: u16) -> Option<Self> { /// Returns [false] and fails if the APID exceeds [MAX_APID]
Self::new_for_tm_checked(apid, SequenceFlags::Unsegmented, seq_count, data_len) pub fn set_apid(&mut self, apid: u16) -> bool;
} });
/// Variant of [SpHeader::new_for_tc_checked] which sets the sequence flag field to [SequenceFlags::Unsegmented] delegate!(to self.psc {
#[inline] /// Returns [false] and fails if the sequence count exceeds [MAX_SEQ_COUNT]
pub fn new_for_unseg_tc_checked(apid: u16, seq_count: u16, data_len: u16) -> Option<Self> { pub fn set_seq_count(&mut self, seq_count: u16) -> bool;
Self::new_for_tc_checked(apid, SequenceFlags::Unsegmented, seq_count, data_len) });
}
/// Variant of [SpHeader::new_for_tc] which sets the sequence flag field to [SequenceFlags::Unsegmented].
///
/// This is an unchecked constructor which can panic on invalid input.
#[inline]
pub const fn new_for_unseg_tc(apid: u16, seq_count: u16, data_len: u16) -> Self {
Self::new_for_tc(apid, SequenceFlags::Unsegmented, seq_count, data_len)
}
/// Variant of [SpHeader::new_for_tm] which sets the sequence flag field to [SequenceFlags::Unsegmented].
///
/// This is an unchecked constructor which can panic on invalid input.
#[inline]
pub const fn new_for_unseg_tm(apid: u16, seq_count: u16, data_len: u16) -> Self {
Self::new_for_tm(apid, SequenceFlags::Unsegmented, seq_count, data_len)
}
delegate! {
to self.packet_id {
/// Returns [false] and fails if the APID exceeds [MAX_APID]
#[inline]
pub fn set_apid(&mut self, apid: u16) -> bool;
}
}
delegate! {
to self.psc {
/// Returns [false] and fails if the sequence count exceeds [MAX_SEQ_COUNT]
#[inline]
pub fn set_seq_count(&mut self, seq_count: u16) -> bool;
}
}
#[inline]
pub fn set_seq_flags(&mut self, seq_flags: SequenceFlags) { pub fn set_seq_flags(&mut self, seq_flags: SequenceFlags) {
self.psc.seq_flags = seq_flags; self.psc.seq_flags = seq_flags;
} }
#[inline]
pub fn set_sec_header_flag(&mut self) { pub fn set_sec_header_flag(&mut self) {
self.packet_id.sec_header_flag = true; self.packet_id.sec_header_flag = true;
} }
#[inline]
pub fn clear_sec_header_flag(&mut self) { pub fn clear_sec_header_flag(&mut self) {
self.packet_id.sec_header_flag = false; self.packet_id.sec_header_flag = false;
} }
#[inline]
pub fn set_packet_type(&mut self, packet_type: PacketType) { pub fn set_packet_type(&mut self, packet_type: PacketType) {
self.packet_id.ptype = packet_type; self.packet_id.ptype = packet_type;
} }
@ -755,15 +621,6 @@ impl SpHeader {
.ok_or(ByteConversionError::ZeroCopyToError)?; .ok_or(ByteConversionError::ZeroCopyToError)?;
Ok(&mut buf[CCSDS_HEADER_LEN..]) Ok(&mut buf[CCSDS_HEADER_LEN..])
} }
/// Create a vector containing the CCSDS header.
#[cfg(feature = "alloc")]
pub fn to_vec(&self) -> alloc::vec::Vec<u8> {
let mut vec = alloc::vec![0; CCSDS_HEADER_LEN];
// This can not fail.
self.write_to_be_bytes(&mut vec[..]).unwrap();
vec
}
} }
impl CcsdsPacket for SpHeader { impl CcsdsPacket for SpHeader {
@ -789,7 +646,6 @@ impl CcsdsPacket for SpHeader {
} }
impl CcsdsPrimaryHeader for SpHeader { impl CcsdsPrimaryHeader for SpHeader {
#[inline]
fn from_composite_fields( fn from_composite_fields(
packet_id: PacketId, packet_id: PacketId,
psc: PacketSequenceCtrl, psc: PacketSequenceCtrl,
@ -857,12 +713,9 @@ pub mod zc {
((self.version_packet_id.get() >> 13) as u8) & 0b111 ((self.version_packet_id.get() >> 13) as u8) & 0b111
} }
#[inline]
fn packet_id(&self) -> PacketId { fn packet_id(&self) -> PacketId {
PacketId::from(self.packet_id_raw()) PacketId::from(self.packet_id_raw())
} }
#[inline]
fn psc(&self) -> PacketSequenceCtrl { fn psc(&self) -> PacketSequenceCtrl {
PacketSequenceCtrl::from(self.psc_raw()) PacketSequenceCtrl::from(self.psc_raw())
} }
@ -872,12 +725,10 @@ pub mod zc {
self.data_len.get() self.data_len.get()
} }
#[inline]
fn packet_id_raw(&self) -> u16 { fn packet_id_raw(&self) -> u16 {
self.version_packet_id.get() & (!VERSION_MASK) self.version_packet_id.get() & (!VERSION_MASK)
} }
#[inline]
fn psc_raw(&self) -> u16 { fn psc_raw(&self) -> u16 {
self.psc.get() self.psc.get()
} }
@ -901,8 +752,6 @@ pub mod zc {
pub(crate) mod tests { pub(crate) mod tests {
use std::collections::HashSet; use std::collections::HashSet;
#[allow(unused_imports)]
use crate::ByteConversionError;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use crate::CcsdsPrimaryHeader; use crate::CcsdsPrimaryHeader;
use crate::{ use crate::{
@ -919,12 +768,12 @@ pub(crate) mod tests {
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
const CONST_SP: SpHeader = SpHeader::new( const CONST_SP: SpHeader = SpHeader::new(
PacketId::new_for_tc(true, 0x36), PacketId::const_tc(true, 0x36),
PacketSequenceCtrl::new(SequenceFlags::ContinuationSegment, 0x88), PacketSequenceCtrl::const_new(SequenceFlags::ContinuationSegment, 0x88),
0x90, 0x90,
); );
const PACKET_ID_TM: PacketId = PacketId::new_for_tm(true, 0x22); const PACKET_ID_TM: PacketId = PacketId::const_tm(true, 0x22);
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
pub(crate) fn generic_serde_test<T: Serialize + DeserializeOwned + PartialEq + Debug>( pub(crate) fn generic_serde_test<T: Serialize + DeserializeOwned + PartialEq + Debug>(
@ -936,12 +785,11 @@ pub(crate) mod tests {
} }
#[test] #[test]
#[allow(clippy::assertions_on_constants)]
fn verify_const_packet_id() { fn verify_const_packet_id() {
assert_eq!(PACKET_ID_TM.apid(), 0x22); assert_eq!(PACKET_ID_TM.apid(), 0x22);
assert!(PACKET_ID_TM.sec_header_flag); assert!(PACKET_ID_TM.sec_header_flag);
assert_eq!(PACKET_ID_TM.ptype, PacketType::Tm); assert_eq!(PACKET_ID_TM.ptype, PacketType::Tm);
let const_tc_id = PacketId::new_for_tc(true, 0x23); let const_tc_id = PacketId::const_tc(true, 0x23);
assert_eq!(const_tc_id.ptype, PacketType::Tc); assert_eq!(const_tc_id.ptype, PacketType::Tc);
} }
@ -950,32 +798,32 @@ pub(crate) mod tests {
let id_default = PacketId::default(); let id_default = PacketId::default();
assert_eq!(id_default.ptype, PacketType::Tm); assert_eq!(id_default.ptype, PacketType::Tm);
assert_eq!(id_default.apid, 0x000); assert_eq!(id_default.apid, 0x000);
assert!(!id_default.sec_header_flag); assert_eq!(id_default.sec_header_flag, false);
} }
#[test] #[test]
fn test_packet_id_ctors() { fn test_packet_id_ctors() {
let packet_id = PacketId::new_checked(PacketType::Tc, true, 0x1ff); let packet_id = PacketId::new(PacketType::Tc, true, 0x1ff);
assert!(packet_id.is_some()); assert!(packet_id.is_some());
let packet_id = packet_id.unwrap(); let packet_id = packet_id.unwrap();
assert_eq!(packet_id.apid(), 0x1ff); assert_eq!(packet_id.apid(), 0x1ff);
assert_eq!(packet_id.ptype, PacketType::Tc); assert_eq!(packet_id.ptype, PacketType::Tc);
assert!(packet_id.sec_header_flag); assert_eq!(packet_id.sec_header_flag, true);
let packet_id_tc = PacketId::new_for_tc_checked(true, 0x1ff); let packet_id_tc = PacketId::tc(true, 0x1ff);
assert!(packet_id_tc.is_some()); assert!(packet_id_tc.is_some());
let packet_id_tc = packet_id_tc.unwrap(); let packet_id_tc = packet_id_tc.unwrap();
assert_eq!(packet_id_tc, packet_id); assert_eq!(packet_id_tc, packet_id);
let packet_id_tm = PacketId::new_for_tm_checked(true, 0x2ff); let packet_id_tm = PacketId::tm(true, 0x2ff);
assert!(packet_id_tm.is_some()); assert!(packet_id_tm.is_some());
let packet_id_tm = packet_id_tm.unwrap(); let packet_id_tm = packet_id_tm.unwrap();
assert!(packet_id_tm.sec_header_flag); assert_eq!(packet_id_tm.sec_header_flag, true);
assert_eq!(packet_id_tm.ptype, PacketType::Tm); assert_eq!(packet_id_tm.ptype, PacketType::Tm);
assert_eq!(packet_id_tm.apid, 0x2ff); assert_eq!(packet_id_tm.apid, 0x2ff);
} }
#[test] #[test]
fn verify_const_sp_header() { fn verify_const_sp_header() {
assert!(CONST_SP.sec_header_flag()); assert_eq!(CONST_SP.sec_header_flag(), true);
assert_eq!(CONST_SP.apid(), 0x36); assert_eq!(CONST_SP.apid(), 0x36);
assert_eq!( assert_eq!(
CONST_SP.sequence_flags(), CONST_SP.sequence_flags(),
@ -1016,7 +864,7 @@ pub(crate) mod tests {
#[test] #[test]
fn test_packet_id() { fn test_packet_id() {
let packet_id = let packet_id =
PacketId::new_checked(PacketType::Tm, false, 0x42).expect("Packet ID creation failed"); PacketId::new(PacketType::Tm, false, 0x42).expect("Packet ID creation failed");
assert_eq!(packet_id.raw(), 0x0042); assert_eq!(packet_id.raw(), 0x0042);
let packet_id_from_raw = PacketId::from(packet_id.raw()); let packet_id_from_raw = PacketId::from(packet_id.raw());
assert_eq!( assert_eq!(
@ -1024,26 +872,26 @@ pub(crate) mod tests {
PacketType::Tm PacketType::Tm
); );
assert_eq!(packet_id_from_raw, packet_id); assert_eq!(packet_id_from_raw, packet_id);
let packet_id_from_new = PacketId::new_checked(PacketType::Tm, false, 0x42).unwrap(); let packet_id_from_new = PacketId::new(PacketType::Tm, false, 0x42).unwrap();
assert_eq!(packet_id_from_new, packet_id); assert_eq!(packet_id_from_new, packet_id);
} }
#[test] #[test]
fn test_invalid_packet_id() { fn test_invalid_packet_id() {
let packet_id_invalid = PacketId::new_checked(PacketType::Tc, true, 0xFFFF); let packet_id_invalid = PacketId::new(PacketType::Tc, true, 0xFFFF);
assert!(packet_id_invalid.is_none()); assert!(packet_id_invalid.is_none());
} }
#[test] #[test]
fn test_invalid_apid_setter() { fn test_invalid_apid_setter() {
let mut packet_id = let mut packet_id =
PacketId::new_checked(PacketType::Tm, false, 0x42).expect("Packet ID creation failed"); PacketId::new(PacketType::Tm, false, 0x42).expect("Packet ID creation failed");
assert!(!packet_id.set_apid(0xffff)); assert!(!packet_id.set_apid(0xffff));
} }
#[test] #[test]
fn test_invalid_seq_count() { fn test_invalid_seq_count() {
let mut psc = PacketSequenceCtrl::new_checked(SequenceFlags::ContinuationSegment, 77) let mut psc = PacketSequenceCtrl::new(SequenceFlags::ContinuationSegment, 77)
.expect("PSC creation failed"); .expect("PSC creation failed");
assert_eq!(psc.seq_count(), 77); assert_eq!(psc.seq_count(), 77);
assert!(!psc.set_seq_count(0xffff)); assert!(!psc.set_seq_count(0xffff));
@ -1051,7 +899,7 @@ pub(crate) mod tests {
#[test] #[test]
fn test_packet_seq_ctrl() { fn test_packet_seq_ctrl() {
let mut psc = PacketSequenceCtrl::new_checked(SequenceFlags::ContinuationSegment, 77) let mut psc = PacketSequenceCtrl::new(SequenceFlags::ContinuationSegment, 77)
.expect("PSC creation failed"); .expect("PSC creation failed");
assert_eq!(psc.raw(), 77); assert_eq!(psc.raw(), 77);
let psc_from_raw = PacketSequenceCtrl::from(psc.raw()); let psc_from_raw = PacketSequenceCtrl::from(psc.raw());
@ -1060,18 +908,16 @@ pub(crate) mod tests {
assert!(!psc.set_seq_count(2u16.pow(15))); assert!(!psc.set_seq_count(2u16.pow(15)));
assert_eq!(psc.raw(), 77); assert_eq!(psc.raw(), 77);
let psc_invalid = PacketSequenceCtrl::new_checked(SequenceFlags::FirstSegment, 0xFFFF); let psc_invalid = PacketSequenceCtrl::new(SequenceFlags::FirstSegment, 0xFFFF);
assert!(psc_invalid.is_none()); assert!(psc_invalid.is_none());
let psc_from_new = let psc_from_new = PacketSequenceCtrl::new(SequenceFlags::ContinuationSegment, 77).unwrap();
PacketSequenceCtrl::new_checked(SequenceFlags::ContinuationSegment, 77).unwrap();
assert_eq!(psc_from_new, psc); assert_eq!(psc_from_new, psc);
} }
#[test] #[test]
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
fn test_serde_sph() { fn test_serde_sph() {
let sp_header = let sp_header = SpHeader::tc_unseg(0x42, 12, 0).expect("Error creating SP header");
SpHeader::new_for_unseg_tc_checked(0x42, 12, 0).expect("Error creating SP header");
assert_eq!(sp_header.ccsds_version(), 0b000); assert_eq!(sp_header.ccsds_version(), 0b000);
assert!(sp_header.is_tc()); assert!(sp_header.is_tc());
assert!(!sp_header.sec_header_flag()); assert!(!sp_header.sec_header_flag());
@ -1093,8 +939,7 @@ pub(crate) mod tests {
assert_eq!(sp_header.ccsds_version(), 0b000); assert_eq!(sp_header.ccsds_version(), 0b000);
assert_eq!(sp_header.data_len, 0); assert_eq!(sp_header.data_len, 0);
let sp_header = let sp_header = SpHeader::tm_unseg(0x7, 22, 36).expect("Error creating SP header");
SpHeader::new_for_unseg_tm_checked(0x7, 22, 36).expect("Error creating SP header");
assert_eq!(sp_header.ccsds_version(), 0b000); assert_eq!(sp_header.ccsds_version(), 0b000);
assert!(sp_header.is_tm()); assert!(sp_header.is_tm());
assert!(!sp_header.sec_header_flag()); assert!(!sp_header.sec_header_flag());
@ -1108,8 +953,8 @@ pub(crate) mod tests {
assert_eq!(sp_header.ccsds_version(), 0b000); assert_eq!(sp_header.ccsds_version(), 0b000);
let from_comp_fields = SpHeader::from_composite_fields( let from_comp_fields = SpHeader::from_composite_fields(
PacketId::new(PacketType::Tc, true, 0x42), PacketId::new(PacketType::Tc, true, 0x42).unwrap(),
PacketSequenceCtrl::new(SequenceFlags::Unsegmented, 0x7), PacketSequenceCtrl::new(SequenceFlags::Unsegmented, 0x7).unwrap(),
0, 0,
None, None,
); );
@ -1126,7 +971,7 @@ pub(crate) mod tests {
#[test] #[test]
fn test_setters() { fn test_setters() {
let sp_header = SpHeader::new_for_tc_checked(0x42, SequenceFlags::Unsegmented, 25, 0); let sp_header = SpHeader::tc(0x42, SequenceFlags::Unsegmented, 25, 0);
assert!(sp_header.is_some()); assert!(sp_header.is_some());
let mut sp_header = sp_header.unwrap(); let mut sp_header = sp_header.unwrap();
sp_header.set_apid(0x12); sp_header.set_apid(0x12);
@ -1144,7 +989,7 @@ pub(crate) mod tests {
#[test] #[test]
fn test_tc_ctor() { fn test_tc_ctor() {
let sp_header = SpHeader::new_for_tc_checked(0x42, SequenceFlags::Unsegmented, 25, 0); let sp_header = SpHeader::tc(0x42, SequenceFlags::Unsegmented, 25, 0);
assert!(sp_header.is_some()); assert!(sp_header.is_some());
let sp_header = sp_header.unwrap(); let sp_header = sp_header.unwrap();
verify_sp_fields(PacketType::Tc, &sp_header); verify_sp_fields(PacketType::Tc, &sp_header);
@ -1152,35 +997,23 @@ pub(crate) mod tests {
#[test] #[test]
fn test_tc_ctor_unseg() { fn test_tc_ctor_unseg() {
let sp_header = SpHeader::new_for_unseg_tc_checked(0x42, 25, 0); let sp_header = SpHeader::tc_unseg(0x42, 25, 0);
assert!(sp_header.is_some()); assert!(sp_header.is_some());
let sp_header = sp_header.unwrap(); let sp_header = sp_header.unwrap();
verify_sp_fields(PacketType::Tc, &sp_header); verify_sp_fields(PacketType::Tc, &sp_header);
} }
#[test]
fn test_tc_ctor_unseg_const() {
let sp_header = SpHeader::new_for_unseg_tc(0x42, 25, 0);
verify_sp_fields(PacketType::Tc, &sp_header);
}
#[test] #[test]
fn test_tm_ctor() { fn test_tm_ctor() {
let sp_header = SpHeader::new_for_tm_checked(0x42, SequenceFlags::Unsegmented, 25, 0); let sp_header = SpHeader::tm(0x42, SequenceFlags::Unsegmented, 25, 0);
assert!(sp_header.is_some()); assert!(sp_header.is_some());
let sp_header = sp_header.unwrap(); let sp_header = sp_header.unwrap();
verify_sp_fields(PacketType::Tm, &sp_header); verify_sp_fields(PacketType::Tm, &sp_header);
} }
#[test]
fn test_tm_ctor_const() {
let sp_header = SpHeader::new_for_tm(0x42, SequenceFlags::Unsegmented, 25, 0);
verify_sp_fields(PacketType::Tm, &sp_header);
}
#[test] #[test]
fn test_tm_ctor_unseg() { fn test_tm_ctor_unseg() {
let sp_header = SpHeader::new_for_unseg_tm_checked(0x42, 25, 0); let sp_header = SpHeader::tm_unseg(0x42, 25, 0);
assert!(sp_header.is_some()); assert!(sp_header.is_some());
let sp_header = sp_header.unwrap(); let sp_header = sp_header.unwrap();
verify_sp_fields(PacketType::Tm, &sp_header); verify_sp_fields(PacketType::Tm, &sp_header);
@ -1198,8 +1031,8 @@ pub(crate) mod tests {
fn test_zc_sph() { fn test_zc_sph() {
use zerocopy::AsBytes; use zerocopy::AsBytes;
let sp_header = SpHeader::new_for_unseg_tc_checked(0x7FF, pow(2, 14) - 1, 0) let sp_header =
.expect("Error creating SP header"); SpHeader::tc_unseg(0x7FF, pow(2, 14) - 1, 0).expect("Error creating SP header");
assert_eq!(sp_header.ptype(), PacketType::Tc); assert_eq!(sp_header.ptype(), PacketType::Tc);
assert_eq!(sp_header.apid(), 0x7FF); assert_eq!(sp_header.apid(), 0x7FF);
assert_eq!(sp_header.data_len(), 0); assert_eq!(sp_header.data_len(), 0);
@ -1264,40 +1097,4 @@ pub(crate) mod tests {
let mut id_set = HashSet::new(); let mut id_set = HashSet::new();
id_set.insert(PacketId::from(1_u16)); id_set.insert(PacketId::from(1_u16));
} }
#[test]
fn sp_header_from_apid() {
let sp_header = SpHeader::new_from_apid(0x03);
assert_eq!(sp_header.apid(), 0x03);
assert_eq!(sp_header.data_len(), 0);
}
#[test]
fn sp_header_from_apid_checked() {
let sp_header = SpHeader::new_from_apid_checked(0x03).unwrap();
assert_eq!(sp_header.apid(), 0x03);
assert_eq!(sp_header.data_len(), 0);
}
#[cfg(feature = "defmt")]
fn is_defmt_format<T: defmt::Format>(_t: T) {}
#[test]
#[cfg(feature = "defmt")]
fn test_defmt_format() {
is_defmt_format(ByteConversionError::ToSliceTooSmall {
found: 1,
expected: 2,
});
}
#[test]
fn test_sp_header_as_vec() {
let sp_header = SpHeader::new_for_unseg_tc(0x42, 25, 1);
let sp_header_as_vec = sp_header.to_vec();
let sp_header_read_back = SpHeader::from_be_bytes(&sp_header_as_vec)
.expect("Error reading back SP header")
.0;
assert_eq!(sp_header, sp_header_read_back);
}
} }

View File

@ -78,7 +78,6 @@ impl ProvidesDaysLength for DaysLen24Bits {
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum LengthOfDaySegment { pub enum LengthOfDaySegment {
Short16Bits = 0, Short16Bits = 0,
Long24Bits = 1, Long24Bits = 1,
@ -95,7 +94,6 @@ pub enum SubmillisPrecision {
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CdsError { pub enum CdsError {
/// CCSDS days value exceeds maximum allowed size or is negative /// CCSDS days value exceeds maximum allowed size or is negative
InvalidCcsdsDays(i64), InvalidCcsdsDays(i64),
@ -145,7 +143,6 @@ pub fn length_of_day_segment_from_pfield(pfield: u8) -> LengthOfDaySegment {
LengthOfDaySegment::Short16Bits LengthOfDaySegment::Short16Bits
} }
#[inline]
pub fn precision_from_pfield(pfield: u8) -> SubmillisPrecision { pub fn precision_from_pfield(pfield: u8) -> SubmillisPrecision {
match pfield & 0b11 { match pfield & 0b11 {
0b01 => SubmillisPrecision::Microseconds, 0b01 => SubmillisPrecision::Microseconds,
@ -273,29 +270,24 @@ impl ConversionFromUnix {
} }
impl CdsCommon for ConversionFromUnix { impl CdsCommon for ConversionFromUnix {
#[inline]
fn submillis_precision(&self) -> SubmillisPrecision { fn submillis_precision(&self) -> SubmillisPrecision {
self.submilis_prec self.submilis_prec
} }
#[inline]
fn ms_of_day(&self) -> u32 { fn ms_of_day(&self) -> u32 {
self.ms_of_day self.ms_of_day
} }
#[inline]
fn ccsds_days_as_u32(&self) -> u32 { fn ccsds_days_as_u32(&self) -> u32 {
self.ccsds_days self.ccsds_days
} }
#[inline]
fn submillis(&self) -> u32 { fn submillis(&self) -> u32 {
self.submillis self.submillis
} }
} }
impl CdsConverter for ConversionFromUnix { impl CdsConverter for ConversionFromUnix {
#[inline]
fn unix_days_seconds(&self) -> i64 { fn unix_days_seconds(&self) -> i64 {
self.unix_days_seconds self.unix_days_seconds
} }
@ -308,31 +300,24 @@ struct ConversionFromChronoDatetime {
} }
impl CdsCommon for ConversionFromChronoDatetime { impl CdsCommon for ConversionFromChronoDatetime {
#[inline]
fn submillis_precision(&self) -> SubmillisPrecision { fn submillis_precision(&self) -> SubmillisPrecision {
self.submillis_prec self.submillis_prec
} }
delegate! { delegate! {
to self.unix_conversion { to self.unix_conversion {
#[inline]
fn ms_of_day(&self) -> u32; fn ms_of_day(&self) -> u32;
#[inline]
fn ccsds_days_as_u32(&self) -> u32; fn ccsds_days_as_u32(&self) -> u32;
} }
} }
#[inline]
fn submillis(&self) -> u32 { fn submillis(&self) -> u32 {
self.submillis self.submillis
} }
} }
impl CdsConverter for ConversionFromChronoDatetime { impl CdsConverter for ConversionFromChronoDatetime {
delegate! {to self.unix_conversion { delegate! {to self.unix_conversion { fn unix_days_seconds(&self) -> i64; }}
#[inline]
fn unix_days_seconds(&self) -> i64;
}}
} }
#[inline] #[inline]

View File

@ -37,7 +37,6 @@ pub const MAX_CUC_LEN_SMALL_PREAMBLE: usize = 8;
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FractionalResolution { pub enum FractionalResolution {
/// No fractional part, only second resolution /// No fractional part, only second resolution
Seconds = 0, Seconds = 0,
@ -106,7 +105,6 @@ pub fn fractional_part_from_subsec_ns(res: FractionalResolution, ns: u64) -> Fra
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CucError { pub enum CucError {
InvalidCounterWidth(u8), InvalidCounterWidth(u8),
/// Invalid counter supplied. /// Invalid counter supplied.
@ -177,7 +175,6 @@ pub struct FractionalPart {
} }
impl FractionalPart { impl FractionalPart {
#[inline]
pub const fn new(resolution: FractionalResolution, counter: u32) -> Self { pub const fn new(resolution: FractionalResolution, counter: u32) -> Self {
let div = fractional_res_to_div(resolution); let div = fractional_res_to_div(resolution);
assert!(counter <= div, "invalid counter for resolution"); assert!(counter <= div, "invalid counter for resolution");
@ -188,18 +185,15 @@ impl FractionalPart {
} }
/// An empty fractional part for second resolution only. /// An empty fractional part for second resolution only.
#[inline]
pub const fn new_with_seconds_resolution() -> Self { pub const fn new_with_seconds_resolution() -> Self {
Self::new(FractionalResolution::Seconds, 0) Self::new(FractionalResolution::Seconds, 0)
} }
/// Helper method which simply calls [Self::new_with_seconds_resolution]. /// Helper method which simply calls [Self::new_with_seconds_resolution].
#[inline]
pub const fn new_empty() -> Self { pub const fn new_empty() -> Self {
Self::new_with_seconds_resolution() Self::new_with_seconds_resolution()
} }
#[inline]
pub fn new_checked(resolution: FractionalResolution, counter: u32) -> Option<Self> { pub fn new_checked(resolution: FractionalResolution, counter: u32) -> Option<Self> {
let div = fractional_res_to_div(resolution); let div = fractional_res_to_div(resolution);
if counter > div { if counter > div {
@ -211,17 +205,14 @@ impl FractionalPart {
}) })
} }
#[inline]
pub fn resolution(&self) -> FractionalResolution { pub fn resolution(&self) -> FractionalResolution {
self.resolution self.resolution
} }
#[inline]
pub fn counter(&self) -> u32 { pub fn counter(&self) -> u32 {
self.counter self.counter
} }
#[inline]
pub fn no_fractional_part(&self) -> bool { pub fn no_fractional_part(&self) -> bool {
self.resolution == FractionalResolution::Seconds self.resolution == FractionalResolution::Seconds
} }
@ -292,7 +283,6 @@ pub struct CucTimeWithLeapSecs {
} }
impl CucTimeWithLeapSecs { impl CucTimeWithLeapSecs {
#[inline]
pub fn new(time: CucTime, leap_seconds: u32) -> Self { pub fn new(time: CucTime, leap_seconds: u32) -> Self {
Self { time, leap_seconds } Self { time, leap_seconds }
} }
@ -308,7 +298,6 @@ pub fn pfield_len(pfield: u8) -> usize {
impl CucTime { impl CucTime {
/// Create a time provider with a four byte counter and no fractional part. /// Create a time provider with a four byte counter and no fractional part.
#[inline]
pub fn new(counter: u32) -> Self { pub fn new(counter: u32) -> Self {
// These values are definitely valid, so it is okay to unwrap here. // These values are definitely valid, so it is okay to unwrap here.
Self::new_generic( Self::new_generic(
@ -319,13 +308,11 @@ impl CucTime {
} }
/// Like [CucTime::new] but allow to supply a fractional part as well. /// Like [CucTime::new] but allow to supply a fractional part as well.
#[inline]
pub fn new_with_fractions(counter: u32, fractions: FractionalPart) -> Result<Self, CucError> { pub fn new_with_fractions(counter: u32, fractions: FractionalPart) -> Result<Self, CucError> {
Self::new_generic(WidthCounterPair(4, counter), fractions) Self::new_generic(WidthCounterPair(4, counter), fractions)
} }
/// Fractions with a resolution of ~ 4 ms /// Fractions with a resolution of ~ 4 ms
#[inline]
pub fn new_with_coarse_fractions(counter: u32, subsec_fractions: u8) -> Self { pub fn new_with_coarse_fractions(counter: u32, subsec_fractions: u8) -> Self {
// These values are definitely valid, so it is okay to unwrap here. // These values are definitely valid, so it is okay to unwrap here.
Self::new_generic( Self::new_generic(
@ -339,7 +326,6 @@ impl CucTime {
} }
/// Fractions with a resolution of ~ 16 us /// Fractions with a resolution of ~ 16 us
#[inline]
pub fn new_with_medium_fractions(counter: u32, subsec_fractions: u16) -> Self { pub fn new_with_medium_fractions(counter: u32, subsec_fractions: u16) -> Self {
// These values are definitely valid, so it is okay to unwrap here. // These values are definitely valid, so it is okay to unwrap here.
Self::new_generic( Self::new_generic(
@ -355,7 +341,6 @@ impl CucTime {
/// Fractions with a resolution of ~ 60 ns. The fractional part value is limited by the /// Fractions with a resolution of ~ 60 ns. The fractional part value is limited by the
/// 24 bits of the fractional field, so this function will fail with /// 24 bits of the fractional field, so this function will fail with
/// [CucError::InvalidFractions] if the fractional value exceeds the value. /// [CucError::InvalidFractions] if the fractional value exceeds the value.
#[inline]
pub fn new_with_fine_fractions(counter: u32, subsec_fractions: u32) -> Result<Self, CucError> { pub fn new_with_fine_fractions(counter: u32, subsec_fractions: u32) -> Result<Self, CucError> {
Self::new_generic( Self::new_generic(
WidthCounterPair(4, counter), WidthCounterPair(4, counter),
@ -470,7 +455,6 @@ impl CucTime {
/// Most generic constructor which allows full configurability for the counter and for the /// Most generic constructor which allows full configurability for the counter and for the
/// fractions. /// fractions.
#[inline]
pub fn new_generic( pub fn new_generic(
width_and_counter: WidthCounterPair, width_and_counter: WidthCounterPair,
fractions: FractionalPart, fractions: FractionalPart,
@ -490,38 +474,31 @@ impl CucTime {
}) })
} }
#[inline]
pub fn ccsds_time_code(&self) -> CcsdsTimeCode { pub fn ccsds_time_code(&self) -> CcsdsTimeCode {
CcsdsTimeCode::CucCcsdsEpoch CcsdsTimeCode::CucCcsdsEpoch
} }
#[inline]
pub fn width_counter_pair(&self) -> WidthCounterPair { pub fn width_counter_pair(&self) -> WidthCounterPair {
self.counter self.counter
} }
#[inline]
pub fn counter_width(&self) -> u8 { pub fn counter_width(&self) -> u8 {
self.counter.0 self.counter.0
} }
#[inline]
pub fn counter(&self) -> u32 { pub fn counter(&self) -> u32 {
self.counter.1 self.counter.1
} }
/// Subsecond fractional part of the CUC time. /// Subsecond fractional part of the CUC time.
#[inline]
pub fn fractions(&self) -> FractionalPart { pub fn fractions(&self) -> FractionalPart {
self.fractions self.fractions
} }
#[inline]
pub fn to_leap_sec_helper(&self, leap_seconds: u32) -> CucTimeWithLeapSecs { pub fn to_leap_sec_helper(&self, leap_seconds: u32) -> CucTimeWithLeapSecs {
CucTimeWithLeapSecs::new(*self, leap_seconds) CucTimeWithLeapSecs::new(*self, leap_seconds)
} }
#[inline]
pub fn set_fractions(&mut self, fractions: FractionalPart) -> Result<(), CucError> { pub fn set_fractions(&mut self, fractions: FractionalPart) -> Result<(), CucError> {
Self::verify_fractions_value(fractions)?; Self::verify_fractions_value(fractions)?;
self.fractions = fractions; self.fractions = fractions;
@ -531,7 +508,6 @@ impl CucTime {
/// Set a fractional resolution. Please note that this function will reset the fractional value /// Set a fractional resolution. Please note that this function will reset the fractional value
/// to 0 if the resolution changes. /// to 0 if the resolution changes.
#[inline]
pub fn set_fractional_resolution(&mut self, res: FractionalResolution) { pub fn set_fractional_resolution(&mut self, res: FractionalResolution) {
if res == FractionalResolution::Seconds { if res == FractionalResolution::Seconds {
self.fractions = FractionalPart::new_with_seconds_resolution(); self.fractions = FractionalPart::new_with_seconds_resolution();
@ -541,7 +517,6 @@ impl CucTime {
} }
} }
#[inline]
fn build_p_field(counter_width: u8, resolution: FractionalResolution) -> u8 { fn build_p_field(counter_width: u8, resolution: FractionalResolution) -> u8 {
let mut pfield = P_FIELD_BASE; let mut pfield = P_FIELD_BASE;
if !(1..=4).contains(&counter_width) { if !(1..=4).contains(&counter_width) {
@ -561,7 +536,6 @@ impl CucTime {
pfield pfield
} }
#[inline]
fn update_p_field_fractions(&mut self) { fn update_p_field_fractions(&mut self) {
self.pfield &= !(0b11); self.pfield &= !(0b11);
self.pfield |= self.fractions.resolution() as u8; self.pfield |= self.fractions.resolution() as u8;
@ -606,7 +580,6 @@ impl CucTime {
) )
} }
#[inline]
pub fn len_packed_from_pfield(pfield: u8) -> usize { pub fn len_packed_from_pfield(pfield: u8) -> usize {
let mut base_len: usize = 1; let mut base_len: usize = 1;
base_len += Self::len_cntr_from_pfield(pfield) as usize; base_len += Self::len_cntr_from_pfield(pfield) as usize;
@ -615,7 +588,6 @@ impl CucTime {
} }
/// Verifies the raw width parameter. /// Verifies the raw width parameter.
#[inline]
fn verify_counter_width(width: u8) -> Result<(), CucError> { fn verify_counter_width(width: u8) -> Result<(), CucError> {
if width == 0 || width > 4 { if width == 0 || width > 4 {
return Err(CucError::InvalidCounterWidth(width)); return Err(CucError::InvalidCounterWidth(width));
@ -623,7 +595,6 @@ impl CucTime {
Ok(()) Ok(())
} }
#[inline]
fn verify_fractions_value(val: FractionalPart) -> Result<(), CucError> { fn verify_fractions_value(val: FractionalPart) -> Result<(), CucError> {
if val.counter > 2u32.pow((val.resolution as u32) * 8) - 1 { if val.counter > 2u32.pow((val.resolution as u32) * 8) - 1 {
return Err(CucError::InvalidFractions { return Err(CucError::InvalidFractions {
@ -634,12 +605,10 @@ impl CucTime {
Ok(()) Ok(())
} }
#[inline]
fn len_as_bytes(&self) -> usize { fn len_as_bytes(&self) -> usize {
Self::len_packed_from_pfield(self.pfield) Self::len_packed_from_pfield(self.pfield)
} }
#[inline]
fn subsec_nanos(&self) -> u32 { fn subsec_nanos(&self) -> u32 {
if self.fractions.resolution() == FractionalResolution::Seconds { if self.fractions.resolution() == FractionalResolution::Seconds {
return 0; return 0;
@ -780,27 +749,22 @@ impl TimeWriter for CucTime {
} }
impl CcsdsTimeProvider for CucTimeWithLeapSecs { impl CcsdsTimeProvider for CucTimeWithLeapSecs {
#[inline]
fn len_as_bytes(&self) -> usize { fn len_as_bytes(&self) -> usize {
self.time.len_as_bytes() self.time.len_as_bytes()
} }
#[inline]
fn p_field(&self) -> (usize, [u8; 2]) { fn p_field(&self) -> (usize, [u8; 2]) {
(1, [self.time.pfield, 0]) (1, [self.time.pfield, 0])
} }
#[inline]
fn ccdsd_time_code(&self) -> CcsdsTimeCode { fn ccdsd_time_code(&self) -> CcsdsTimeCode {
self.time.ccsds_time_code() self.time.ccsds_time_code()
} }
#[inline]
fn unix_secs(&self) -> i64 { fn unix_secs(&self) -> i64 {
self.time.unix_secs(self.leap_seconds) self.time.unix_secs(self.leap_seconds)
} }
#[inline]
fn subsec_nanos(&self) -> u32 { fn subsec_nanos(&self) -> u32 {
self.time.subsec_nanos() self.time.subsec_nanos()
} }

View File

@ -33,7 +33,6 @@ pub const NANOS_PER_SECOND: u32 = 1_000_000_000;
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CcsdsTimeCode { pub enum CcsdsTimeCode {
CucCcsdsEpoch = 0b001, CucCcsdsEpoch = 0b001,
CucAgencyEpoch = 0b010, CucAgencyEpoch = 0b010,
@ -66,7 +65,6 @@ pub fn ccsds_time_code_from_p_field(pfield: u8) -> Result<CcsdsTimeCode, u8> {
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DateBeforeCcsdsEpochError(UnixTime); pub struct DateBeforeCcsdsEpochError(UnixTime);
impl Display for DateBeforeCcsdsEpochError { impl Display for DateBeforeCcsdsEpochError {
@ -80,7 +78,6 @@ impl Error for DateBeforeCcsdsEpochError {}
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub enum TimestampError { pub enum TimestampError {
InvalidTimeCode { expected: CcsdsTimeCode, found: u8 }, InvalidTimeCode { expected: CcsdsTimeCode, found: u8 },
@ -166,7 +163,6 @@ pub fn seconds_since_epoch() -> f64 {
/// ///
/// - CCSDS epoch: 1958-01-01T00:00:00+00:00 /// - CCSDS epoch: 1958-01-01T00:00:00+00:00
/// - UNIX Epoch: 1970-01-01T00:00:00+00:00 /// - UNIX Epoch: 1970-01-01T00:00:00+00:00
#[inline]
pub const fn unix_to_ccsds_days(unix_days: i64) -> i64 { pub const fn unix_to_ccsds_days(unix_days: i64) -> i64 {
unix_days - DAYS_CCSDS_TO_UNIX as i64 unix_days - DAYS_CCSDS_TO_UNIX as i64
} }
@ -175,19 +171,16 @@ pub const fn unix_to_ccsds_days(unix_days: i64) -> i64 {
/// ///
/// - CCSDS epoch: 1958-01-01T00:00:00+00:00 /// - CCSDS epoch: 1958-01-01T00:00:00+00:00
/// - UNIX Epoch: 1970-01-01T00:00:00+00:00 /// - UNIX Epoch: 1970-01-01T00:00:00+00:00
#[inline]
pub const fn ccsds_to_unix_days(ccsds_days: i64) -> i64 { pub const fn ccsds_to_unix_days(ccsds_days: i64) -> i64 {
ccsds_days + DAYS_CCSDS_TO_UNIX as i64 ccsds_days + DAYS_CCSDS_TO_UNIX as i64
} }
/// Similar to [unix_to_ccsds_days] but converts the epoch instead, which is the number of elpased /// Similar to [unix_to_ccsds_days] but converts the epoch instead, which is the number of elpased
/// seconds since the CCSDS and UNIX epoch times. /// seconds since the CCSDS and UNIX epoch times.
#[inline]
pub const fn unix_epoch_to_ccsds_epoch(unix_epoch: i64) -> i64 { pub const fn unix_epoch_to_ccsds_epoch(unix_epoch: i64) -> i64 {
unix_epoch - (DAYS_CCSDS_TO_UNIX as i64 * SECONDS_PER_DAY as i64) unix_epoch - (DAYS_CCSDS_TO_UNIX as i64 * SECONDS_PER_DAY as i64)
} }
#[inline]
pub const fn ccsds_epoch_to_unix_epoch(ccsds_epoch: i64) -> i64 { pub const fn ccsds_epoch_to_unix_epoch(ccsds_epoch: i64) -> i64 {
ccsds_epoch + (DAYS_CCSDS_TO_UNIX as i64 * SECONDS_PER_DAY as i64) ccsds_epoch + (DAYS_CCSDS_TO_UNIX as i64 * SECONDS_PER_DAY as i64)
} }
@ -269,7 +262,6 @@ pub trait CcsdsTimeProvider {
/// similarly to other common time formats and libraries. /// similarly to other common time formats and libraries.
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct UnixTime { pub struct UnixTime {
secs: i64, secs: i64,
subsec_nanos: u32, subsec_nanos: u32,

View File

@ -15,12 +15,10 @@ pub trait ToBeBytes {
impl ToBeBytes for () { impl ToBeBytes for () {
type ByteArray = [u8; 0]; type ByteArray = [u8; 0];
#[inline]
fn written_len(&self) -> usize { fn written_len(&self) -> usize {
0 0
} }
#[inline]
fn to_be_bytes(&self) -> Self::ByteArray { fn to_be_bytes(&self) -> Self::ByteArray {
[] []
} }
@ -29,12 +27,9 @@ impl ToBeBytes for () {
impl ToBeBytes for u8 { impl ToBeBytes for u8 {
type ByteArray = [u8; 1]; type ByteArray = [u8; 1];
#[inline]
fn written_len(&self) -> usize { fn written_len(&self) -> usize {
1 1
} }
#[inline]
fn to_be_bytes(&self) -> Self::ByteArray { fn to_be_bytes(&self) -> Self::ByteArray {
u8::to_be_bytes(*self) u8::to_be_bytes(*self)
} }
@ -43,12 +38,9 @@ impl ToBeBytes for u8 {
impl ToBeBytes for u16 { impl ToBeBytes for u16 {
type ByteArray = [u8; 2]; type ByteArray = [u8; 2];
#[inline]
fn written_len(&self) -> usize { fn written_len(&self) -> usize {
2 2
} }
#[inline]
fn to_be_bytes(&self) -> Self::ByteArray { fn to_be_bytes(&self) -> Self::ByteArray {
u16::to_be_bytes(*self) u16::to_be_bytes(*self)
} }
@ -57,12 +49,9 @@ impl ToBeBytes for u16 {
impl ToBeBytes for u32 { impl ToBeBytes for u32 {
type ByteArray = [u8; 4]; type ByteArray = [u8; 4];
#[inline]
fn written_len(&self) -> usize { fn written_len(&self) -> usize {
4 4
} }
#[inline]
fn to_be_bytes(&self) -> Self::ByteArray { fn to_be_bytes(&self) -> Self::ByteArray {
u32::to_be_bytes(*self) u32::to_be_bytes(*self)
} }
@ -71,12 +60,9 @@ impl ToBeBytes for u32 {
impl ToBeBytes for u64 { impl ToBeBytes for u64 {
type ByteArray = [u8; 8]; type ByteArray = [u8; 8];
#[inline]
fn written_len(&self) -> usize { fn written_len(&self) -> usize {
8 8
} }
#[inline]
fn to_be_bytes(&self) -> Self::ByteArray { fn to_be_bytes(&self) -> Self::ByteArray {
u64::to_be_bytes(*self) u64::to_be_bytes(*self)
} }
@ -118,7 +104,6 @@ pub enum UnsignedByteFieldError {
} }
impl From<ByteConversionError> for UnsignedByteFieldError { impl From<ByteConversionError> for UnsignedByteFieldError {
#[inline]
fn from(value: ByteConversionError) -> Self { fn from(value: ByteConversionError) -> Self {
Self::ByteConversionError(value) Self::ByteConversionError(value)
} }
@ -146,24 +131,20 @@ impl Error for UnsignedByteFieldError {}
/// Type erased variant. /// Type erased variant.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct UnsignedByteField { pub struct UnsignedByteField {
width: usize, width: usize,
value: u64, value: u64,
} }
impl UnsignedByteField { impl UnsignedByteField {
#[inline]
pub const fn new(width: usize, value: u64) -> Self { pub const fn new(width: usize, value: u64) -> Self {
Self { width, value } Self { width, value }
} }
#[inline]
pub const fn value_const(&self) -> u64 { pub const fn value_const(&self) -> u64 {
self.value self.value
} }
#[inline]
pub fn new_from_be_bytes(width: usize, buf: &[u8]) -> Result<Self, UnsignedByteFieldError> { pub fn new_from_be_bytes(width: usize, buf: &[u8]) -> Result<Self, UnsignedByteFieldError> {
if width > buf.len() { if width > buf.len() {
return Err(ByteConversionError::FromSliceTooSmall { return Err(ByteConversionError::FromSliceTooSmall {
@ -196,12 +177,10 @@ impl UnsignedByteField {
} }
impl UnsignedEnum for UnsignedByteField { impl UnsignedEnum for UnsignedByteField {
#[inline]
fn size(&self) -> usize { fn size(&self) -> usize {
self.width self.width
} }
#[inline]
fn value(&self) -> u64 { fn value(&self) -> u64 {
self.value_const() self.value_const()
} }
@ -241,7 +220,6 @@ impl UnsignedEnum for UnsignedByteField {
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GenericUnsignedByteField<TYPE: Copy + Into<u64>> { pub struct GenericUnsignedByteField<TYPE: Copy + Into<u64>> {
value: TYPE, value: TYPE,
} }
@ -257,7 +235,6 @@ impl<TYPE: Copy + Into<u64>> GenericUnsignedByteField<TYPE> {
} }
impl<TYPE: Copy + ToBeBytes + Into<u64>> UnsignedEnum for GenericUnsignedByteField<TYPE> { impl<TYPE: Copy + ToBeBytes + Into<u64>> UnsignedEnum for GenericUnsignedByteField<TYPE> {
#[inline]
fn size(&self) -> usize { fn size(&self) -> usize {
self.value.written_len() self.value.written_len()
} }
@ -273,7 +250,6 @@ impl<TYPE: Copy + ToBeBytes + Into<u64>> UnsignedEnum for GenericUnsignedByteFie
Ok(self.value.written_len()) Ok(self.value.written_len())
} }
#[inline]
fn value(&self) -> u64 { fn value(&self) -> u64 {
self.value_typed().into() self.value_typed().into()
} }
@ -299,7 +275,6 @@ impl From<UnsignedByteFieldU8> for UnsignedByteField {
impl TryFrom<UnsignedByteField> for UnsignedByteFieldU8 { impl TryFrom<UnsignedByteField> for UnsignedByteFieldU8 {
type Error = UnsignedByteFieldError; type Error = UnsignedByteFieldError;
#[inline]
fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> { fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> {
if value.width != 1 { if value.width != 1 {
return Err(UnsignedByteFieldError::InvalidWidth { return Err(UnsignedByteFieldError::InvalidWidth {
@ -312,7 +287,6 @@ impl TryFrom<UnsignedByteField> for UnsignedByteFieldU8 {
} }
impl From<UnsignedByteFieldU16> for UnsignedByteField { impl From<UnsignedByteFieldU16> for UnsignedByteField {
#[inline]
fn from(value: UnsignedByteFieldU16) -> Self { fn from(value: UnsignedByteFieldU16) -> Self {
Self::new(2, value.value as u64) Self::new(2, value.value as u64)
} }
@ -321,7 +295,6 @@ impl From<UnsignedByteFieldU16> for UnsignedByteField {
impl TryFrom<UnsignedByteField> for UnsignedByteFieldU16 { impl TryFrom<UnsignedByteField> for UnsignedByteFieldU16 {
type Error = UnsignedByteFieldError; type Error = UnsignedByteFieldError;
#[inline]
fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> { fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> {
if value.width != 2 { if value.width != 2 {
return Err(UnsignedByteFieldError::InvalidWidth { return Err(UnsignedByteFieldError::InvalidWidth {
@ -334,7 +307,6 @@ impl TryFrom<UnsignedByteField> for UnsignedByteFieldU16 {
} }
impl From<UnsignedByteFieldU32> for UnsignedByteField { impl From<UnsignedByteFieldU32> for UnsignedByteField {
#[inline]
fn from(value: UnsignedByteFieldU32) -> Self { fn from(value: UnsignedByteFieldU32) -> Self {
Self::new(4, value.value as u64) Self::new(4, value.value as u64)
} }
@ -343,7 +315,6 @@ impl From<UnsignedByteFieldU32> for UnsignedByteField {
impl TryFrom<UnsignedByteField> for UnsignedByteFieldU32 { impl TryFrom<UnsignedByteField> for UnsignedByteFieldU32 {
type Error = UnsignedByteFieldError; type Error = UnsignedByteFieldError;
#[inline]
fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> { fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> {
if value.width != 4 { if value.width != 4 {
return Err(UnsignedByteFieldError::InvalidWidth { return Err(UnsignedByteFieldError::InvalidWidth {
@ -356,7 +327,6 @@ impl TryFrom<UnsignedByteField> for UnsignedByteFieldU32 {
} }
impl From<UnsignedByteFieldU64> for UnsignedByteField { impl From<UnsignedByteFieldU64> for UnsignedByteField {
#[inline]
fn from(value: UnsignedByteFieldU64) -> Self { fn from(value: UnsignedByteFieldU64) -> Self {
Self::new(8, value.value) Self::new(8, value.value)
} }
@ -365,7 +335,6 @@ impl From<UnsignedByteFieldU64> for UnsignedByteField {
impl TryFrom<UnsignedByteField> for UnsignedByteFieldU64 { impl TryFrom<UnsignedByteField> for UnsignedByteFieldU64 {
type Error = UnsignedByteFieldError; type Error = UnsignedByteFieldError;
#[inline]
fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> { fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> {
if value.width != 8 { if value.width != 8 {
return Err(UnsignedByteFieldError::InvalidWidth { return Err(UnsignedByteFieldError::InvalidWidth {