Search code examples
cfgetscan-bus

C: Shell command double output without reason


so im working with CAN utils using this CANopenNode im making candump through a .c program file.

my code for the receiver looks like this

char raw_message[47], message_id[4], message_data[17];
fp = popen("candump vcan0 -L", "r");

  if( fp == NULL )
  {
    printf("Failed to run CANDUMP for VCAN0");
    exit(1);
  }

  while ( fgets(raw_message, sizeof(raw_message), fp) )
  {
      if( isspace(raw_message[0]) )
      {
      }
      else
      {
        //GETTING THE ACTUAL MESSAGE = ID+DATA
        cid = 0;
        cdata = 0;
        for(i=26; i<46; i++)
        {
          if( i<29 )
          {
            message_id[cid] = raw_message[i];
            cid++;
          }
          else if ( i==29 )
            message_id[cid] = '\0';
          else if ( i>29 )
          {
            message_data[cdata] = raw_message[i];
            cdata++;
          }
        }
        message_data[16] = '\0';
        //END OF GETTING MESSAGE
        fprintf(stdout,"%s\n",raw_message); 
        fflush(stdout);
      }

  }

  pclose(fp);

and im running a shell script for sending

echo "Start"
i=0;
while [ $i -le 5 ] ;
do
    #echo "sent"
    cansend vcan0 123#0801010101010101
    let i=$i+1
done
exit 0

what im trying to do is to split the id from the actual data of message. The thing is that as you can see I do that only if the first slot of the raw_message isnt space cause I receive a message i get it with fgets and then I get ' ' then message, then ' ' and so go on. Only when I use if (isspace) seems to work and if I put on comments the command "fprintf(stdout,"%s\n",raw_message);" stops working. I tried multiple solutions but nothing seems to work. Is there any particular reason why is doing that? Am I doing something wrong or it maybe something of CANUtils ?

Output when I use issspace() (output is the same as when I run candump on bash){}

(1585149182.549347) vcan0 123#0801010101010101
(1585149182.550713) vcan0 123#0801010101010101
(1585149182.555930) vcan0 123#0801010101010101
(1585149182.559413) vcan0 123#0801010101010101
(1585149182.560687) vcan0 123#0801010101010101
(1585149182.561604) vcan0 123#0801010101010101

Output when I dont use it

while ( fgets(raw_message, sizeof(raw_message), fpdump) )
  {
      // if( isspace(raw_message[0]) )
      // {
      // }
      // else
      {
        //GETTING THE ACTUAL MESSAGE = ID+DATA
        cid = 0;
        cdata = 0;
        for(i=26; i<46; i++)
        {
          if( i<29 )
          {
            message_id[cid] = raw_message[i];
            cid++;
          }
          else if ( i==29 )
            message_id[cid] = '\0';
          else if ( i>29 )
          {
            message_data[cdata] = raw_message[i];
            cdata++;
          }
        }
        message_data[16] = '\0';
        //END OF GETTING MESSAGE
        fprintf(stdout,"%s\n",raw_message); 
        fflush(stdout);
      }

  }

Output:

(1585149305.257591) vcan0 123#0801010101010101


(1585149305.258339) vcan0 123#0801010101010101


(1585149305.259055) vcan0 123#0801010101010101


(1585149305.259651) vcan0 123#0801010101010101


(1585149305.260280) vcan0 123#0801010101010101


(1585149305.260860) vcan0 123#0801010101010101

Solution

  • The example data as shown in the question

    (1585149182.549347) vcan0 123#0801010101010101
    (1585149182.550713) vcan0 123#0801010101010101
    

    ...

    has a line length of 46 characters without the newline character ('\n') or 47 including the newline.

    fgets needs to append a trailing NUL character ('\0') to terminate the string. That's why the first call will read the line without the newline because the buffer is full. The buffer will contain the string

    "(1585149182.549347) vcan0 123#0801010101010101"
    

    The next call will read the newline character only because this is the end of the line. The buffer will contain

    "\n"
    

    You have to increase the size of raw_message to at least 48. Then you would get

    "(1585149182.549347) vcan0 123#0801010101010101\n"
    

    in one fgets call.

    Note that it might be better to read the binary CAN messages using the socketcan interface instead of parsing the text output of candump.