0

I want to measure the maximum speed at which I can send messages via SocketCan from one Raspberry Pi (sender) using PiCan2 to another Raspberry Pi (recipient). The sender reads a 20KiB file, then each byte is sent separately via CAN. The recipient reads the message and saves it on their side to a file. Then I compare if both files are the same.

Initially, I used sleep () and typed the delay from sending each frame.

Then I sent a message and waited for a reply in the form of an empty frame, after which I sent another message.

Now I wanted to use the msg_flags flag and read MSG_CONFIRM to check if the message was delivered, but it doesn't work properly.

How can I read the MSG_CONFIRM flag? Is there another way to send messages as quickly as possible without taking up all of the buffer space and without losing some of the messages?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.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>
#include <unistd.h>

main(void)

{
int i = 0;
int recv_own_msgs = 1;
int flags =0;
int s;
struct msghdr msg;
struct sockaddr_can addr;
struct can_frame frame;
struct ifreq ifr;
char ch;
FILE *fpbr;
ssize_t len;
const char *ifname = "can0";

// *************** read file to send

fpbr = fopen("/home/pi/Desktop/file_to_send.txt", "rb");

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

// *******************enable retransmission

setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &recv_own_msgs, sizeof(recv_own_msgs));

  


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)) == -1) 
{
    perror("Error in socket bind");
    return -2;
}

msg.msg_flags = 0;

while(1)
{
    ++i;
    
    // read from file to variable
    
    ch = fgetc(fpbr);
    
    frame.can_id  = i;
    frame.can_dlc = 1;
    frame.data[0] = ch;
    
    //send message
    
    write(s, &frame, sizeof(struct can_frame));

    //Here I would like to receive msg_flags after each message is sent and read and use MSG_CONFIRM 
    // to check if the message was correctly received by the other device to be able to send another message
    
    len = recvmsg(s, &msg, flags);

    
    if (msg.msg_flags==MSG_CONFIRM) // msg_flags is 0, not MSG_CONFIRM
    {
        printf("yes");
    }
    
    if (i > 1000)
        {
            break;
        }
    
}

fclose(fpbr);

return 0;
}
Domi Nik
  • 1
  • 2
  • What exactly do you want to measure? CAN bus traffic is limited by the bitrate, which you can obtain with `ip link show can0`. But sending 1 data byte at a time is not a good measure for the throughput of a CAN bus because of the overhead per frame. Data bytes are 8-10 bits on the wire (because of bit stuffing) and the rest of the frame is anywhere between 47 and 80 bits, including CAN identifier. Waiting for `MSG_CONFIRM` between each message adds even more overhead. It would be more accurate to send everything at once and process all confirmations at the end. – Jos Seldenthuis Nov 30 '20 at 16:25
  • I use an oscilloscope to measure and check that all messages have been received. Before, I used Python and checked if there were differences in the amount of correctly transferred data and how quickly the entire file would be sent depending on the environment, language, etc. used. – Domi Nik Dec 01 '20 at 07:23
  • So far, the speed of sending and receiving messages in Python has been 2 milliseconds while in C it is 700 microseconds between each frame. When I was sending frames in C and receiving frames on the second device via `candump`, the difference in time was 185 microseconds and I try to get as close to that time as possible. – Domi Nik Dec 01 '20 at 07:31

0 Answers0