Skip to main content

CemiFrame

Struct CemiFrame 

Source
pub struct CemiFrame { /* private fields */ }
Expand description

A cEMI L_Data frame around 1 group telegram: what the frame is, the 2 control field octets, the telegram itself, and any additional-info block.

The control octets are held as octets, not as decoded flags - a frame that arrived keeps what its sender wrote there, and the marks this layer acts on have their own accessors. Self::encode emits them as held, with the single exception of the frame-type mark, which it corrects where the payload is too wide for a standard frame to state.

Implementations§

Source§

impl CemiFrame

Source

pub const DEFAULT_CONTROL1: u8 = 0xBC

The control field a frame carries unless its payload needs the extended form. Bit 7 set marks the standard frame type.

Source

pub const DEFAULT_CONTROL2_GROUP: u8 = 0xe0

The second control field a constructor-built group frame carries. Bit 7 set marks the destination as a group address rather than an individual one, the next 3 bits are the hop count, set to 6, and the low 4 bits state the extended frame format, 0 for a group frame.

Source

pub fn new(message_code: CemiMessageCode, telegram: GroupTelegram) -> Self

Builds a frame around a telegram, choosing the frame type its payload requires.

The standard frame type states its length in 4 bits, so it cannot carry a payload past that; anything wider is marked extended. The choice follows the encoded length alone - this layer reads no datapoint declaration - and this entry point takes no frame-type argument. A frame marked otherwise reaches this type through Self::decode.

Source

pub const fn is_standard_frame(&self) -> bool

Whether this frame is marked as the standard frame type.

This reports the mark the frame holds, which for a decoded frame is the one its sender wrote. Self::encode emits that mark as held, except around a payload too wide for the standard frame type to state, where it emits the extended mark instead.

Source

pub const fn confirmation(&self) -> Option<ConfirmStatus>

What the server reports about the transmission it confirmed, or None where this frame is not a confirmation.

The status lives in the control field, which a request and an indication also carry - so the message code decides whether the bit means anything, and this answers None rather than reporting a bit that does not.

Source

pub fn with_confirmation(self, status: ConfirmStatus) -> Result<Self>

Returns the frame stating the outcome a server reports for the transmission it performed.

A server states this; a client never does. The flag is defined on an L_Data.con alone, so this refuses on any other message code rather than setting a bit that carries no meaning there - the same rule Self::confirmation reads it back through.

Source

pub fn group_value_read( source: IndividualAddress, destination: GroupAddress, ) -> Result<Self>

Builds a group-value read request: the service that asks a group’s senders to state their value.

The read is the 1 group service that carries no data, so unlike its response and write siblings this takes no payload and leaves the caller no transmitted form to choose.

Source

pub fn group_value_response( source: IndividualAddress, destination: GroupAddress, payload: GroupPayload, ) -> Result<Self>

Builds a group-value response frame around an already-formed payload.

This is a frame constructor, not a datapoint entry point: the caller states the transmitted form, having decided it where the datapoint’s declared width is known.

Source

pub fn group_value_write( source: IndividualAddress, destination: GroupAddress, payload: GroupPayload, ) -> Result<Self>

Builds a group-value write frame around an already-formed payload.

The same frame-constructor contract as Self::group_value_response.

Source

pub const fn message_code(&self) -> CemiMessageCode

What the frame is, as its first octet states it.

Source

pub const fn control1(&self) -> u8

The first control field octet as the frame holds it. For a decoded frame that is the octet its sender wrote, uninterpreted; the 2 marks this layer reads out of it have their own accessors, Self::is_standard_frame and Self::confirmation.

Source

pub const fn control2(&self) -> u8

The second control field octet as the frame holds it, uninterpreted. It carries the address type, the hop count, and the extended frame format; a constructor-built frame states Self::DEFAULT_CONTROL2_GROUP.

Source

pub const fn telegram(&self) -> &GroupTelegram

The group telegram this frame carries.

Source

pub fn additional_info(&self) -> &[u8]

Opaque cEMI additional-info bytes (empty for constructor-built frames).

Source

pub fn with_additional_info( self, additional_info: impl Into<Vec<u8>>, ) -> Result<Self>

Returns the frame with the given opaque additional-info block.

The cEMI additional-info length is a single octet, so the block must be at most 255 bytes; longer input is rejected with KnxError::InvalidFrame("additional info too long").

Source

pub fn decode(input: &[u8]) -> Result<(Self, &[u8])>

Decodes a frame, preserving the control field exactly as it arrived.

A received frame keeps the frame type its sender chose, even where that contradicts its own length octet: this layer is strict about what it emits and faithful about what it reports, so a peer’s malformed control field is visible rather than silently normalized.

That fidelity is the control field’s, and stating it of the whole frame would be false. The APDU has 1 malformed shape this layer does not carry forward: a group read whose APDU is 2 octets and whose service octet sets the 6 bits a well-formed read leaves clear. Those bits are dropped, the payload decodes as GroupPayload::None, and re-encoding emits a clean service octet rather than the one that arrived - the decoded frame cannot hold them, because a read carrying data is not a representable telegram here. The wider malformed reads are refused instead: an APDU longer than 2 octets is rejected for setting those bits, or for carrying a payload at all.

Nothing in this workspace re-transmits a decoded frame, so no shipped path puts that difference on the bus. A consumer that needs the octets a peer actually sent must keep the input; a re-encode is not a copy of it.

Source

pub fn encode(&self, out: &mut Vec<u8>) -> Result<()>

Encodes the frame, deriving what the frame states about its own shape.

One thing here is derived rather than carried: the NPDU length, which is the encoded APDU’s own width. The control field is emitted as held, with one exception. The constructor is not the only way a frame comes into being - a decoded frame keeps whatever its sender marked - so a frame can hold the standard mark around a payload no standard frame can state. That mark is cleared here, through control1_with_frame_type, so such a frame cannot leave this layer. Every other control bit, the extended mark included, is emitted exactly as given.

What cannot be derived is refused instead: a telegram whose payload contradicts its service is rejected by the APDU encoding rather than repaired.

Trait Implementations§

Source§

impl Clone for CemiFrame

Source§

fn clone(&self) -> CemiFrame

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for CemiFrame

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for CemiFrame

Source§

impl PartialEq for CemiFrame

Source§

fn eq(&self, other: &CemiFrame) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for CemiFrame

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.