Linux socketCan Interrupthandler mehrere CANs

Gast #6396440
Hallo,
ich habe unter linux socket can (4 CAN-Nodes) implementiert.
wenn eine message reinkommt, rufe ich einen interrupt auf. Diese habe 
ich mit pthread erstellt.
1
    ret = pthread_create(&thread_id, NULL, (void*)pVCan1Rx, NULL);
2
    ret = pthread_create(&thread_id, NULL, (void*)pVCan2Rx, NULL);
3
    ret = pthread_create(&thread_id, NULL, (void*)pVCan3Rx, NULL);
4
    ret = pthread_create(&thread_id, NULL, (void*)pVCan4Rx, NULL);


die threads sehen dann wie folgt aus
1
void * pVCan1Rx(__attribute__((unused)) void * pData)
2
{
3
    int s, i;
4
    int nbytes;
5
    struct sockaddr_can addr;
6
    struct ifreq ifr;
7
    struct can_frame frame;
8

9
    uint16 msgHandle_u16 = 0;
10

11
    char *ifname = "vcan0";
12

13

14
    if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
15
        perror("Socket");
16
        return 1;
17
    }
18

19
    strcpy(ifr.ifr_name, ifname );
20
    ioctl(s, SIOCGIFINDEX, &ifr);
21

22
    memset(&addr, 0, sizeof(addr));
23
    addr.can_family = AF_CAN;
24
    addr.can_ifindex = ifr.ifr_ifindex;
25

26
    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
27
        perror("Bind");
28
        return 1;
29
    }
30

31
    while(1)
32
    {
33
        nbytes = read(s, &frame, sizeof(struct can_frame));
34

35
        printf("vcan1: ");
36
        fflush(stdout);
37

38
        if (nbytes < 0) {
39
            perror("Read");
40
            return 1;
41
        }
42

43
        printf("0x%03X [%d] ",frame.can_id, frame.can_dlc);
44
        fflush(stdout);
45

46
        for (i = 0; i < frame.can_dlc; i++)
47
        {
48
            printf("%02X ",frame.data[i]);
49
            fflush(stdout);
50
        }
51

52

53
    }
54

55
    printf("\r\n");
56

57
    if (close(s) < 0) {
58
        perror("Close");
59
        return 1;
60
    }
61

62
    return 0;
63
}

bis auf die Zeile char *ifname = "vcan0"; sehen diese alle gleich aus.

jetzt erstelle ich im Terminal vcan0 bis vcan4
Wenn ich jetzt eine Nachricht schicke, kommt diese auch im 
Interrupthandler an. Allerdings in allen.
Wo kann/muss ich es genau einstellen, dass Nachrichten von vcan0 nur in 
pVCan1Rx ankmomen?
Gast
Johannes schrieb:
> bis auf die Zeile char *ifname = "vcan0"; sehen diese alle gleich aus.

Für sowas hat pthread_create hinten das "void *arg" wenn die Threads 
identisch sind, dann schreibe den Code einmal und denke dir eine schöne 
Struktur aus um die Unterschiede per Parameter zu übergeben.

Johannes schrieb:
> jetzt erstelle ich im Terminal vcan0 bis vcan4
> Wenn ich jetzt eine Nachricht schicke, kommt diese auch im
> Interrupthandler an. Allerdings in allen.

Glückwunsch 50% Erfolg, aber mal ernsthaft, hast du den Return des ioctl 
mal überprüft?
1
ioctl(s, SIOCGIFINDEX, &ifr);

Wenn der schiefgeht ist, der Rest des Threads undefiniert, was zu dein 
beschrieben verhalten führen kann.
1
strcpy(ifr.ifr_name, ifname );
 das ist sicher ein Security-Issue, die, wenn ifname hinreichend lang 
ist gibt es ein Bufferoverflow, wie viele Bytes verträgt denn 
ifr.ifr_name?

der Teil ist Toter Code und kann nicht erreicht werden, da es nur ein 
return 1 die while(1) Schleife verlassen kann!
1
printf("\r\n");
2

3
if (close(s) < 0) {
4
perror("Close");
5
return 1;
6
}
7

8
return 0;

deine Funktionssignatur ist:
1
void * pVCan1Rx(__attribute__((unused)) void * pData);

Du gibst aber Int werte zurück, diese werden implizit auf Pointer 
gecastet, ein Pointer auf die Adresse 1 (return 1) ist aber Käse und 
führt im besten fall nur zu einem Coredump wenn jemand den Return wert 
weiter verwendet. Deine Fehlerbehandlung durch die Return Values ist 
daher komplett für die Tonne und sollte dringend überarbeitet werden.

Johannes schrieb:
> Wo kann/muss ich es genau einstellen, dass Nachrichten von vcan0 nur in
> pVCan1Rx ankmomen?

Es war schwer denn Code zu schreiben, also muss es schwer sein Ihn zu 
lesen!
Das ist für 3. eine fiese Falle, wenn du wirklich für jeden can eine 
eigene Funktion implementierst muss die für vcan0 auch pVCan0Rx heißen. 
C ist zerobased und alles andere sorgt nur für Verwirrung und bei 
hinreichend Komplexen Programmen dafür das die Programmierer falsche 
annahmen machen.

und Zuletzt, wenn du das Gefühl hast nach jeden Printf stdout zu 
flushen, solltest du Nachdenke ob printf dein Freund ist und/oder du mit 
tcsetattr() das Terminal nicht vielleicht besser auf unbufferd umstellen 
willst.
Johannes schrieb:
> bis auf die Zeile char *ifname = "vcan0"; sehen diese alle gleich aus.

Dann würde ich eine Funktion machen und ihr den ifname als Paramter 
übergeben. Woebei man hier nicht unbedingt vier Threads braucht. Du 
kannst auch alle vier CANs in einem Thread und mit einer Funktion lesen, 
wenn du select() oder poll() nutzt.

> Wenn ich jetzt eine Nachricht schicke, kommt diese auch im
> Interrupthandler an. Allerdings in allen.

Ich verstehe nicht, was du mit "Interrupthandler" meinst. Interrupts 
kommen in deinem Code überhaupt nicht vor.
Gast
Rolf M. schrieb:
> alle vier CANs in einem Thread und mit einer Funktion lesen,
> wenn du select() oder poll() nutzt.

Theoretisch nicht mal select oder poll aus 
https://www.kernel.org/doc/Documentation/networking/can.txt

  To bind a socket to all(!) CAN interfaces the interface index must
  be 0 (zero). In this case the socket receives CAN frames from every
  enabled CAN interface. To determine the originating CAN interface
  the system call recvfrom(2) may be used instead of read(2). To send
  on a socket that is bound to 'any' interface sendto(2) is needed to
  specify the outgoing interface.

Und danach dann mit recvfrom die Nachrichten lesen und fröhlich 
ausgeben. Aber ich glaube dann lernt der TO weniger, er hat sich halt 
für diesen Overengineering Ansatz entschieden und nun sollte er mal 
schön die Geister bändigen, die er gerufen hat.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.