2014-01-15 3 views
2

Я пишу программу, которая непрерывно отправляет «Hello» на CAN-шину и считывает данные с шины через SocketCAN. Я хочу, чтобы эти два шага были независимыми. Это означает, что даже если на шине нет данных, программа все равно отправит «Hello». Но с обычным считыванием CAN это невозможно, потому что эта функция останавливает запуск программы и ждет данных.SocketCAN непрерывное чтение и запись

Есть ли способ сделать это неблокирующим или ожидающим данных только на несколько миллисекунд?

ответ

2

Вы можете использовать следующие созвездия (это не полное решение, но только алгоритм):

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

См man select для получения дополнительной информации и как обрабатывать возвращаемое значение.

+3

Вам не нужно использовать 'select' для SocketCAN (хотя это не проблема, если вы это делаете); вы также можете использовать 'setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, & tv, sizeof (tv))' где 'tv' является' timeval' для тайм-аутов приема. Тогда 'read' будет терпеть неудачу с' EAGAIN', если истечет время ожидания. –

+0

@Jason C: Мне нравится ваше предложение, но это не сработало для меня: я пробовал, как описано выше, а также с «setsockopt (skt, SOL_CAN_RAW, SO_RCVTIMEO, ...», поскольку это показалось более вероятным, но в обоих случаях «read» call заблокирован навсегда, пока не появится кадр (без таймаута). – Jeremy

+0

К сожалению, моя ошибка ... из руководства по Linux для «socket»: «Если таймаут установлен на ноль (по умолчанию), то операция никогда не будет таймаутом . Я использовал таймаут 0 в надежде получить немедленное возвращение, если не было кадра для чтения. – Jeremy

3

Другой способ, который я нашел - потоки. Просто сделайте работу чтения CAN в потоке, и он не остановит основной цикл. Для систем Linux это выглядит следующим образом:

#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; 
    } 
+3

Кстати, вы можете использовать 'setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, & tv, sizeof (tv))' где 'tv' является' timeval', чтобы установить тайм-аут чтения. Тогда 'read' будет терпеть неудачу с' EAGAIN', если истечет время ожидания. Вы также можете использовать ['CAN_RAW_FILTER'] (https://www.kernel.org/ doc/Documentation/networking/can.txt), чтобы уменьшить нагрузку на обработку и фильтровать только интересующие вас фреймы. –

0

Будьте осторожны с этим решением:

void *thread(int cansock) { 
     struct can_frame rxmsg;  
     while (1) { 
      read(cansock, &rxmsg, sizeof(rxmsg)); 
      printf("message received\n");      
     } 
    } 

, потому что если прочитать() начинает возвращается ошибка без блока, и это в поле и там никого нет чтобы посмотреть результаты printf(), вы перейдете в цикл занятости.

+0

Возможно, это будет d лучше в качестве комментария к другому ответу; а не ответ сам по себе. Я знаю, что вы еще не можете комментировать - см. [Этот пост] (http://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i -do-вместо/214174 # 214174) для некоторых подробностей о том, что вы можете сделать в это время. –

Смежные вопросы