-
Notifications
You must be signed in to change notification settings - Fork 201
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
Controller Area Network (CAN) Take 3 #212
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @thejpster (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
Hey! I am just dropping by I am taking up Rust and I was thinking that I would do CAN layer for embedded-hal since I have quite some encounter with CAN on embedded, but I see I come a bit late. But now looking at it I was thinking wouldn't it make sense to have some generic timing structure akin to what is in Linux kernel: The idea is that struct as If this is not done then setting timing will be a a bit bypass of HAL layer because the values are specific for each CAN IP core.. I saw that timing was discussed before, but is a bit different way of doing it.. its not implementing anything directly, only defining the interface common to both CAN driver and an application siting on top of embedded-hal this way the drivers can provide concise way to show timing capabilities while application layer can use those to set the timing. |
I added traits for receive filter configuration. There is quite some variation between CAN controllers:
I tried to cover all those configurations with an interface that exposes capabilities similar to the approach that @josko7452 described for timing. @josko7452 Regarding the bit timings I’m not quite sure if they are in scope of
Usually the system integrator configures the bit timings. I would consider bit timing configuration to be part of the init procedure in (6). |
Yes I have seen that ASCII graphics. My point is that I don't know whose scope that would be otherwise. To me if you are an init procedure in (6) you would only like to pass something generic to the driver which all drivers understand rather than having to deal at (6) which register sets what.. That's the point of the driver to abstract the register accesses or am I wrong? And this is exactly what
The driver can take this and translate it to IP core specific registers that set what this describes. I am not saying there is need to include this calculation in embedded-hal this can be done elsewhere (even application layer, or pre-calculated constants), but what is needed is a concise interface to set the timing. Also by these examples I am not saying we should copy what is in the Linux kernel. Just for completness this is how these structs are used: As you can see it doesn't add a lot of burden to the driver. What it does is that instead of having And then when you would port your application from one CAN HW to another you wouldn't need to replace your init function in (6) for the CAN HW, because it would still apply (be it constants or a function that calculates If there is another place where such a generic interface can be defined for all CAN drivers then I welcome the suggestions. |
Rebased to resolve the conflict in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks great. I'd probably though also go for only the "Non-Filter" part so only the first commit. Just for the sake of getting a standard interface quicker.
I implemented this here in a fork of the socketcan
crate.
My observations were:
- I had to unwrap() when creating the CanFrame because the identifier may be too large to fit into the frame u32 > 29bit for EFF and u32 > 11bit for SFF. So I assume it's probably a good idea to make both
new_extended
andnew_standard
return aResult
. - Unable to implement
with_rtr
without modification, I assume this is not really critical. - The Ok return type documentation for Transmitter::transmit was a little unclear to me. I assume the returned frame would be one with lower priority already in the buffer right?
- Maybe add a
is_err_frame
fn, not sure about this though. id
innew_standard
could beu16
Thank you for the comments and suggestions!
Makes sense looking at your socketcan implementation. I did not put a
socketcan should be able to support this. The rust wrapper should be extended with a method to set that bit.
You understood that correctly: The returned frame is the one with the lowest priority of all pending messages. As a non-native speaker I’m glad to take suggestions for better a description. |
Wondering what's up with this PR? Looking forward to having this available... |
Hey @timokroeger, You might be asked to rename several trait methods with the I noticed this while trying to submit a PR in linux-embedded-hal... complicates things a little. Thoughts? |
@thejpster I'm guessing a) you got lots on your plate or b) you're out on vacation and very intoxicated (hope it's b)... looking forward to getting your input. Seems to me like adding CAN support would be a pretty big deal, and Timo's implementation is very solid. |
I'm on holidays. Give me another week to write a summary about the state of this pull request und outstanding changes/ideas. |
Gotcha. Enjoy your off-time and stay safe. |
Added New requirementsProtocol libraries like UAVCAN are the intended consumers of the CAN traits.
I’m not sure if it possible to add TX deadlines in nice generic way (SocketCAN for example cannot implement it). RX timestamps, in contrast, can IMO easily be added with a Combine
|
I think adding |
# Conflicts: # src/lib.rs
Changes
@marcelbuesing I’m hesitant to add the |
Please have a good look at the blocking traits! I’m not overly confident, because I’m not fully familiar with the pattern yet. Example blocking trait implementations and usages: |
Well it seem mostly analogous to the serial implementation, although serial seems to add a Regarding the timestamp, not sure what the policy is regarding dependencies. Maybe this could be put behind a feature flag making the dependency to embedded-time optional.
Yes I assume you are right, it might be a little inconvenient but it probably makes more sense this way. Btw. not really relevant but since I mostly worked with a Socketcan so far, I'd consider naming the fns |
I'm attempting to use the fork for an ISOTP implementation but I'm stuck with Error not enforcing being std::fmt::Debug. Any ideas ;)? use thiserror::Error as ThisError;
#[derive(ThisError, Debug)]
pub enum Error<TCan> where TCan: Can, <TCan as Can>::Error: std::fmt::Debug {
// ...
#[error("CAN error")]
Can(#[from] TCan::Error),
}
|
@marcelbuesing |
What do you think about starting with a seperate crate for can traits for now? That way it could already be used by other crates. |
Great idea! The traits now live at: https://github.com/timokroeger/embedded-can and there is a v0.1 release on crates.io |
Use `try_read()` / `try_write()` as suggested by @marcelbuesing
Use newtypes for the enum variants so they cannot be constructed anymore. Implement the `From` trait for the variants to access the id value as integer. timokroeger/embedded-can#7
Just want to point out that @timokroeger 's crate has 39,887 downloads. I think that's a pretty clear indicator that CAN support should be included here. |
Here an update about the changes that have happened
It is great to see these traits have so many users and 2 implementations. I would welcome these traits on
|
Appreciate you looking into this @eldruin. Timo's implementation has matured over time. @timokroeger Why did you switch the 'Id' trait to an actual implementation? The one piece I'm really not crazy about are the constructors. If the value is out of range, shouldn't that be an error? Take 4? :) |
Thank you bringing the PR to my attention again. @reneherrero I still have to catch up #296 on the error handling. If we have concrete error types I agree that it might make sense for the |
314: Controller Area Network (CAN) Take 4 r=eldruin a=timokroeger Updated to the latest HAL changes: * Removed `try_` prefix * Moved non-blocking implementation to `nb` module * Removed default `blocking` implementaions ## Usage Example [stm32-fwupdate](https://github.com/timokroeger/pcan-basic-rs/blob/eh-take-4/pcan-basic/examples/stm32-fwupdate.rs) ## Implementations Updated for this PR: * [pcan-basic](https://github.com/timokroeger/pcan-basic-rs/blob/eh-take-4/pcan-basic/src/lib.rs) on top of an existing software API * [bxcan](https://github.com/timokroeger/bxcan/blob/eh-take-4/src/lib.rs#L460) Based on the very similar predecessor traits `embedded-can` v0.3 ([diff v0.3 -> this PR](https://github.com/timokroeger/embedded-can/compare/eh-take-4)) * [candev](https://github.com/reneherrero/candev) implementing the traits for linux SocketCAN * [socketcan-isotc](https://github.com/marcelbuesing/socketcan-isotp) ## Previous Discussion * #212 * #77 * #21 * #53 Co-authored-by: Timo Kröger <timokroeger93@gmail.com>
Closed by take 4 in #314. |
Usage Example
stm32-fwupdate
Prototype Implementations
TODOs for seperate PRs
FilteredReceiver
and associated traits ref (open a new PR without them)Previous Discussion