Posts
4963
Following
329
Followers
494
Linux kernel hacker and maintainer etc.

OpenPGP: 3AB05486C7752FE1

Jarkko Sakkinen

trivial to get my #zmodem crate heapless with the `tinyvec` crate: https://github.com/jarkkojs/zmodem2/commit/6494028c3970c2c9f769643dac0e33c31a103fff

Still a few locations using heap but they are not more complicated than these sites :-)

As for "async" goes I think I just have a function to run one cycle of the state machine as it is fairly clean that way. It should be pretty easy then to wrap whatever framework is used around.

I.e. have start_send and next_send instead of just send and such and so forth. The way zmodem splits stuff that ZDATA subpackets fits well to this scheme. I should probably learn the language level async scheme but I see no point complicating this. I'm sure a framework using that can easily wrap a state machine.

#rustlang
0
0
2

Jarkko Sakkinen

Edited 2 years ago

One thing that I had to dig up from previous #Enarx work was core::marker::PhantomData. It is not so well known but pretty important concept inside Rust.

PhantomData is a zero-sized struct that merely acts as a life-time indicator for the other parameter, which are usually pointers on where it is applied. It is used to implement many of the core structs such as Rc to name one instance.

It is pretty good lesson on how lifetime parameters interact with the Rust compiler.

I’d even say that if you understand PhantomData, then you have the basic understanding of Rust, and if not, you still have to learn a bit. It is the block that the whole core library is based on after all.

#rustlang

0
0
1

I’d actually recommend to do few exercises with just from_raw_parts and lifetime parameters before using zerocopy because that sort of gives you full tutorial on what that particular crate does internally :-) I sort of enjoy thinking of those scenarios so it also takes some fun away :-)

0
0
1
Also this the Rust tutorial I wish I had found when I first started working on with Rust: https://google.github.io/comprehensive-rust/.

It is far better than any e.g. book I've ever seen on the topic of Rust.

At least this is by fart the best tutorial if you already have strong C/C++ and perhaps assembly background. Any books that I've ever read on Rust, well I've stop reading latest on chapter 2 because they have incredibly boring. This is really good hands on engineering material if you already sort of have understanding already topics such as memory management etc.
1
0
2

Jarkko Sakkinen

All the crates that #Google has done for #Rust seem to be like stuff I’ve been looking for to get better control of the memory.

Especially zerocopy is a time saver as it has all the thinkable stuff that I have used previously core::slice::from_raw_parts and spent a lot of time thinking of all the possible safety scenarios, such as this recent one:

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>()) }
    }
}

Previously I’ve had to do similar consideration in the #Enarx project. You can do these by hand but it is nice to have a common crate, which is tested by many for these risky scenarios.

Other mentionable crate from Google is tinyvec, which I’m going to use in zmodem2 to remove internal heap usage.

1
0
1
@regehr Other than that I appreciate a lot a book called Embedded Linux Primer. It has all the essential pieces of Linux kernel binary de-construction and power on (initcalls, kernel command-line etc.).
0
0
1
@regehr Linkers and loader is by far the best and it has depth, and is just a great piece of text. And still fully valid. The more recent books are pretty dull compared to it, and more like tool guides than great prose.
1
0
2

Jarkko Sakkinen

Edited 2 years ago
I also have my own minicom etc. alike tool in early phases but do not yet want to advertise it too much:

https://github.com/jarkkojs/tior

The whole point starting to do this was to have a serial tool with great zmodem feature. Since a suitable crate did not exist I had to halt that and start working on this one.

Of course also for this pull requests are welcome. And I can promise to commit maintaining for some time as these are tools that I've needed in my work pretty much my whole career.

For text editors and email there's been always a great tool existing like vim and mutt for instance. For serial port, it was a downgrade to move on from MS-DOS to Linux, as minicom does not really compare to telex or telemate. And to this day there's nothing nearly as good as there were even for good old DOS.
0
0
0
So if you are interested of actually enabling ZMODEM for the Rust ecosystem and various applications dealing with ttyS, I'm open for contributions :-) I could see e.g. https://github.com/hacknus/serial-monitor-rust adapting this eventually. #rustlang
1
0
0
I made bunch of high-level issues to draw an idea what are my sort of immediate goals with this work so that it is easier to contribute given some (not too restrictive) goals have been set: https://github.com/jarkkojs/zmodem2/issues
1
0
0

