USB Read/Write between Arduino and Ubuntu pc

I have to control my Arduino from Ubuntu and so i connected it to my pc with the USB cable.
From my pc, i have to send some command strings to Arduino and wait for the answer.

For example:

my pc sends "check"
Arduino answer: "everything_ok"
my pc then sends: "start"
Arduino: receive "start" and begin some routines
and so on.

I wrote a C code and it does not work everytime and it is not able to read and receive strings in the correct way.
I'm using termios to open and manage the serial port and then i use these functions to read and receive:

int serialport_write(int fd, const char* str)
{
    int len = strlen(str);
    int n = write(fd, str, len);
    if( n!=len ) 
        return -1;
    return 0;
}

int serialport_read(int fd)
{
	
	unsigned char c='D';
	while (c !='q')
	{
		
		if (read(fd,&c,1)>0)        write(STDOUT_FILENO,&c,1);              // if new data is available on the serial port, print it out
		if (read(STDIN_FILENO,&c,1)>0)  write(fd,&c,1);                     // if new data is available on the console, send it to the serial port
	}
   
	return 0;
	
}

Can you help me to solve my problem, please?
Any input or advice?

I wrote a C code and it does not work everytime

Does not work every time? Or, does not work any time?

When the PC is sending, does the RX light on the Arduino flash?

It works.. sometimes.

Arduino receives something but not the correct string because, as i think, it receives also some garbage and so it is not able to recognize the full correct string.
In fact, when i send strings from my application, RX blinks, but it doesn't recognize the commands every time.

I was reading about LibSerial as a more robust solution even if i'd like to continue to use C instead of C++.

It works.. sometimes.

We'd need to see ALL of your PC code and your Arduino code.

I'm using LibSerial on Ubuntu because this library seems to be more roboust.

At the moment, i'm able to read correctly all the data sent by Arduino, but i'm not able to write any commands because when i try to send "check" string, i receive nothing and sometimes i receive "Error".
When i try to write on serial port, TX led blinks on Arduino.

May be, it sends also some garbage with the commands and Arduino is not able to recognize it?

This is the C/C++ code:

#include <SerialStream.h>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <string>

int
main( int    argc,
       char** argv  )
{
     //
     // Open the serial port.
     //
     using namespace std;
     using namespace LibSerial ;
     SerialStream serial_port ;
     char c;
     serial_port.Open( "/dev/ttyACM0" ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] "
                   << "Error: Could not open serial port."
                   << std::endl ;
         exit(1) ;
     }
     //
     // Set the baud rate of the serial port.
     //
     serial_port.SetBaudRate( SerialStreamBuf::BAUD_9600 ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not set the baud rate." <<  
std::endl ;
         exit(1) ;
     }
     //
     // Set the number of data bits.
     //
     serial_port.SetCharSize( SerialStreamBuf::CHAR_SIZE_8 ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not set the character size." <<  
std::endl ;
         exit(1) ;
     }
     //
     // Disable parity.
     //
     serial_port.SetParity( SerialStreamBuf::PARITY_NONE ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not disable the parity." <<  
std::endl ;
         exit(1) ;
     }
     //
     // Set the number of stop bits.
     //
     serial_port.SetNumOfStopBits( 1 ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not set the number of stop bits."
                   << std::endl ;
         exit(1) ;
     }
     //
     // Turn off hardware flow control.
     //
     serial_port.SetFlowControl( SerialStreamBuf::FLOW_CONTROL_NONE ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not use hardware flow control."
                   << std::endl ;
         exit(1) ;
     }
     //
     // Do not skip whitespace characters while reading from the
     // serial port.
     //
     // serial_port.unsetf( std::ios_base::skipws ) ;
     //
     // Wait for some data to be available at the serial port.
     //
     //
     // Keep reading data from serial port and print it to the screen.
     //
  // Wait for some data to be available at the serial port.
     //
     while( serial_port.rdbuf()->in_avail() == 0 )
     {
         usleep(100) ;
     }

     usleep(10000);
     
     char out_buf[] = "check";
     serial_port.write(out_buf, 1);
     while( 1  )
     {
         char next_byte;
         serial_port.get(next_byte);
         std::cerr << next_byte;
         
     }
     std::cerr << std::endl ;
     return EXIT_SUCCESS ;
}

