MultiSerialMega example problem

I have a question about the MultiSerialMega example. I jave a machine that is controlled over a serial port. The pc sends data to the controller. Now i want to add manual control to the machine. The only way I can do that is over a serial port. So i'm trying to use mega2560 as a serial director. By default the mega forwards serial comands from Serial to Serial1 (and backwards). I added some code if i press a switch the mega stopc sommunicatin from Serial to Serial1 and writes a predefined command. It works but sometimes i get corrupted data when the mega is fowarding the data. Sometimes it even stops sending data. The part of the code that stops data and sends predefined data is not the problem. I commented out everything and the only thing left was the code that is the same as in the MultiSerialMega example. U use 115200 baud so i think the buffer doesn't clear fast enough. Is there any other way to do what the example does? It doesnt matter if the data has lag it only needs to arrive. The messages are typicaly 20bytes long.

When the button is detected does the Mega have time to finish sending the last data packet? Nevermind. You said this isn't the issue.

115200 is pretty fast but I'd think the Mega's hardware UARTs could handle this.

How is the data being passed on? One byte at a time? Some serial devices don't like excessive delays between bytes. You might need to store the command to a buffer and the send the entire buffer contents at once.

I think you'd have a better chance of someone spotting the problem if you posted the code you're using.

Edit: I took a look at the MultiSerialMega example. It is sending one byte at a time. This could be your problem. You may need to save a full command and then send the command all at once.

To answer your crossed text. Yes it does. The mega is sending byte by byte and the PC only sends a "?". So that is one byte. The data stream from the machine to the PC is never interrupted. Yes I was thinking the same thing sending accumolated bytes but how can i do this? The messages aren't the same lenght?

Tady: Yes I was thinking the same thing sending accumolated bytes but how can i do this? The messages aren't the same lenght?

Does the message have an end of message character like a carriage return or line feed?

It uses carriage return.

You may find the examples in Serial Input Basics useful.

It may be wise to have comprehensive receive code on both serial instances.

As you have not posted your code I cannot know how you are doing things.

...R

If you think buffering is neccessary, you can try this buffered version (untested)
(40 byte max, bidirectonal)

/*
  Mega multple serial test buffered
*/
const byte dlmBack = '\n';
const byte dlmForth = '\n';
const byte BuffLen = 40;

byte cBPos = 0;
byte cBBuff[BuffLen];

byte cFPos = 0;
byte cFBuff[BuffLen];

