C - Sending cyclic message on socketCAN's broadcast manager

1.4k Views Asked by At

I'm writing some messages on a CAN bus using socketcan's broadcast manager:

struct bcm_message{
    struct bcm_msg_head msg_head;
    struct can_frame frame[5];
};

int main(){
    int s;
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct bcm_message msg;     
    s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);
    strcpy(ifr.ifr_name, "can1");
    ioctl(s, SIOCGIFINDEX, &ifr);
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    connect(s, (struct sockaddr *)&addr, sizeof(addr));

    msg.msg_head.opcode  = TX_SETUP;
    msg.msg_head.can_id  = 0x180;
    msg.msg_head.flags   = SETTIMER|STARTTIMER|TX_CP_CAN_ID;
    msg.msg_head.nframes = 5;
    msg.msg_head.count = 5;
    msg.msg_head.ival1.tv_sec = 0;
    msg.msg_head.ival1.tv_usec = 100000;
    msg.msg_head.ival2.tv_sec = 0;
    msg.msg_head.ival2.tv_usec = 0;
    msg.frame[0].can_dlc=8;
    memcpy(msg.frame[0].data,(__u8[]){0x00,0x28,0xFF,0x00,0x00,0x01,0xFF,0x00},8);
    msg.frame[1].can_dlc=8;
    memcpy(msg.frame[1].data,(__u8[]){0x00,0x32,0xFF,0x00,0x00,0x01,0xFF,0x00},8);
    msg.frame[2].can_dlc=8;
    memcpy(msg.frame[2].data,(__u8[]){0x00,0x3C,0xFF,0x00,0x00,0x01,0xFF,0x00},8);
    msg.frame[3].can_dlc=8;
    memcpy(msg.frame[3].data,(__u8[]){0x00,0x46,0xFF,0x00,0x00,0x01,0xFF,0x00},8);
    msg.frame[4].can_dlc=8;
    memcpy(msg.frame[4].data,(__u8[]){0x00,0x50,0xFF,0x00,0x00,0x01,0xFF,0x00},8);

    write(s, &msg, sizeof(msg));
    while(1){}
return 0;
}

This code works properly and simply sends the five messages once with an interval of 100ms, but it's not what I want. I want send the five messages (from frame[0] to frame[4]) once, then continue sending only the last frame (frame[4]) always with an interval of 100ms. So bcm should send:

frame[0]
frame[1] 
frame[2] 
frame[3] 
frame[4] 
frame[4] 
frame[4] 
frame[4] 
....
....

If i set iva2.tv_usec to 100000 it will continue sending all the frames, while i want to send only the last. How could I do this? I've read that adding the TX_COUNTEVT flag, the bcm will generate a TX_EXPIRED message when count reaches the zero. Maybe i can handle this TX_EXPIRED message and manually modify the bcm transmission as i need? And just if in case, how and where can I handle this TX_EXPIRED message? Is there another simplier way to reach my aim?

2

There are 2 best solutions below

0
On

You first need to send one BCM message with the content for frames 0 to 3. In this message you need to configure SETTIMER, STARTTIMER and TX_COUNTEVT. When you receive TX_EXPIRED message, just send another BCM message with only frame 4, and with only SETTIMER flag set (and the same timing configuration). This will not restart the timer and will continue sending with just the new data.

2
On

You have to split your msg into two instances to bcm_message.

In the first one, you configure your frames 0 to 3. SETTIMER and STARTTIMER are not really necessary if you want these messages to be sent only once.

In the second instance, you just configure what is frame[4] in your code. Then you can set iva2.tv_usec which will only apply to that frame.