and this is the code on Arduino side:

void setup()
{
 Serial.begin(9600);
}
void loop(){
 inputSize = 0;
 
 if (Serial.available() > 0) {
   delay(300);
   inputSize = Serial.available();
   for (int i = 0; i < inputSize; i++){
     myCmd[i] = Serial.read();
   }

 if (strcmp(myCmd, "check") == 0){
 String start = sonar + token + check_sonar() + end_char; // this string is: Sonar@1\n
 Serial.print(start);
 start = gyroscope + token + check_gyroscope() + end_char; // this string is: Gyroscope@1\n
 Serial.print(start);
 start = encoders + token + check_encoders() + end_char; // this string is Encoders@1\n
 Serial.print(start); 
 } 
 if (strcmp(myCmd, "start") == 0){
 START = true;
 }
 if (strcmp(myCmd, "stop") == 0){
 START = false;
 }
 else if ( !(strcmp(myCmd, "check") == 0) && !(strcmp(myCmd, "start") == 0) && !(strcmp(myCmd, "stop") == 0) ) {
 Serial.print("Error\n");
 }
 
   
 // END FIRST CHECK
 }
}
 if (Serial.available() > 0) {
   delay(300);
   inputSize = Serial.available();
   for (int i = 0; i < inputSize; i++){
     myCmd[i] = Serial.read();
   }

 if (strcmp(myCmd, "check") == 0){

If the data does not all arrive in 300 seconds, it's OK to just ignore the rest?

The strcmp() function expects two strings as arguments. myCmd is NOT a string.

A string is a NULL terminated array of chars. myCmd is an array of chars. It is not NULL terminated, therefore it is not a string, and should not be passed to strcmp() with any reasonable expectation that it will be properly recognized/dealt with.

If I use Serial Monitor to test the Arduino sketch, it works very well because it receive and recognize the strings very well.
For this reason, i was supposing that the sketch was good.

What i should do in order to fix the problem?
What's the best way to read from serial and compare two strings in Arduino?

I hope you can help me.

Since a string is an array of characters with the null termination, can i add '\n' to myCmd to obtein a string in order to succefully use strcmp()?

Since a string is an array of characters with the null termination, can i add '\n' to myCmd to obtein a string in order to succefully use strcmp()?

\n is a carriage return, Adding it will not NULL terminate the string.

The NULL terminator is \0. Adding that WILL help.

I tryed to add the NULL termination character, but now it does not recognize any input when i try to send commands from Serial Monitor.
It writes "Error" all the time.

if (Serial.available() > 0) {
  
   inputSize = Serial.available();
   for (int i = 0; i < inputSize; i++){
     myCmd[i] = Serial.read();
   }
   myCmd[i] = '\0';  <-- Added here

// FIRST CHECK

 if (strcmp(myCmd, "check") == 0){

EDIT: Weird error! i is equal to ZERO outer the for loop.

Ok, now i think i did the right thing!

 if (Serial.available() > 0) {
  
   inputSize = Serial.available();
   for (int i = 0; i < inputSize; i++){
     myCmd[i] = Serial.read();
    if (i == inputSize){
     myCmd[i] = '\0';
     }
   }

In this way, I obtein a string with a NULL character at the end.

Paul, do you think it's correct?

The string should ALWAYS be NULL terminated, not just once.

   for (int i = 0; i < inputSize; i++)
   {
     myCmd[i] = Serial.read();
     myCmd[i+1] = '\0';
   }

You have reason, in this way it adds a NULL character after the last character read.
It is correct :slight_smile:

Sorry, i didn't get it immediately.

Now the problem is that Arduino is not able to recognize the commands sent by the C program: it always returns Error.

I do not know the reason because i simply open the connection and try to send "check".
May be is there an error with the connection time scheduling between Arduino and the C program and Arduino read just a part of the full string command?

This is the C code (I use LibSerial):

#include <SerialStream.h>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <string>

int
main( int    argc,
       char** argv  )
{
     //
     // Open the serial port.
     //
     using namespace std;
     using namespace LibSerial ;
     SerialStream serial_port ;
     char c;
     serial_port.Open( "/dev/ttyACM0" ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] "
                   << "Error: Could not open serial port."
                   << std::endl ;
         exit(1) ;
     }
     //
     // Set the baud rate of the serial port.
     //
     serial_port.SetBaudRate( SerialStreamBuf::BAUD_9600 ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not set the baud rate." <<  
std::endl ;
         exit(1) ;
     }
     //
     // Set the number of data bits.
     //
     serial_port.SetCharSize( SerialStreamBuf::CHAR_SIZE_8 ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not set the character size." <<  
std::endl ;
         exit(1) ;
     }
     //
     // Disable parity.
     //
     serial_port.SetParity( SerialStreamBuf::PARITY_NONE ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not disable the parity." <<  
std::endl ;
         exit(1) ;
     }
     //
     // Set the number of stop bits.
     //
     serial_port.SetNumOfStopBits( 1 ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not set the number of stop bits."
                   << std::endl ;
         exit(1) ;
     }
     //
     // Turn off hardware flow control.
     //
     serial_port.SetFlowControl( SerialStreamBuf::FLOW_CONTROL_NONE ) ;
     if ( ! serial_port.good() )
     {
         std::cerr << "Error: Could not use hardware flow control."
                   << std::endl ;
         exit(1) ;
     }
     //
     // Do not skip whitespace characters while reading from the
     // serial port.
     //
     // serial_port.unsetf( std::ios_base::skipws ) ;
     //
     // Wait for some data to be available at the serial port.
     //
     //
     // Keep reading data from serial port and print it to the screen.
     //
  // Wait for some data to be available at the serial port.
     //
     while( serial_port.rdbuf()->in_avail() == 0 )
     {
         usleep(100) ;
     }

     usleep(10000);
     
     char out_buf[] = "check";
     serial_port.write(out_buf, 1);  <-- HERE I SEND CHECK AND I RECEIVE ERROR
     while( 1  )
     {
         char next_byte;
         serial_port.get(next_byte);
         std::cerr << next_byte;
         
     }
     std::cerr << std::endl ;
     return EXIT_SUCCESS ;
}

Now the problem is that Arduino is not able to recognize the commands sent by the C program: it always returns Error.

So you post the PC code. Why?

PaulS:

Now the problem is that Arduino is not able to recognize the commands sent by the C program: it always returns Error.

So you post the PC code. Why?

Because I thought the sketch is correct now since it manages the string correctly, so i posted the C code in order to receive some help on it.

May be, i'm not sending the commands in the correct way with my C code and someone can give me some suggestions.

In fact, to test it I added a println(myCmd) after the for loop in order to get back the string received and i noticed that Arduino receives just the "c" character of the whole string "check" sent my the C program.

C program sends "check"
Arduino receive "c" and then sends "Error".

Someone can help me on this problem, please?

Arduino receives just the first character and then stops.

I solved it!

Paul_S thanks for your help!!

Paul_S thanks for your help!!

You're welcome.

I solved it!

Be nice to know how/what the problem was.

Yes, the problem was in the C code with the libSerial write() function: i was sending just the first character of the buffer and not the other ones.

Now, i'll try to implement a communication protocol between C program and Arduino.

When i'll do this, can i post the C code and the Arduino sketch in order to see if it can be improved?

Or I have to post only the Arduino code?