Responding to Serial

Hi,
I am working on a project to connect a densitometer to a pc app (both made in the 90s).
The newer densitometer doesn’t speak the same serial protocol and the app is fixed, has to be used as is.
I have captured the serial control data from the app and replicated on a Nano v3 with a Max 232 (Code below).
That works just like the app, timing is close enough.

In the code below, the serial_Read(); is where the app would expect a response from the densitometer.
In this case its "R 0.01 0.05 0.09" or whatever other numbers are on the display, they don't matter just the format.
For the other 2 reads its " 0.01 0.05 0.09" (a space instead of R.

I think using the usb serial port to interface with the app and the software serial for the other densitometer should work.
The other densitometer has a completely different protocol but that’s a problem for another day.

Now that I understand what the app is sending and asking for, im not sure how to proceed.

I guess im not really sure of how to get the Nano to read the first 7 lines of serial data transmitted from the PC, respond and wait for the next bunch of lines, respond....then once its done just act as a pass through.

Any ideas?

Thanks so much!!

#include <SoftwareSerial.h>
#define startButton 4
SoftwareSerial mySerial(10, 11); // RX, TX

void setup()
{
  pinMode(startButton, INPUT_PULLUP); //Start
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Native USB only
  }
  // set the data rate for the SoftwareSerial port
  mySerial.begin(9600);
  digitalWrite(startButton, HIGH);
}

void loop() // run over and over
{ boolean state = false;
  if (mySerial.available())
    Serial.write(mySerial.read());
  if (Serial.available())
    mySerial.write(Serial.read());


  if (digitalRead(startButton) == LOW) {
    Serial.println("TEST");
    delay(1000);
    test();
  }
}

void test () {
  mySerial.println("0");
  delay(100);
  mySerial.println("K");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("G");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("X");
  delay(100);
  mySerial.println("");

  serial_Read();

  mySerial.println("G");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("0");
  delay(100);
  mySerial.println("K");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("G");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("X");
  delay(100);
  mySerial.println("");

  serial_Read();

  mySerial.println("G");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("0");
  delay(100);
  mySerial.println("K");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("G");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("X");
  delay(100);
  mySerial.println("");

  serial_Read();

  mySerial.println("G");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("OFF3");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("0726");
  delay(100);
  mySerial.println("W");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("ON3");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("ON2");
  delay(100);
  mySerial.println("");
  delay(100);
  mySerial.println("G");
  delay(100);
  mySerial.println("");
  delay(100);
}

void serial_Read() {
  if (mySerial.available())
    Serial.write( mySerial.read());
  if (Serial.available())
    mySerial.write(Serial.read());
  delay(1000);
}

Ianm1:
I guess im not really sure of how to get the Nano to read the first 7 lines of serial data transmitted from the PC, respond and wait for the next bunch of lines, respond....then once its done just act as a pass through.

I'd suggest a state machine using switch/case (examples and tutorials all over). State1, get first set of characters then do something, then set switch variable to State2, get next set.... Lather, rinse, repeat.

Thanks so much for the suggestion!
Took some hunting, massaging and brute force but it works!

Thanks again!

Ianm1:
Took some hunting, massaging and brute force but it works!

Well done! Would you care to post your solution for the benefit of future seekers?

I would but turns out I spoke to soon.
Didn’t work at all, the default of the switch/case acted as a passthrough and totally ignored my code.

Im still trying to figure out how to read the incoming serial.
I found Serial.readString almost works but I cant get it to recognize the lines.
i.e. either carriage return or line feed. If I input the LF or CR characters, hex, escape characters, its fails.

Still searching...

Does the densitometer send a CR or LF or CR+LF in its response?

The densitometer can accept either CR or LF. Unfortunately the densitometer is the part I already finished.

I cant seem to figure out how to get the Arduino to read in the serial stream and respond.
The attachment is what the PC sends out in Red. In blue is the response. Timing is the first column.

I have to send the blue parts to the pc over serial. Basically just responding but im stuck.
I have tried Serial.readStringUntil and tried to use all of the escape characters one at a time.
Also just Serial.read. Neither seem to be able to interpret because of all of the line breaks.

Any ideas?

Addition: The blank Red lines are Line Feed LF. The blank Blue lines are Carriage Return + Line feed.

That screen shot has other things on it.

What is all that text in black?

I am still not understanding what is the purpose of the Arduino in all of this.
PC program sends something
new densitometer responds with something

What is the Arduino's role?

Do check out the Serial Input Basics tutorial.

On Serial communications characters trickle in one at a time, you can read them one by one and store them in a buffer, optionally parsing chunks of the input as you find the separators (space characters).

When you have that step done, you can do whatever you like with that data: show it on a display, send it on to another PC for further processing - whatever you like.

The PC sends out a command set to setup a specific densitometer.
I am trying to interface another model that doesn’t use the same protocol.
The PC is expecting a specific response after a certain number of controls it sends out.

The later step will be parsing what the new densitometer sends. But I have that pretty much figured out.
It’s spoofing the pc that’s the problem.

  1. PC sends old command
  2. Arduino receives old command
  3. Arduino translates old command to new command
  4. Arduino sends new command
  5. densitometer receives new command
  6. densitometer responds with value
  7. Arduino receives value
  8. Arduino sends value to PC

I don't see anything in your code that resembles that sequence of steps.

Edit:
Personally, I would simply write a new program for the new densitometer.

.

Sorry that code was a duplicate of what the PC sends to the densitometer.
Not the translation bit.
I made that so I could verify that the protocol was correct, where the breaks where, where it expected data back...
Running that, I am able to duplicate how the PC interacted with the densitometer.
That code wont be in the finished project.

This is what I came up with to send to the PC so it thinks the densitometer is connected.
But I couldn’t get it to work. Im still tinkering with it.

 int Reply2 = 0;
  char inByte = Serial.read();
  int switch_value = 0;
  if (inByte == '0' && inByte == 'K' && inByte == '\r' && inByte == 'G' && inByte == 'X' &&
      inByte == '\r') switch_value = 0; //1st Reply

  if (inByte == 'G' && inByte == '\r' && inByte == '0' && inByte == 'K' && inByte == '\r' &&
      inByte == 'G' && inByte == '\r' && inByte == 'X' && inByte == '\r') switch_value = 1; //2nd Reply

  if (Reply2 == 1 && inByte == 'G' && inByte == '\r' && inByte == '0' && inByte == 'K' && inByte == '\r' &&
      inByte == 'G' && inByte == '\r' && inByte == 'X' && inByte == '\r') switch_value = 2; //3rd Reply

  switch (switch_value) {
    case '0':
      Serial.println("R 0.01 0.05 0.09"); //First Reply
      Serial.println("\r");
      break;
    case '1':
      Serial.write(0x03); //ETX Break/end of text
      Serial.println("0.01 0.05 0.09"); //Second and Third Reply
      Serial.println("\r");
      Reply2 = 1;
      break;
    case '2':
      Serial.write(0x02); //STX Start of text
      Serial.println("0.01 0.05 0.09"); //Second and Third Reply
      Serial.println("\r");
      Reply2 = 0;
      break;
    default:
      Serial.write( mySerial.read()); //default should be a passthrough
  }

inByte can be only one thing at a time. Those if statements will always be false.

Look into char arrays and the strcmp function.