converted legacy hard coded test cases for frame to rstest in the #zmodem 2 crate:
#[cfg(test)]
mod tests {
use crate::frame::*;
#[rstest::rstest]
#[case(Encoding::ZBIN, Type::ZRQINIT, &[ZPAD, ZLDE, Encoding::ZBIN as u8, 0, 0, 0, 0, 0, 0, 0])]
#[case(Encoding::ZBIN32, Type::ZRQINIT, &[ZPAD, ZLDE, Encoding::ZBIN32 as u8, 0, 0, 0, 0, 0, 29, 247, 34, 198])]
fn test_header(
#[case] encoding: Encoding,
#[case] frame_type: Type,
#[case] expected: &[u8]
) {
let header = Header::new(encoding, frame_type);
let mut packet = vec![];
new_frame(&header, &mut packet);
assert_eq!(packet, expected);
}
#[rstest::rstest]
#[case(Encoding::ZBIN, Type::ZRQINIT, &[1, 1, 1, 1], &[ZPAD, ZLDE, Encoding::ZBIN as u8, 0, 1, 1, 1, 1, 98, 148])]
#[case(Encoding::ZHEX, Type::ZRQINIT, &[1, 1, 1, 1], &[ZPAD, ZPAD, ZLDE, Encoding::ZHEX as u8, b'0', b'0', b'0', b'1', b'0', b'1', b'0', b'1', b'0', b'1', 54, 50, 57, 52, b'\r', b'\n', XON])]
fn test_header_with_flags(
#[case] encoding: Encoding,
#[case] frame_type: Type,
#[case] flags: &[u8; 4],
#[case] expected: &[u8]
) {
let header = Header::new(encoding, frame_type).flags(flags);
let mut packet = vec![];
new_frame(&header, &mut packet);
assert_eq!(packet, expected);
}
}
Should be easier to refactor the legacy code now as there is less raw code that might be affected in tests.
I hope I got this right (safety-proprty), i.e. so that references are enforced to have equal life-time:
impl<'a> From<&'a Header> for &'a [u8] {
fn from(value: &Header) -> Self {
// SAFETY: out-of-boundary is not possible, given that the size constraint
// exists in the struct definition. The lifetime parameter links the lifetime
// of the header reference to the slice.
unsafe { from_raw_parts((value as *const Header) as *const u8, size_of::<Header>()) }
}
}
great implemented transmutable (with u8) enum for the frame type of the #ZMODEM transfer protocol header: https://github.com/jarkkojs/zmodem2/commit/c76316c2ecae097be03506e8ce19d61287e6468a
I can use this as a reference model for refactoring rest of the code base.
Next, I’ll replace encoding: u8 with a similar enum Encoding .
After trial and error, i.e. brute force going through crc crate algorithms, I can say that CRC32_32_ISO_HDLC is the correct variant for ZMODEM 32-bit transfers, i.e. cipher can be acquired by:
const CRC32: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
It is better to declare like this so that it gets compiled into .rodata and not initialized at run-time.
I really like this heapless. It sort of helps to implement my strategy for developing Rust programs:
1.Maximize no_std surface. 2 Minimize heap allocations.
It is easier to see then the hot zones where the program actually dynamically grows for a good reason, similarly as with unsafe blocks it is easy to the red zones for memory errors. This helps a lot with availability and protection against denial-of-service (DoS) attacks.
So to summarize I don’t split Rust program in my mind just to “unsafe” and “safe” but instead I split it “unsafe”, “static” and “dynamic”, or along the lines.
really like this fsmetry crate (also no_std):
fsmentry::dsl! {
#[derive(Debug)]
pub Mode {
WaitingInput -> WaitingCommand -> WaitingInput;
WaitingCommand -> SendingFile -> WaitingInput;
WaitingCommand -> ReceivingFile -> WaitingInput;
WaitingCommand -> Exit;
}
}
I use it manage life-cycle in my small serial port tool tior. I also have some #zmodem code together but it is apparently much bigger leap to implement the #cli interface than it is to implement the protocol. I had to take some time to refactor existing code (e.g. to put FSM in place) and now I’m doing file path auto-completing interface for sending and receiving files with zmodem.
For the text input I’m going to use inquire.
I guess the definition of feature complete for 0.1 version is fully working zmodem transfers and known bugs have been fixed. Right now there is a single known bug: https://github.com/jarkkojs/tior/issues/1.
I wonder if #BeagleV has similar #DIP switch as #VisionFive2, which works as a selector for different boot modes?
In VisionFive2 you can choose to:
These VisionFive2 e.g. pretty capable board for prototyping CPU extensions.