Need some help with serial read and serial print

I'll be up front that I'm no programmer. I can't sit down with a blank screen and write even a simple blink sketch. I can however take several existing sketches and totally rework them and then combine the functions I need from each into a single sketch to so suit my needs. So please understand that what seems "simple" to you may be Greek to me.

I am trying to create a simple sketch(in my mind it's simple) that reads text from a Sparkfun shield via the Tx/Rx inputs on an Uno. I can use an FTDI shield and communicate with the Sparkfun board in a serial terminal just fine. Every thing is simple text and commands are short. What I'd like to do is write a sketch that send's a couple of configuration commands in the setup section of the sketch and verifies the commands were accepted. Every command issued to the shield will either return with a "?" or the text "OK". I need to make sure that the previous command was accepted before sending the next command and that's where I've run into an issue. I can get a sketch to send the commands but I don't know how to read the result sent back from the shield, process the response and then proceed with the next command.

I have searched, tried dozens of sketches and even tried reworking several of them but I still haven't figured this out. I've found a couple that used libraries and could communicate with the shield but none of them had any type of verification of the commands being sent to the shield. This is going to be missing a number of formatting brackets since I'm copying around a lot of unused lines in the code and comments for things that were removed.

char rxData[20];
char rxIndex=0;
int incomingByte = 0;
int dataRead=0;

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

Serial.println("ATI");
    delay(2000);
  
Serial.println("ATSP0");
    delay(3000);

void loop(){
   
  Serial.flush();

  
  Serial.println("03");
  
  getResponse();
  getResponse();
  
  delay(1000);

  
}

//The getResponse function collects incoming data from the UART into the rxData buffer
// and only exits when a carriage return character is seen. Once the carriage return
// string is detected, the rxData buffer is null terminated (so we can treat it as a string)
// and the rxData index is reset to 0 so that the next string can be copied.
void getResponse(void){
  char inChar=0;
  //Keep reading characters until we get a carriage return
  while(inChar != '\r'){
    //If a character comes in on the serial port, we need to act on it.
    if(Serial.available() > 0){
      //Start by checking if we've received the end of message character ('\r').
      if(Serial.peek() == '\r'){
        //Clear the Serial buffer
        inChar=Serial.read();
        //Put the end of string character on our data string
        rxData[rxIndex]='\0';
        //Reset the buffer index so that the next character goes back at the beginning of the string.
        rxIndex=0;
      }
      //If we didn't get the end of message character, just add the new character to the string.
      else{
        //Get the new character from the Serial port.
        inChar = Serial.read();
        //Add the new character to the string, and increment the index variable.
        rxData[rxIndex++]=inChar;
      }
    }
  }

}

This code will send commands but I have no idea how to get the arduino to read the response and act on it. Yes I know the delay function is evil but it was already in the sketch.

Here's another bit of code I've messed with that kind of does what I need where it's requesting information and returns the result but is doesn't send any response back to the Shield. The data is also being formatted in a mathematical equation for conversion....I don't need that equation and I don't understand how to remove that portion of the code.

 //Query the OBD-II-UART for the Vehicle rpm
  Serial1.println("010C\r");
  //Get the response from the OBD-II-UART board
  getResponse();

  //Convert the string data to an integer
  //NOTE: RPM data is two bytes long, and delivered in 1/4 RPM from the OBD-II-UART
  vehicleRPM = ((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4;

  //Print the rpm data to debug serial window
  Serial.print("RPM: ");
  Serial.print(vehicleRPM);
  Serial.println(" ");

  //Give the OBD bus a rest
  delay(500);

I could really use some help with this, something that I would have figured to be a couple lines of code has brought me to my knee's begging for help.

Thanks

This only provides part of what you need, but it handles the part where you look for a line feed ('\r'). The code below looks for a newline character ('\n') which is more common, but you can change it if need be.

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

void loop() {
  int charsReceived;
  char inputBuffer[20];            // Make whatever size you need plus one

  if (Serial.available()) {
    charsReceived = Serial.readBytesUntil('\n', inputBuffer, sizeof(inputBuffer) - 1);  // Save room for NULL
    inputBuffer[charsReceived] = NULL;      // Make it a string
    Serial.print("there were ");
    Serial.print(charsReceived);
    Serial.print(" chars received, which are: ");
    Serial.println(inputBuffer);    
  }
}

I think this code is a little simpler than what you're trying to use. Run in the serial monitor and press Enter when you're done.

What’s wrong with your getResponse function which collects incoming data from the UART into the rxData buffer ? (Besides that it does not check for overflow)

PeteS160: I am trying to create a simple sketch(in my mind it's simple) that reads text from a Sparkfun shield via the Tx/Rx inputs on an Uno.

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

...R

econjack: This only provides part of what you need, but it handles the part where you look for a line feed ('\r'). The code below looks for a newline character ('\n') which is more common, but you can change it if need be.

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

void loop() {   int charsReceived;   char inputBuffer[20];            // Make whatever size you need plus one

  if (Serial.available()) {     charsReceived = Serial.readBytesUntil('\n', inputBuffer, sizeof(inputBuffer) - 1);  // Save room for NULL     inputBuffer[charsReceived] = NULL;      // Make it a string     Serial.print("there were ");     Serial.print(charsReceived);     Serial.print(" chars received, which are: ");     Serial.println(inputBuffer);      } }




I think this code is a little simpler than what you're trying to use. Run in the serial monitor and press Enter when you're done.

I tried it and all it does is run a loop stating the number characters that are in the inputBuffer but doesn't actually display them.

J-M-L:
What’s wrong with your getResponse function which collects incoming data from the UART into the rxData buffer ? (Besides that it does not check for overflow)

I’m able to read data from the UART shield and can have it pull data, what I’m trying to do is set a predetermined response based on the returned data. Example like this…once it’s powered up and can get data

Arduino Sends> ATI
The Response from shield will either be “OK” or “?”, Lets assume it was OK

Arduino Sends>ATSP0
Wait for response “OK” or “?”, assuming it was OK

Arduino Sends>ATH1
Wait for responce “OK” or"?"

I need to wait until each command has been issued and accepted before issuing the next one. I can send the lines just fine and have used delay to give a preset amount of time for a response but it was just a work around because I couldn’t figure out how to make it reply based on the response it gets from the board. One of the things I have found with a lot of sketches for these shields is that they are done for pids that report numbers and they are using a mathematical equation on the answer. I can do every thing I need to with just letters and numbers that are readable by a human because all the shields commands and responses I need are setup in simple readable form.

As for the line I don’t think I need that either, all the text could be one continuous line with no spaces as long as the arduino can detect letters and numbers at would only occur in a preset order and I’m assuming it could. So reading something like… 3h57s8rfThisIsWhatsNeededjsdc8sudcsdjsdIgnorEveryThingElsegys7w68d9f.

Rather then using a variable I can declare the items I’m looking for exactly how they would appear when being read. It only needs to respond when a certain set of characters popup.

Once the intial setup is done this is the only function I need to do.

E8 FF 10 03 B3

When that line Is read with the UART from the vehicle it’s hooked to I need to send the response

E8 FF 01 03 3B

All I’m trying to do is keep the line open. The vehicle pings for avaible nodes on the data bus and waits X amount of seconds for responses from all avaible nodes, if it expects an answer back from a given nodes and it’s not there on the next ping cycle then it ignores all data revived from that node until the car is shut off and restarted. I have been trying to do this by just having the arduino send the message on a timed bases but the vehicle changes the timing that it sends out the ping so presetting a timed response easily gets thrown out of sync. If the Arduino sends the message twice before the ping restarts it also ignores all future pings back from that node until it’s shut off.

And before any one says any thing, this is NOT something that affects the cars drive abilty where it could cause safety issues. It’s part of the vehicles heater control system. I already have all the data I need to set the headers of the UART Shield and it’s capable of doing what I need…I just need to get this ping response to work so it doesn’t keep getting kicked off the vehicles bus network.

What's you grammar/language? If You need to develop a parser for a conversation you're better start by defining what are your "words" and acceptable "sentences" on both sides

or do you just need to develop something that waits for 'OK' before sending the next command? (In which case what does need to happen if you don't get the 'OK'?

PeteS160: I need to wait until each command has been issued and accepted before issuing the next one.

I wonder if you are thinking that this is a complex problem rather than a simple one.

You need a variable that keeps track of where you are - let's call it messageNum. Suppose you want to send 6 different items and wait for a response before sending the next one.

Start with 0 in messageNum

Send the message appropriate to the value in messageNum Note that the message has been sent (so you don't send it twice) Maybe set a variable called messageSent to true When the reply arrives increment messageNum and set messageSent back to false Repeat

The code in Serial Input Basics can be used to listen for the response and if newData == true it will be time to increment messageNum

...R

Draw the state machine. Can you start with a blank sheet of paper? Write "Idle" at the top and draw a circle around it.

What makes this move out of the Idle state? What input does it get or what variable does it look at to decide to start sending the command strings? Maybe it's not connected to the thingy. So draw an arrow leading out of the Idle state with "not connected" next to it.

As you're moving down that arrow, you should be sending the first command.

The arrow should point to a state called "Waiting for first response". Draw a circle around that.

So now, how does it leave that state? Obviously the desired result is it receives the first response. So that's one arrow leaving that circle and moving to the next state. But what if the response never arrives? Does it wait 5 seconds and go back to Idle? You're not connected, so it will immediately leave Idle and re-send the first command. Alternatively, you could go to a "Stop" state where it gives up and alerts the user "No Thingy found", or whatever.

Stop might have a button the user can press to re-try the connection process. So there could be one or more arrows leading out of the Stop state.

The diagram will get quite complex, particularly if there's any user interaction. But it's easy enough to see the whole process on one piece of paper. It's much more complex in code and impossible to see all that code on one page, so you will refer back to the diagram many times.

Larger programs will have many state machines. This whole "connect to the thingy" might be just one state transition in the main program. But it's pretty easy for the main state machine to check if it's connected or not by just looking at the state of this sub-section.

Robin2:
I wonder if you are thinking that this is a complex problem rather than a simple one.

You need a variable that keeps track of where you are - let’s call it messageNum. Suppose you want to send 6 different items and wait for a response before sending the next one.

Start with 0 in messageNum

Send the message appropriate to the value in messageNum
Note that the message has been sent (so you don’t send it twice) Maybe set a variable called messageSent to true
When the reply arrives increment messageNum and set messageSent back to false
Repeat

The code in Serial Input Basics can be used to listen for the response and if newData == true it will be time to increment messageNum

…R

I’ve managed to do what I needed in an Android app using MIT’s App Inventor and it was actually rather simple. However I am struggling to find any examples of this type of logic being implemented with an Adruino. I can find examples of reading in strings of a specific number but still nothing where it for a “word” of some type and then acts on it. I’ve included a brief summary of the general logic I used to accomplish this using App Builder.

//Declare variables
#Set variable - Count = 0
#Set variable - answer  = "  "
#Set Variable - Serial input InputRead = DataRead
#Declare Setup = Dataread + global response
#Declare Restart = Send "ATZ" & set  response = 0 // Set count to 0
#Declare Timer = When Timer Start Set count to 10  // Start count down to reset
DateRead = SerialInput \\ Read serial data in real time  
{  While Count < 5 
         {DO Setup      
                       {IF Count = 0 & DataRead = ">"
                              Then - Send text "ATZ" & (set count = count + 1) // Reset and start the count
                              Else - Do Restart
                        IF Count = 1 & Data Read = "OK
                             Then - Send "ATI" & (set count = count + 1) \\ Setup command 1and add to count
                             Else - do Restart restart and set count back to 0
                        IF Count = 2 & Data Read = "OK
                             Then - Send "ATSP0" & (set count = count + 1)   
                             Else - Send "ATI" & (set count = 1) \\ Go back 1 step, if this step fails 
                        IF Count = 3 & Data Read = "OK
                             Then - Send "ATH1" & (set count = count + 1)   
                             Else - Send "ATSP0" & (set count = 2) \\ Go back to Reply2 , if the previous step fails it go to step before that
                        IF Count = 4 & Data Read = "OK
                             Then set count = 6
                             Else - Send "ATH1" & (set count = 3) \\ Go back to Reply3 , if the previous step fails it go to step before that
                       }
             }
}             
//once count is greater then 5 do the loop
Void LOOP 
   If Count>5
         Then DO ReadData
                 {If DataRead is >0 \\Make sure there is data coming in
                          Then GET DataRead \\ check for the specific input value
                          Else Start Timer & Set Count = Count - 1
                 }
                          
                 {If DataRead = E8 FF 10 03 B3 \\ The only line we need to respond to
                           Then - Send text"E8 FF 01 03 3B" \\Send the response 
                           Else - DO DataRead} //Keep looking for the set of text were after}
                  }

Look at Robin's code in Serial Input Basics, use strcmp() or strncmp() for example to compare your buffer with known commands or implement a parsing tree