Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asynchronous embedded-hal traits roadmap #356

Closed
5 of 8 tasks
eldruin opened this issue Feb 10, 2022 · 14 comments
Closed
5 of 8 tasks

Asynchronous embedded-hal traits roadmap #356

eldruin opened this issue Feb 10, 2022 · 14 comments

Comments

@eldruin
Copy link
Member

eldruin commented Feb 10, 2022

We have started a project to develop a asynchronous versions of the embedded-hal traits, at the moment championed by @Dirbaio.
This will be developed as a separate crate called embedded-hal-async until it is ready for integration inside a module in embedded-hal.
This can be found in the subfolder embedded-hal-async

Roadmap:

Asynchronous execution holds great potential for embedded. Please join us!

@adamgreig
Copy link
Member

Would it be worth cutting a 0.1.0-alpha (or just 0.1.0) release with the existing I2C, SPI etc async traits, while Serial is worked out?

Given the higher complexity I also expect CAN might take a while longer to figure out than the others, so at least getting the basic traits onto crates.io would let people start using them without git dependencies.

@kalkyl
Copy link

kalkyl commented May 23, 2022

Could we have an alpha 1 release of this? I have a pending PR for embassy that depends on the new SPI transaction API in master. Cheers!

@quentinmit
Copy link

I've started trying to port some of my code over to embedded-hal-async, and I'm wondering if you have any guidance for how device driver crates should be ported. It's not a great story if we tell everyone they have to maintain two copies of every function, where the ~only difference is async and .await sprinkled in one of them.

I'm wondering if there might be a procedural macro solution that would allow a single device driver to be compiled in both blocking and async modes. Has anyone explored that? Or is it more trouble than it's worth and we expect crates to quickly move over to the new traits? (Presumably that's blocked on the necessary features hitting stable.)

@Dirbaio
Copy link
Member

Dirbaio commented Jul 9, 2022

there's a blocking to "fake async" adapter that you can use to get an async impl out of any HAL with only a blocking impl. It's "fake async" because it will block and never "async yield", but for many use cases that's fine (spi/i2c register reads/writes are fast).

This allows maintaining just one version of the driver (async) but still using it with HALs that don't support async.

You still need an "executor", but since there's no yielding/waking going on a very dumb one like loop { fut.poll() } is enough (roughly same idea as nb::block!()), so it should still be very lightweight.

@quentinmit
Copy link

I saw that adapter, but I feel like you wouldn't want to do "async only" until both these traits are stable and they can be compiled with stable Rust, and probably an fut::block!() macro that mirrors nb:block!() exists for people who are not using async.

@ryankurte
Copy link
Contributor

I'm wondering if there might be a procedural macro solution that would allow a single device driver to be compiled in both blocking and async modes. Has anyone explored that?

i've spent way more time than i should have trying to achieve this with traits with no real success (though radio is kinda neat in that our higher-level blocking traits automagically become async)... definitely interested in whether we can do useful things with proc macros without too much magic (tm).

Or is it more trouble than it's worth and we expect crates to quickly move over to the new traits?

i don't think we can expect folks to all move to async (or vice versa), so the story for compatibility and combining the two seems fairly important!

@quentinmit
Copy link

I'm wondering if there might be a procedural macro solution that would allow a single device driver to be compiled in both blocking and async modes. Has anyone explored that?

i've spent way more time than i should have trying to achieve this with traits with no real success (though radio is kinda neat in that our higher-level blocking traits automagically become async)... definitely interested in whether we can do useful things with proc macros without too much magic (tm).

I started writing something like this and then I discovered the maybe-async-cfg crate already does pretty much exactly what I was thinking of.

I was able to very easily adapt my async device driver into something that compiles both sync and async versions side-by-side. I don't quite love the user ergonomics (it generates types named FooSync and FooAsync to keep them separate; I think it would be better if they could just be generated in two different modules, so the user would only have to change a use statement to swap between them, but then the problem is that async is a reserved identifier and use device::r#async::Device is not a great UX either.)

@ryankurte Maybe take a look at that crate and see what you think?

@kalkyl
Copy link

kalkyl commented Jul 18, 2022

I was able to very easily adapt my async device driver into something that compiles both sync and async versions side-by-side. I don't quite love the user ergonomics (it generates types named FooSync and FooAsync to keep them separate; I think it would be better if they could just be generated in two different modules, so the user would only have to change a use statement to swap between them, but then the problem is that async is a reserved identifier and use device::r#async::Device is not a great UX either.)

I think the accepted naming convention for async modules is asynch :)

@elpiel
Copy link

elpiel commented Jun 12, 2023

Hello everyone,
I'm joining this conversation to see the progress of the issue.
It seems that there are still a few things missing (to my understanding) in order to release a stable version of the async traits, however, there is one thing that can be done additionally:

Digital Pin (input, output, etc.) in the async hal should be added, until the traits get merged inside the embedded-hal, until then we still have to rely on embedded-hal for the async versions when dealing with digital pins.

@madsmtm
Copy link

madsmtm commented Nov 21, 2023

Discussion point from #177:

Should embedded-hal-async be merged back into embedded-hal, now that async fn in traits are stable? And if so, how do we best do that?

@madsmtm
Copy link

madsmtm commented Nov 21, 2023

Another thing: Is embedded-hal-nb still useful, or should it be deprecated now that we can do async things in stable?

@Dirbaio
Copy link
Member

Dirbaio commented Nov 25, 2023

my personal opionion is we should deprecate it (i.e never release embedded-hal-nb 1.0), but it's up to the HAL team as a whole to decide... It was discussed a while back and the conclusion was "don't deprecate, or at least not yet". Perhaps now that stable AFIT is here it's worth a second discussion?

@jessebraham
Copy link
Member

For what it's worth, I never encountered a library that actually implements the embedded-hal-nb traits in the wild. Most of the dependent packages are HALs, based on what's published at least.

@eldruin
Copy link
Member Author

eldruin commented Jan 9, 2024

embedded-hal-async 1.0.0 has now been released.
Thank you so much to everyone that was worked and helped through all this time to make this a reality.
🎉

@eldruin eldruin closed this as completed Jan 9, 2024
@eldruin eldruin unpinned this issue Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants