C - Отправка циклического сообщения диспетчеру вещания socketCAN

Я пишу несколько сообщений по CAN-шине с помощью диспетчера трансляций socketcan:

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;
}

Этот код работает правильно и просто отправляет пять сообщений один раз с интервалом в 100 мс, но это не то, что я хочу. Я хочу отправить пять сообщений (от кадра [0] до кадра [4]) один раз, а затем продолжить отправку только последнего кадра (кадр [4]) всегда с интервалом 100 мс. Итак, bcm должен отправить:

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

Если я установлю для iva2.tv_usec значение 100000, он продолжит отправку всех кадров, а я хочу отправлять только последние. Как я мог это сделать? Я читал, что добавив флаг TX_COUNTEVT, bcm сгенерирует сообщение TX_EXPIRED, когда счетчик достигнет нуля. Может быть, я смогу обработать это сообщение TX_EXPIRED и вручную изменить передачу bcm по мере необходимости? И на всякий случай, как и где я могу обработать это сообщение TX_EXPIRED? Есть ли другой более простой способ достичь моей цели?


person spx305    schedule 10.05.2019    source источник


Ответы (2)


Вы должны разделить свой msg на два экземпляра, чтобы bcm_message.

В первом вы настраиваете фреймы от 0 до 3. SETTIMER и STARTTIMER на самом деле не нужны, если вы хотите, чтобы эти сообщения отправлялись только один раз.

Во втором случае вы просто настраиваете то, что frame[4] в вашем коде. Затем вы можете установить iva2.tv_usec, который будет применяться только к этому кадру.

person M. Spiller    schedule 13.05.2019
comment
Как я могу быть уверен, что bcm начнет отправлять фрейм [4] ровно через 100 мс после отправки фреймов от 0 до 3? - person spx305; 14.05.2019
comment
Во-первых, имейте в виду, что в контексте шины CAN нет ничего похожего на в точности. Для отправки сообщения автобус должен быть свободным. Таким образом, всегда будут некоторые отклонения во времени цикла. В вашем случае вы можете подождать, пока не будут отправлены первые 4 кадра. Как только это будет сделано, bcm отправит вам сообщение. Вы можете получить это сообщение, вызвав read или select на сокете в вашей переменной s. Он ведет себя как любой другой сокет Linux. Чтобы узнать формат сообщения, отправляемого вам bcm, вы должны проверить документацию. - person M. Spiller; 14.05.2019

Сначала вам нужно отправить одно сообщение BCM с содержимым для кадров от 0 до 3. В этом сообщении вам необходимо настроить SETTIMER, STARTTIMER и TX_COUNTEVT. Когда вы получаете сообщение TX_EXPIRED, просто отправьте другое сообщение BCM только с кадром 4 и только с установленным флагом SETTIMER (и такой же конфигурацией синхронизации). Это не приведет к перезапуску таймера и продолжит отправку только с новыми данными.

person Tomo Česnik    schedule 08.05.2020