0

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?

spx305
  • 109
  • 2
  • 11

2 Answers2

0

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.

MSpiller
  • 3,500
  • 2
  • 12
  • 24
  • How can I be sure that bcm will start sending frame[4] exactly 100 ms after sending frames from 0 to 3? – spx305 May 14 '19 at 07:53
  • First, keep in mind, that there is nothing like _exactly_ in the context of the CAN bus. The bus has to be free for a message to be sent. Thus there will always be some deviations in the cycle time. For your case, you could wait until your first 4 frames are sent. The bcm will send you a message, once this is done. You can receive this message, by calling `read` or `select` on the socket in your variable `s`. This behaves like any other linux socket. For the format of the message sent to you by the bcm, you have to check the documentation. – MSpiller May 14 '19 at 08:45
0

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.

Tomo Česnik
  • 146
  • 2
  • 5