Home > front end >  How to create CAN frame using SocketCAN interface in C using values larger and smaller than 8 bit
How to create CAN frame using SocketCAN interface in C using values larger and smaller than 8 bit

Time:12-10

I need to write three different CAN messages to a CAN bus. The first message consists of 8 values of 8 bits so no problem there but the second and third message are more irregular In the third message I have three values all with a size of 16bits and the third message has some values which are smaller than 8 bits. How can I properly create the data for the CAN frame using values larger or smaller than 8 bits.

This is my code

`

int main(int argc, char **argv)
{
    int s; 
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;
    struct can_frame frame2;

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

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

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

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

    frame.can_id = 0x500;
    frame.can_dlc = 8;
    frame.data[0] = 122;
    frame.data[1] = 150;
    frame.data[2] = -27;
    frame.data[3] = -22;
    frame.data[4] = 160;
    frame.data[5] = 160;
    frame.data[6] = -60;
    frame.data[7] = 90;

    frame2.can_id = 0x501;
    frame.can_dlc = 6;
    frame.data[0] = 32766;
    frame.data[2] = -32765;
    frame.data[4] = 20542;

    if (write(s, &frame, sizeof(struct can_frame)) != sizeof(struct can_frame)) {
        perror("Write");
        return 1;
    }

    if (close(s) < 0) {
        perror("Close");
        return 1;
    }

    return 0;
}

` Index 0 obviously corresponds to the first 8 bits of the data frame but I don't really know any other way to do this because I have very little experience with C

I would like to be able to make these CAN frames properly with the data on two indexes but have no clue how to do this. Aswell as a way to use single bits instead of 8 bits using the index of the frame.data object since I need to make a CAN message where multiple values exist in the single 8 bit data frame of the can message. If that makes sense

CodePudding user response:

First of all, you cannot do this unless you know the network endianess of the specific CAN bus. Big endian is the most common, but some CAN application layers like CANopen use little endian for the payload.

Assuming network = big endian, assuming 32766, -32765 and 20542 are your 16 bit numbers, then:

const int16_t data16[3] = { 32766, -32765, 20542 };
...
frame.data[0] = ((uint16_t)data16[0] >> 8) & 0xFFu;
frame.data[1] = ((uint16_t)data16[0] >> 0) & 0xFFu;
frame.data[2] = ((uint16_t)data16[1] >> 8) & 0xFFu;
frame.data[3] = ((uint16_t)data16[1] >> 0) & 0xFFu;
frame.data[4] = ((uint16_t)data16[2] >> 8) & 0xFFu;
frame.data[5] = ((uint16_t)data16[2] >> 0) & 0xFFu;

Or if you will:

for(size_t i=0; i<3; i  )
{
  frame.data[i*2]   = ((uint16_t)data16[i] >> 8) & 0xFFu;
  frame.data[i*2 1] = ((uint16_t)data16[i] >> 0) & 0xFFu;
}

Here the bit shifts are the same no matter if CPU is big/little endian, but you have to swap MS and LS bytes in case the network uses little endian.

  • Related