Struct flipdot_core::Frame
source · pub struct Frame<'a> { /* private fields */ }
Expand description
A low-level representation of an Intel HEX data frame.
The Luminator protocol uses the Intel HEX format but not its semantics.
This struct handles parsing the raw bytes into a form we can reason about,
dealing with checksums, and so forth. It makes no attempt to ascribe meaning
to the address, message type, and data (that’s Message
’s job).
Both owned and borrowed data are supported.
§Examples
use flipdot_core::{Address, Data, Frame, MsgType};
let frame = Frame::new(Address(2), MsgType(1), Data::try_new(vec![3, 31])?);
println!("Parsed frame is {}", frame);
let bytes = frame.to_bytes();
assert_eq!(b":02000201031FD9", bytes.as_slice());
let parsed = Frame::from_bytes(&bytes)?;
assert_eq!(parsed, frame);
§Format Details
The format consists of a leading colon, several numeric fields (two-character ASCII representations
of hex bytes), and a final carriage return/linefeed terminator. Note that for convenience,
Frame
allows omitting the final CRLF sequence.
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬ ┄ ┬────┬────┬────┬────┬────┬────┐
│ : │ DataLen │ Address │ MsgType │ Data 0 │...│ Data N │ Chksum │ \r │ \n │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴ ┄ ┴────┴────┴────┴────┴────┴────┘
└╌╌╌╌╌╌╌╌╌╌╌╌╌ # of ╌╌╌╌╌╌╌╌╌╌╌╌╌> ┆ Data bytes ┆
The DataLen
field describes how many two-character data byte sequences are present.
Note that since it is represented as a single byte, the data length cannot exceed 255 (0xFF
).
If DataLen
is 0, there are no data bytes, and MsgType
is followed directly by Chksum
.
The checksum is a longitudinal redundancy check calculated on all numeric fields.
Implementations§
source§impl<'a> Frame<'a>
impl<'a> Frame<'a>
sourcepub fn new(address: Address, message_type: MsgType, data: Data<'a>) -> Self
pub fn new(address: Address, message_type: MsgType, data: Data<'a>) -> Self
Constructs a new Frame
with the specified address, message type, and data.
§Examples
// some_data is moved into owning_frame.
let some_data = vec![1, 2, 3];
let owning_frame = Frame::new(Address(0xB), MsgType(0xA), Data::try_new(some_data)?);
// other_data is borrowed.
let other_data = vec![1, 2, 3];
let borrowing_frame = Frame::new(Address(0xD), MsgType(0xC), Data::try_new(other_data.as_slice())?);
sourcepub fn message_type(&self) -> MsgType
pub fn message_type(&self) -> MsgType
Returns the message type of the frame.
§Examples
let frame = Frame::new(Address(1), MsgType(1), Data::try_new(vec![])?);
match frame.message_type() {
MsgType(1) => println!("Message 1"),
_ => println!("Something else"),
}
sourcepub fn address(&self) -> Address
pub fn address(&self) -> Address
Returns the address of the frame.
§Examples
let frame = Frame::new(Address(1), MsgType(1), Data::try_new(vec![])?);
if frame.address() == Address(3) {
println!("This frame is addressed to me!");
}
sourcepub fn data(&self) -> &Cow<'a, [u8]>
pub fn data(&self) -> &Cow<'a, [u8]>
Returns a reference to the frame’s data.
§Examples
let frame = Frame::new(Address(1), MsgType(1), Data::try_new(vec![10, 20])?);
if (frame.data().as_ref() == &[10, 20]) {
println!("Found the expected data!");
}
sourcepub fn into_data(self) -> Data<'a>
pub fn into_data(self) -> Data<'a>
Consumes the frame and returns ownership of its data.
§Examples
let frame = Frame::new(Address(1), MsgType(1), Data::try_new(vec![6, 7])?);
let frame2 = Frame::new(Address(2), MsgType(2), frame.into_data());
sourcepub fn to_bytes(&self) -> Vec<u8>
pub fn to_bytes(&self) -> Vec<u8>
Converts the frame to its wire format, without trailing carriage return/linefeed.
§Examples
let frame = Frame::new(Address(2), MsgType(1), Data::try_new(vec![3, 31])?);
let bytes = frame.to_bytes();
assert_eq!(b":02000201031FD9", bytes.as_slice());
sourcepub fn to_bytes_with_newline(&self) -> Vec<u8>
pub fn to_bytes_with_newline(&self) -> Vec<u8>
Converts the frame to its wire format, including trailing carriage return/linefeed.
§Examples
let frame = Frame::new(Address(2), MsgType(1), Data::try_new(vec![3, 31])?);
let bytes = frame.to_bytes_with_newline();
assert_eq!(b":02000201031FD9\r\n", bytes.as_slice());
sourcepub fn from_bytes(bytes: &[u8]) -> Result<Self, FrameError>
pub fn from_bytes(bytes: &[u8]) -> Result<Self, FrameError>
Parses the Intel HEX wire format into a new Frame
.
§Errors
Returns:
FrameError::InvalidFrame
if the data does not conform to the Intel HEX format.FrameError::FrameDataMismatch
if the actual number of data bytes does not match the specified amount.FrameError::BadChecksum
if the computed checksum on the data does not match the specified one.
§Examples
let bytes = b":02000201031FD9\r\n";
let frame = Frame::from_bytes(&bytes[..])?;
assert_eq!(Frame::new(Address(2), MsgType(1), Data::try_new(vec![3, 31])?), frame);
sourcepub fn write<W: Write>(&self, writer: &mut W) -> Result<(), FrameError>
pub fn write<W: Write>(&self, writer: &mut W) -> Result<(), FrameError>
Writes the byte representation (including CRLF) of the frame to a writer.
§Errors
Returns FrameError::Io
if the write fails.
§Examples
let mut port = serial::open("COM3")?;
let frame = Frame::new(Address(2), MsgType(1), Data::try_new(vec![3, 31])?);
frame.write(&mut port)?;
sourcepub fn read<R: Read>(reader: &mut R) -> Result<Self, FrameError>
pub fn read<R: Read>(reader: &mut R) -> Result<Self, FrameError>
Reads the next line (up to \n
) from the reader and converts the result
into a new Frame
.
§Errors
Returns:
FrameError::Io
if the read fails.FrameError::InvalidFrame
if the data does not conform to the Intel HEX format.FrameError::FrameDataMismatch
if the actual number of data bytes does not match the specified amount.FrameError::BadChecksum
if the computed checksum on the data does not match the specified one.
§Examples
let mut port = serial::open("COM3")?;
let frame = Frame::read(&mut port)?;
Trait Implementations§
source§impl<'a> From<Frame<'a>> for Message<'a>
impl<'a> From<Frame<'a>> for Message<'a>
source§fn from(frame: Frame<'a>) -> Self
fn from(frame: Frame<'a>) -> Self
Converts a Frame
into a Message
.
This cannot fail as all valid Frame
s are representable as Message
s (though perhaps Unknown
).
The input Frame
is consumed to allow efficiently reusing its data where possible.
§Examples
let frame = Frame::new(Address(0x12), MsgType(4), Data::try_new(vec![0x07])?);
let message = Message::from(frame);
assert_eq!(Message::ReportState(Address(0x12), State::ConfigReceived), message);
source§impl<'a> From<Message<'a>> for Frame<'a>
impl<'a> From<Message<'a>> for Frame<'a>
source§fn from(message: Message<'a>) -> Self
fn from(message: Message<'a>) -> Self
Converts a Message
into a Frame
.
This cannot fail as all Message
s can be represented as Frame
s.
The input Message
is consumed to allow efficiently reusing its data where possible.
§Examples
let message = Message::ReportState(Address(0xFF), State::ConfigReceived);
let frame = Frame::from(message);
assert_eq!(Frame::new(Address(0xFF), MsgType(4), Data::try_new(vec![0x07])?), frame);