Search code examples
cmaskingcan-bussocketcan

Unclear as to why first digit of hex value is appearing as a +8 version of itself. SocketCAN


Task

I wanted to write my own smaller version of candump. The aim being that it's similar in nature but with the only feature being that I would like to show only the incoming message from one CAN ID.

Code

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <linux/can.h>
#include <linux/can/raw.h>

int
main(void) {

    int s;
    int nbytes;
    struct sockaddr_can addr;
    struct can_frame frame;
    struct ifreq ifr;
//  struct can_filter *rfilter; // how do work?

    const char *ifname = "vcan0";

    if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
        perror("Error while opening socket");
        return -1;
    }

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

    addr.can_family  = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;

    if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("Error in socket bind");
        return -2;
    }

    nbytes = read(s, &frame, sizeof(struct can_frame));

    if(nbytes < 0) {
        perror("Error reading from socket.\n");
        return 1;
    }

    while(1) {
        if(read(s, &frame, sizeof(struct can_frame)) > 0) {
            //printf("Message...\n");
            printf("%X - [len] - %X %X %X %X %X %X %X %X\n", frame.can_id,
                frame.data[0], frame.data[1], frame.data[2], frame.data[3], 
                frame.data[4], frame.data[5], frame.data[6], frame.data[7]);
        }
    }

    close(s);

    return 0;
}

Problem

I've been using cansend with the command cansend vcan0 18DA40F1#1234. When running my code the response I get back is almost there apart from the first character in the CAN ID being a value 8+ bigger. Response 98DA40F1 - [len] - 12 34 0 0 0 0 0 0 I get back running my code.

Looking at the source code of previously mentioned candump I think it's something to do with rfilter but I'm not 100% sure and checking the SocketCAN documentation it doesn't feel much clearer. Is it something to do with masking? An example of how to solve my problem would be appreciated. Feel free to ask questions if there's anything you feel I've not mentioned.


Solution

  • From SocketCAN - The official CAN API of the Linux kernel p.05-21:

    “can_id” is 32 bit wide, holding the CAN id in the lower 11 bit. An extended CAN id is indicated by a set “CAN_EFF_FLAG” flag, the CAN id then covers the lower 29 bits. An RTR frame is signaled by the “CAN_RTR_FLAG” flag. “can_dlc” defines the number of used data bytes in the CAN frame, The payload of 8 bytes is located in the “data” array.

    So the 29-LSB of 98DA40F1 is 18DA40F1. The values of CAN_EFF_FLAG and CAN_RTR_FLAG are 0x80000000U and 0x20000000U respectively. In your case CAN_EFF_FLAG is set indicating a 29 nit extended ID.

            printf("%X - [len] - %X %X %X %X %X %X %X %X\n", 
                   frame.can_id & 0x1fffffffu,  // 29 bit CAN ID
                   frame.data[0], frame.data[1], frame.data[2], frame.data[3], 
                   frame.data[4], frame.data[5], frame.data[6], frame.data[7]);