Jarkko Sakkinen

1
0
0

My crate has the implementation now in 933 lines and not a lot of dependencies. It starts to be in a shape that is not a huge stretch to make it fully no_std even. Not the first priority tho but entirely possible.

After I have a similar state function for the receiver I’ll look at futures crate, which claims to be no_std compatible. I.e. idea would be to get yield once per iteration.

I’m not interested in async stuff for multi-threading. I’m interested single-threaded sequenced type of stuff, co-operative multitasking…

0
0
0

Jarkko Sakkinen

Edited 2 years ago

This should clarify how it is organized:

/// Map the previous frame type of the sender and incoming frame type of the
/// receiver to the next packet to be sent.
///
/// NOTE: ZRINIT is used here as a wait state, as the sender does not use it for
/// other purposes. Other than tat the states map to the packets that the sender
/// sends next.
const fn next_state(sender: Option<Type>, receiver: Type) -> Option<Type> {
    match (sender, receiver) {
        (None, Type::ZRINIT) => Some(Type::ZFILE),
        (None, _) => Some(Type::ZRQINIT),
        (Some(Type::ZRQINIT), Type::ZRINIT) => Some(Type::ZFILE),
        (Some(Type::ZFILE), Type::ZRPOS) => Some(Type::ZDATA),
        (Some(Type::ZFILE), Type::ZRINIT) => Some(Type::ZRINIT),
        (Some(Type::ZRINIT), Type::ZRPOS) => Some(Type::ZDATA),
        (Some(Type::ZDATA), Type::ZACK) => Some(Type::ZDATA),
        (Some(Type::ZDATA), Type::ZRPOS) => Some(Type::ZDATA),
        (Some(Type::ZDATA), Type::ZRINIT) => Some(Type::ZFIN),
        (Some(Type::ZFIN), Type::ZFIN) => None,
        (_, _) => None,
    }
}

No reason to add complexity with fsmentry. This is a nice clean const function.

1
0
0

Jarkko Sakkinen

#zmodem2 is a nice history lesson to develop:

    style: cleanup and fix cosmetic stuff

    1. This inherits from original `zmodem` crate: "ZLDE" is in-fact ZDLE,
       an acronym of "ZMODEM Data Link Escape" character.
    2. Fine-tune use statements.

    Link: https://wiki.synchro.net/ref:zmodem
    Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@iki.fi>

That link in the commit message is a great source of information on #zmodem.

#rustlang

0
0
1

After looking that for some time my state diagram for “sz” is simply this:

fsmentry::dsl! {
    #[derive(Debug)]
    pub Mode {
        WaitingForReceiver -> Starting;
        Starting -> Sending;
        Starting -> WaitingForPosition;
        Sending -> WaitingForPosition;
        WaitingForPosition -> Sending;
        Sending -> Ending;
    }
}

This is scales exactly of the normal serial transfer. ZCHALLENGE/ZCOMPL, “corporate zmodem” (yes it was a real concept back in the say) and running commands by the request of the sender are definitely out of scope. So pretty clean and understandable in the end when you carve deep enough…

1
0
0
Moving file through the serial post is tricky, not because of protocols but because mostly it is based on launching rz and sz. This indirection makes impossible to implement an user experience that people used to transferring file such as showing progress, canceling the transfer and such and so forth. I'm fed up with this difficulty so that's where the motivation comes from.
1
0
0

Jarkko Sakkinen

Edited 2 years ago
I was going to use `fsmentry` crate for the state machine but then i ended up to something way more simpler: https://github.com/jarkkojs/zmodem2/commit/86a4af491448cf30a718a43dd1e5998b5b1863c6
1
0
0

Jarkko Sakkinen

next step in my zmodem2 crate is to make send and receive asynchronous so that progress can be tracked. then i’m ready to integrate this to my other small project, tior. #zmodem #rustlang

1
1
3
@Dr_Emann Yeah, I was not doing that because I can but because I had to :-) Good lesson anyway with the type system, learned a lot even though the snippet is only few lines.
0
0
0
@Dr_Emann This was a good tip. I want to refactor this as a zero-copy thing overally but doing these primitives takes time because you really have to think through, I was going to add cast from bytes next. Saves time!
1
0
0
Show older