-
Notifications
You must be signed in to change notification settings - Fork 639
Relax restriction of arbitration ID uniqueness for SocketCAN #785
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Conversation
Codecov Report
@@ Coverage Diff @@
## develop #785 +/- ##
===========================================
+ Coverage 69.50% 69.58% +0.07%
===========================================
Files 70 70
Lines 6556 6565 +9
===========================================
+ Hits 4557 4568 +11
+ Misses 1999 1997 -2 |
GLOBAL_TASK_ID = 0 | ||
TASK_LOCK = threading.Lock() |
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.
Instead of making this global, perhaps consider storing this on the Bus
context since we map 1:1 to a SocketCAN bus. This is because the kernel code matches based on the combination of:
- Task ID (
op->can_id
) - Interface (
op->ifindex
) - Flags (
op->flags
)
/*
* helpers for bcm_op handling: find & delete bcm [rx|tx] op elements
*/
static struct bcm_op *bcm_find_op(struct list_head *ops,
struct bcm_msg_head *mh, int ifindex)
{
struct bcm_op *op;
list_for_each_entry(op, ops, list) {
if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
(op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME))
return op;
}
return NULL;
}
(Taken from the 5.5.7 kernel)
I think this should be doable if we expand the socketcan.CyclicTask
to take an ID argument in __init__
. Thoughts?
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.
This looks good to me. I am thinking about adding a member function to SocketcanBus
class that returns next task ID, incrementing old one. The result of that function passed to CyclicSendTask::__init__
as an additional argument. I will try that.
with TASK_LOCK: | ||
global GLOBAL_TASK_ID | ||
GLOBAL_TASK_ID += 1 | ||
return GLOBAL_TASK_ID |
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.
We will want to also ensure that we don't overflow the canid_t
type, on the off-chance that someone is running this for extended periods of time and repeatedly starting/stopping periodic TX tasks.
typedef __u32 canid_t;
Ensuring that we wrap at 2^11 - 1
is probably sufficient for now.
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.
Thanks, good catch. It looks to be an unsigned integer though, thus wrapping is required at 2^32 - 1
, isn't it?
Considering this accidental case, some of the previous tasks IDs can be used already, wouldn't it better still implement usage of CAN_BCM_TX_READ
to check if they are busy or not?
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.
When I commented, I wasn't sure if the kernel code was doing anything with anything beyond the 11-bits (ie. checking other bits for various flags in the 32-bits) so I just said 11-bits to be safe to avoid any potential unintended side effects.
Looking more closely through the kernel code now, it seems like for TX Tasks, this value is only copied (for things other than the TX Task ID) when TX_CP_CAN_ID
is set as part of flags
on the BCM message. The only places it's used for determining behaviour is when dealing with RX tasks, but they're stored in separate lists so they won't affect each other (and python-can
currently doesn't support this).
But yes, you're right, it should be safe to increase this to 32-bits.
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.
Considering this accidental case, some of the previous tasks IDs can be used already, wouldn't it better still implement usage of CAN_BCM_TX_READ to check if they are busy or not?
Yes, let's do that. If we detect that the TX ID has been used, let's just raise an Exception, and make it explicit for the user to decide whether to retry calling bus.send_periodic
.
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.
Done
|
||
# The second one raises a ValueError when we attempt to create a new | ||
# Task, since it has the same arbitration ID. | ||
with self.assertRaises(ValueError): |
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 test could probably be repurposed to ensure that we receive both messages, rather than throwing an exception.
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.
Modified this test.
return task | ||
|
||
def _get_next_task_id(self) -> int: | ||
self._task_id = (self._task_id + 1) % (2 ** 11 - 1) |
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 believe you still need mutual exclusion around the task_id
since access to the Bus
via send_periodic
isn't serialized. I think we assume that send_periodic
can be called concurrently.
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 am not really sure in that. There is ThreadSafeBus, but I don't really understand whether it serializes access to periodic messages sending. Anyway, I've added a guard.
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.
LGTM % the missing documentation comment. Thanks for working on this!
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.
This is looking really solid. 🚀
Do you mind updating the interfaces/socketcan
and bcm
documentation too?
I thought about that too. No problem. I would be happy to update if you point out what you want to add into existing documentation. Note please that those changes are not user-visible, public API hasn't changed. But I could add some description that clarifies internals, though. Is that what you want? |
Awesome thanks, clarifying the internal behavior is what I was thinking. But you are now in the best position to check that the docstrings are still accurate e.g. |
I did few more changes to Sphinx docs if you don't mind along with other updates to docstrings. |
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.
🌟 for extra doc updates. Thank you for improving python-can!
References #721
I am unsure about the correct way to make a unique identifier. Please, suggest.