shared-bus icon indicating copy to clipboard operation
shared-bus copied to clipboard

Can bus suppport?

Open codytrey opened this issue 2 years ago • 5 comments

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).

codytrey avatar Mar 19 '22 18:03 codytrey

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 :)

Rahix avatar Mar 21 '22 21:03 Rahix

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.

codytrey avatar Mar 22 '22 03:03 codytrey

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...

Rahix avatar Mar 22 '22 21:03 Rahix

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.

codytrey avatar Mar 23 '22 16:03 codytrey

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?

Rahix avatar Mar 24 '22 07:03 Rahix