void setup() {
  // initialize both serial ports:
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {

  // read from port 1
  if (Serial1.available()) {
    if (cBPos < BuffLen) {
      cBBuff[cBPos] = Serial1.read(); // collect
      if (cBBuff[cBPos] == dlmBack) {
        Serial.write(cBBuff, cBPos);  // send to port 0:
        cBPos = 0;
      } else {
        cBPos++;
      }
    }

    // read from port 0
    if (Serial.available()) {
      if (cFPos < BuffLen) {
        cFBuff[cFPos] = Serial.read();  // collect
        if (cFBuff[cFPos] == dlmForth) {
          Serial1.write(cFBuff, cFPos); // send to port 1:
          cFPos = 0;
        } else {
          cFPos++;
        }
      }
    }
  }
}

The above code doesn't work. I will try to see what is wrong this evening. Thank you for helping me :)

Ok i edited the code a little. now i hit another bump. How can i see what kind of termination is the PC sending?

My code was designed to handle CR delimiters in both directions.

If you do not know the delimiter of the pc side, its hard to buffer messages.

You changed the code, you did not post it, so I'm unable to comment it.

Tady:
Ok i edited the code a little. now i hit another bump. How can i see what kind of termination is the PC sending?

It’s not a carriage return?

Here’s my version.

/*
 BufferedSerialTest

 By Duane Degn
 November 2, 2015
 
 Based example program "MultiSerialMega".


 */
const byte MESSAGE_DELIMITER = 13;
const byte FROM_PC_BUFFER_SIZE = 40;
const byte FROM_MACHINE_BUFFER_SIZE = FROM_PC_BUFFER_SIZE * 2; // Make PC wait for replies if needed.
byte rxFromPcBuffer[FROM_PC_BUFFER_SIZE];
byte rxFromMachineBuffer[FROM_MACHINE_BUFFER_SIZE];

void setup() 
{
  // initialize both serial ports:
  Serial.begin(115200);  // Com between PC and Arduino
  Serial1.begin(115200); // Com between machine and Arduino
}

void loop() 
{
  byte rxPcIndex = 0;
  byte rxMachineIndex = 0;
  
  do
  {
    if (Serial.available()) 
    {
      rxFromPcBuffer[rxPcIndex++] = Serial.read();
    }
    if (Serial1.available()) 
    {
      rxFromMachineBuffer[rxMachineIndex++] = Serial1.read();
    }
  }  
  while(rxPcIndex < FROM_PC_BUFFER_SIZE && rxMachineIndex < FROM_MACHINE_BUFFER_SIZE && rxFromPcBuffer[rxPcIndex - 1] != MESSAGE_DELIMITER);  
  
  if (rxPcIndex > 0)
  {
    Serial1.write(rxFromPcBuffer, rxPcIndex);
    rxPcIndex = 0;
  }
  if (rxMachineIndex > 0)
  {
    Serial.write(rxFromMachineBuffer, rxMachineIndex);
    rxMachineIndex = 0;
  }  
    
}

It compiles but I haven’t tested it (I don’t have a Mega).

I’m not new to programming but I’m new to the Arduino so I’m not sure about my syntax. (I kept wondering why pointers weren’t used in some of the serial calls.)

The code posted here only worries about finding the carriage return from the PC. It figures the PC isn’t picky about the byte timing so it caters to the machine. Always sending it complete messages.

Whandall: My code was designed to handle CR delimiters in both directions.

Isn't "\n" the newline character ASCII 10?

I thought "\r" was the carriage return (ASCII 13)?

I know the lots of devices use both but there are a few which only use the carriage return.

My bad.

In most C's I worked with a '\n' embedded in output-strings gets translated to a CR/LF sequence. Sometimes a problem in communications between Win-PCs and Linux.

Whandall: My bad.

In most C's I worked with a '\n' embedded in output-strings gets translated to a CR/LF sequence. Sometimes a problem in communications between Win-PCs and Linux.

I won't tell you how many times I've gotten those out of order. (Apparently it can be important sometimes.)

.cvs files don't show up in Excel if only carriage returns are used at the end of a line.

I was trying to figure what sort of scenarios would cause a problem for the program I posted and I thought of one. If the machine were to send the PC a short message, the message wouldn’t get sent through until the PC also sent a message to the machine.

I don’t really like the solution I came up with but it might work well enough.

/*
 BufferedSerialTest

 By Duane Degn
 November 2, 2015
 
 Based example program "MultiSerialMega".


 */
const byte MESSAGE_DELIMITER = 13;
const byte FROM_PC_BUFFER_SIZE = 40;
const byte FROM_MACHINE_BUFFER_SIZE = FROM_PC_BUFFER_SIZE * 2; // Make PC wait for replies if needed.
const unsigned long RX_TIME_OUT = 2000;
byte rxFromPcBuffer[FROM_PC_BUFFER_SIZE];
byte rxFromMachineBuffer[FROM_MACHINE_BUFFER_SIZE];
unsigned long lastRxTime;
void setup() 
{
  // initialize both serial ports:
  Serial.begin(115200);  // Com between PC and Arduino
  Serial1.begin(115200); // Com between machine and Arduino
}

void loop() 
{
  byte rxPcIndex = 0;
  byte rxMachineIndex = 0;

  lastRxTime = millis();
  do
  {
    if (Serial.available()) 
    {
      rxFromPcBuffer[rxPcIndex++] = Serial.read();
      lastRxTime = millis(); // Priority to complete input from PC so machine gets full message.
    }
    if (Serial1.available()) 
    {
      rxFromMachineBuffer[rxMachineIndex++] = Serial1.read();
    }
  }  
  while(rxPcIndex < FROM_PC_BUFFER_SIZE && rxMachineIndex < FROM_MACHINE_BUFFER_SIZE && rxFromPcBuffer[rxPcIndex - 1] != MESSAGE_DELIMITER && millis() - lastRxTime < RX_TIME_OUT);  
  
  if (rxPcIndex > 0)
  {
    Serial1.write(rxFromPcBuffer, rxPcIndex);
    rxPcIndex = 0;
  }
  if (rxMachineIndex > 0)
  {
    Serial.write(rxFromMachineBuffer, rxMachineIndex);
    rxMachineIndex = 0;
  }  
    
}

The code will now pass a message along after a predetermine timeout period (set as two seconds). Again it compiles but I haven’t tested it.

You might use some simple echo code like below and have the arduino convert the received characters into hex and send them to the serial monitor to see if non printable characters are included.

//zoomkat serial echo test 7-31-2011

char c; // incoming serial data

void setup() {
  Serial.begin(9600);  // set serial port at desired value
  Serial.println("serial echo test 0021"); // echo test
  Serial.println();
}

void loop() {

  if (Serial.available() > 0) { // check for serial buffer input
    c = Serial.read(); // read the incoming byte:

    Serial.println(c); // print the input
    //select an output format
    Serial.println(c, DEC);  // print as an ASCII-encoded decimal
    Serial.println(c, HEX);  // print as an ASCII-encoded hexadecimal
    Serial.println(c, OCT);  // print as an ASCII-encoded octal
    Serial.println(c, BIN);  // print as an ASCII-encoded binary
    Serial.println();
    //Serial.println(); // print new line for better reading
  }
}

Guys i did some testing and it seems that pc in some cases sends a carriage return and sometimes i doesn't. The same goes for the machine. So buffering is not working for me. But i did some exploring with the byte by byte transfer example. And managed to get that working. I did use the MultiSerialMega example and i added some digitalRead commands. It seems when i was troubleshooting the code i did't remove everything. So the example is now working.