communicating with Linux...

Hi,
I finished with my arduino sketch that provides a set of commands for my Linux box to use to read sensors, run servo motors etc.

Commands have this format: @xxxx\n
For instance to read my Ping))) my Linux box issues (after opening the serial port as a file):

fprintf("@sp\n");

Where 's' means the query goes to the sensor array, and 'p' specifies the Ping))) sensor I have. This works correct now. One problem I dealt with was using:

Serial.print(pingOutput);

that made my Linux box to wait forever for a line termination to arrive! Then I changed it to:

Serial.println(pingOutput);

and world became a happy place :smiley:

now there is a new problem I don't have any idea how to solve:
I decided to test if I can read my Ping))) 10 times with an interval of 1 second:

      for(icount=0; icount < 10; icount++)
      {
                printf("querying the Ping sensor...\n");
            fprintf(motorController, "@sp\n" );
            sleep(1);
            fscanf(motorController, "%s", buffer);
            printf("Pinged: %s\n", buffer);
            bzero(buffer,256);
      }

The problem:
When I run this code, I receive:

querying Ping sensor...
Pinged: 27
querying Ping sensor...

and the Linux box waits forever, as if for a line termination to arrive! I have for sure "Serial.println(pingOutput)" so what may be the reason please?

Could you maybe share (parts of) your Arduino code?

Nearly all the code (other parts simply to run LCD: standard codes).
Sorry may be not commented well!

void setup()
{
  //Serial.begin(115200);
  Serial.begin(9600);
  for (int i=CLK; i <= STR; i++) {
    pinMode(i,OUTPUT);
  }  
  for(int icount=0;icount<MOTORS;icount++)
  {
    pinMode(MotorPin[icount], OUTPUT);
    Motor[icount].attach(MotorPin[icount]);
  }
  pinMode(FLLenc, INPUT);  
  pinMode(FRLenc, INPUT);  
  pinMode(echoPin, INPUT); 
  pinMode(pingPin, OUTPUT);
  SetupTimer2();
  //attachInterrupt(0, intISR, CHANGE);  //set the interupt and ISR/mode
  Serial.flush();  
  ///INIT LCD AND WRITE A GREETING///
  LcdInit();
  //LcdCommandWrite(0x0F); //  cursor blink
  //delay(10);
  setLCD();  
  ////////////////////////////////////
}

void loop()
{
  //setLCD();  
 if( Serial.available() > 0 && Serial.read()=='@') 
 {  
   delay(SERIDELAY); //wait to accumulate commands bytes
   char cmdbuf[MAXCMDLEN];
   char c;
   int i = 0;
   while( Serial.available()>0 && c != '\n' && i < MAXCMDLEN) //MAXCMDLEN
   {
     c = Serial.read();
     cmdbuf[i++] = c;
   }
   if(c!='\n')  
     cmdbuf[i] = '\n';
   commandRouter(cmdbuf, i);
 }  
}

void commandRouter(char* cmd, int bufCounter)
{
   //do what you want with the arrived command here
   char c = toupper(cmd[0]);
   switch (c)
   {
     case 'M':
       analyzeMotorCmd(cmd);
       break;
     case 'S':
       analyzeSensorCmd(cmd);
       break;
     case 'L':
       writeCmdToLcd(cmd, bufCounter);    
       break; 
      case '?':
        Serial.println("#r");  //I'm alive!
        break;      
   }
}

void analyzeSensorCmd(char* cmd)
{
  char c = toupper(cmd[1]);
  switch (c)
  {
    case 'P': //Ultrasonic Sensor
    { //example: @sp
      long cm = ping();
      Serial.println(cm, DEC);
      break;
    }
    case 'F': //Follower of line encoder sensors
    { //example: @sfr
      char f = toupper(cmd[2]);
      if(f=='L') //Left
        Serial.println(digitalRead(FLLenc),DEC);
      else if(f=='R') //Right
        Serial.println(digitalRead(FRLenc),DEC);
      break;      
    }
  }
}


long ping()
{
  long duration;

  //to send a sound wave
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);
  
  //pulseIn: start timing when pin goes to High, then stop when goes Low.
  duration = pulseIn(echoPin, HIGH);
  
  //return centimeters: divide by 2 as sound is going AND comming.
  return (long)(duration / 29 / 2);
}

