SocketCAN continuous reading and writing
Solution 1
You can use following constellation (this is not the complete solution, but just algorithm):
while(1) {
FD_ZERO(&rdfs);
FD_SET(s, &rdfs);
tv.tv_sec = 0;
tv.tv_usec = 10000; // microseconds
rc = select(s + 1, &rdfs, NULL, NULL, &tv);
// rc == 0 - timeout
if (!rc) {
// write your CAN frame
}
if (FD_ISSET(s, &rdfs)) {
// read CAN frames
}
}
See man select for more information and how to handle return value.
Solution 2
Another way I found - threads. Just make CAN reading work in thread and it won't stop main cycle. For Linux systems it looks like this:
#include <pthread.h>
void *thread(int cansock) {
struct can_frame rxmsg;
while (1) {
read(cansock, &rxmsg, sizeof(rxmsg));
printf("message received\n");
}
}
int main(){
// initialize CAN socket and message to send
pthread_t pth;
pthread_create(&pth, NULL, thread, cansock);
while(1){
write(cansock, &txmsg, sizeof(txmsg));
printf("message sent\n");
}
return 0;
}
Solution 3
Be careful with this solution:
void *thread(int cansock) {
struct can_frame rxmsg;
while (1) {
read(cansock, &rxmsg, sizeof(rxmsg));
printf("message received\n");
}
}
because if read() starts returning an error without block, and this is out in the field and there's nobody to look at the results of printf(), you're going into a busy loop.
Solution 4
I solved it by add the following code on initialization
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 10000;
setsockopt(skt_, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
and add the loop read
in another thread.
Comments
-
PaulPonomarev almost 2 years
I'm writing a program that continuously sends "Hello" to a CAN-bus and reads data from the bus via SocketCAN. I want those two steps to be independent. That means even if there is no data on the bus, the program will still send "Hello". But with usual CAN reading it is impossible, because this function stops program run and waits for data.
Is there a way how to make it non-blocking or waiting for data only for a few milliseconds?
-
Jason C about 10 yearsYou don't have to use
select
for SocketCAN (although it's not a problem at all if you do); you can also usesetsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))
wheretv
is atimeval
for receive timeouts. Thenread
will fail withEAGAIN
if the timeout expires. -
Jason C about 10 yearsBy the way, you can use
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))
wheretv
is atimeval
to set the read timeout. Thenread
will fail withEAGAIN
if the timeout expires. You can also useCAN_RAW_FILTER
to reduce processing overhead and filter only the frames you are interested in. -
Tim Malone almost 8 yearsThis probably would be better as a comment on the other answer; rather than an answer in itself. I know you can't comment yet - see this post for some details on what you can do in the meantime.
-
Jeremy over 6 years@Jason C: I like your suggestion, but it didn't work for me: I tried as above and also with "setsockopt(skt, SOL_CAN_RAW, SO_RCVTIMEO,..." since this seemed more likely, but in both cases the "read" call blocked forever until a frame arrived (no timeout).
-
Jeremy over 6 yearsOops, my mistake... from the linux manual for "socket": "If the timeout is set to zero (the default) then the operation will never timeout." I was using a timeout of 0 in the hope of getting an immediate return if there was no frame to read.