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

Can bus suppport? #32

Open
codytrey opened this issue Mar 19, 2022 · 5 comments
Open

Can bus suppport? #32

codytrey opened this issue Mar 19, 2022 · 5 comments

Comments

@codytrey
Copy link

Is there anything that would prevent adding support for can bus? If not and this would be a welcome addition I'll plan to start working on it as it would be useful in my own project(s).

@Rahix
Copy link
Owner

Rahix commented Mar 21, 2022

Hi,

is there an existing generic trait crate for CAN bus (I vaguely remember seeing one at some point)? If yes, it would of course be great to also support it here. You're welcome to send a PR :)

@codytrey
Copy link
Author

codytrey commented Mar 22, 2022

That's great to hear! I've got a theoretically working implementation that I plan to test tomorrow if the work day is slow. One issue I know of now is that embedded-hal-mock doesn't currently support can. If not having tests is an issue, it doesn't look like like it should be too hard to add can support there too.

@Rahix
Copy link
Owner

Rahix commented Mar 22, 2022

If not having tests is an issue, it doesn't look like like it should be too hard to add can support there too.

Of course tests would be great but in this case I don't think we're missing too much without the tests here...

@codytrey
Copy link
Author

After some more testing it seems non-trivial to add support for can bus because while embedded-hal does have a generic trait for it, the hal crates that implement it (stm32f1xx-hal at least, as that's the only one I'm currently able to test) also depend on bxcan and the bxcan::Can trait would also need to be implemented.

There's also a more fundamental issue of how to handle can frames received for other device drivers while the bus is being used another device driver. I can think of a few ways to handle that, but are probably out of scope for this crate.

  1. Implement bxcan::Can for BusProxy and allow setting the bus filter bank when mutex is locked.
    • this is probably a bad idea as it will cause frames for the other devices to be ignored (It's completely valid for a periodic status frame from device X to be received while sending frames to/receiving frames from device Y)
  2. Write all received frames to a buffer, have the BusProxy read from the buffer with logic to filter out frames from other devices
    • this has a lot of over head and I could see it having scenarios that are unsound
  3. Not using a shared bus, and writing can device drivers to produce and consume frames leaving the user to implement to the handling of the can interface.

@Rahix
Copy link
Owner

Rahix commented Mar 24, 2022

Fair warning, my experience with CAN is very limited...

I think I see the problem. Arbitrating Can::transmit() would be "easy" as its contract states that it should block until the frame is written. But Can::receive() is essentially impossible without additional logic and buffering because we need to make sure the right messages reach the right receiving code. That said, even the naive implementation for Can::transmit() would be suboptimal because it blocks unnecessarily, which probably makes it infeasible for a lot of usecases as well.

So I agree that shared-bus probably doesn't fit CAN... What we need is something smarter, a kind of routing layer with an interface similar to the one in Linux (the only reference I have here ^^): https://www.kernel.org/doc/html/latest/networking/can.html

I.e. client code can create an arbitrary number of sockets with different filters and the routing layer does the right thing with incoming frames (any maybe even set the hardware filter to the union of all socket's filters where possible).

What comes to mind is the smoltcp crate which implements socket networking for tcp/udp/ip. I think its design is quite well thought out and works quite nicely for embedded systems. Maybe copying the design pattern from there into a can-routing crate would be a good idea. The crate then consumes an embedded_hal::can::nb::Can and routes frames between multiple socket clients which are connected to it.

What do you think?

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

2 participants