Assuming your MAXCMDLEN is large enough (couldn't find it in the source, but I'm sure it's > 3), the only possible problem I'm seeing so far is the following.

You are comparing an uninitialized variable:

   char c;
   int i = 0;
   while( Serial.available()>0 && [glow]c != '\n'[/glow] && i < MAXCMDLEN) //MAXCMDLEN

You should not only define, but also assign c a value. Or you could change the while loop to look somewhat like this (untested)

   while( Serial.available()>0)
   {
     c = Serial.read();
     if(c == '\n' || i >= MAXCMDLEN) break;
     cmdbuf[i++] = c;
   }

Well I changed that, and now initialize the variable. It didn't work either. Then to exclude any possible effect of other parts of the code, I designed a new sketch from scratch...

Arduino new sketch:

char c;
char test[10];
int icnt;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if(Serial.available()>0 && Serial.read()=='@')
  {
    delay(10);
    c = Serial.read();
    while( c!='\n' && icnt<10)
    {
      test[icnt++] = c;
      c = Serial.read();
    }

    for(int ist = 0; ist < icnt; ist++)
      Serial.print(test[ist]);
      Serial.println();

     icnt = 0;
  }     
}

Linux box new program:

char buffer[256];
//.....
//motorController file descriptor opened, and all other setup...
//....
while(1==1)
{
  fprintf(motorController, "@testing\n" );
  fscanf(motorController, "%s", buffer);
  printf("Pinged: %s\n", buffer);
  bzero(buffer,256);
  sleep(1);
}

same as before:
if I exclude the while loop in the Linux box, it works fine, i.e. I sent "@testing\n", and I'll get back "testing". Then I return to my while and it works again one time, and then waits forever!

Do you please suggest how to get rid of the error?

It looks like you're assuming there'll be enough characters to read after the first "Serial.available()".

You should either use "Serial.available() > NUMBER_OF_CHARS_IN_CMD", or check every time if there actually are any bytes to read.

I don't have an Arduino at hand to try it, but try to make your code work more like this:

      int c;
      char test[10];
      int icnt = -1;

      void setup()
      {
            Serial.begin(9600);
            Serial.println("Starting...");
      }

      void loop()
      {
            if(Serial.available() > 0)
            {
                  int c = Serial.read();
                  if(c == '@') {
                        icnt = 0;
                  } else if(c == '\n') {
                        handleCmd(test, icnt);
                        icnt = -1;
                  } else if(icnt >= 0) {
                        test[icnt++] = (char) c;
                  }
                  
                  if(icnt > sizeof(test)) {
                        handleCmd(test, icnt);
                        icnt = -1;
                  }
            }    
      }
      
      void handleCmd(char* cmd, int size) {
            Serial.print("Executing command: ");
            for(int i=0; i < size; ++i) Serial.print(cmd[i]);
            Serial.println();
      }

Thank you very much! Excellent support! :slight_smile:

Does that mean you've got it to work?

Yes! You formulated the solution much better than me: the logic you wrote above is crystal clear, and efficient.

I still have one problem, but it must be solved (95%) under Linux. Anyway I'll write it here, may be you kindly give the next idea.

Linux code:

//motorController opens "/dev/tts/1" serial port.
   bzero(buffer,256);
     
   while(1==1)
   {
     fprintf(motorController, "@sp\n" ); //s:sensor, p:ping.
     fscanf(motorController, "%s", buffer);
     printf("Ping: %s\n", buffer);

     bzero(buffer,256);

/*
     fprintf(motorController, "@sel\n" ); //e: encoder, l:left.
     fscanf(motorController, "%s", buffer);
     printf("Left Encoder: %s\n", buffer);

     bzero(buffer,256);
*/
   }
     
   fclose(motorController);
   return 0; 
}
  1. running the code gives accurate output from Ultrasonic sensor: it continuously gives the right distance from the sensor.
  2. next I remove the comments you see. the code continues to behave as if it is still commented! To force it to work, I have to close the file descriptor and reopen it before querying the encoder sensor. This is inefficient, as I'll have various sensors. Also, even if I close and reopen the file descriptor, code works for some time and then hangs!

Questions:
a) it seems that it is certainly not connected with Arduino sketch right?
b) any idea how to approach the solution?