Hi
I'm trying to use an Arduino Mega to receive and parse streams of bytes from some laboratory equipment (received via the Serial1 port) into a 321 byte array in real-time.
My problem is how to implement a Data Link Escaping (DLE) protocol (also called “byte stuffing”, “octet stuffing”, or “data transparency” - see below) on the Mega in real time in a way which is efficient and stable.
A new packet of data is received at approximately 10 second intervals.
Character frame : Asynchronous. 19,200 baud 8-E-1 RTS/CTS
Packet length: Variable prior to parsing (>= 321 bytes: the actual number of bytes depends on number of additionalDLE bytes); Fixed length of 321 bytes after parsing.
Each packet of data is enclosed by a start and end flag: 0x7E.
Because the same flags are used for both start and end of data, there is also the possibility of the Arduino getting “out of phase” with the incoming data and trying to read the gaps between the flags rather than the the data between the flags, and the code needs to prevent this.
If the data bytes contain 0x7E, then this would prematurely signal “End of Message” (EOM).
Therefore a DLE protocol has been employed by the equipment manufacturer as follows:
0x7D acts like a “shift” key. It should not be parsed as data, but indicates that the next byte to be read should be XORed (^) with 0x20, so:
\0x7D\0x5E => \0x5E ^ \0x20 => 0x7E, and:
\0x7D\0x5D => \0x5D ^ \0x20 => 0x7D
I've successfully written code to do the above in Python on a laptop, using Python's powerful string handling routines; but I'm struggling to adapt this to work using a byte array on the Mega.
I'm using Serial1 to handle the data and Serial to report back via the USB cable to the Arduino Serial Monitor to keep track of program flow and aid debugging.
Despite several different approaches, I'm getting unpredictable results with intermittent freezes, board resets, and mangling of the text returned to the Serial Monitor; occurring apparently at random.
I wondered if overflow of the Mega's serial buffer might be to blame; therefore I've edited the core file HardwareSerial.cpp (as explained elsewhere on this forum) to increase the buffer size from 64 to 256 bytes; however this has not resolved my problems; and despite an extensive search of the forums and web, I've been unable to find a solution.
A crude (non-working) minimal example of my code is pasted below to indicate my general approach; although I've modified this repeatedly in desperation to try and get the **** thing to work!
I'd be very grateful for any help you can give me.
Many thanks in anticipation
Dave
const int RxPin = 19; // Serial1 Rx.Connect to Tx pin on RS232-TTL adaptor
byte data[321];
byte d = 0; // buffer for reading data byte
byte e = 0;// buffer for reading data byte
void setup()
{
// Serial Rx and Tx are automatically configured to USB & pins 1 and 2 respectively
//Serial 1
pinMode(RxPin,INPUT);
Serial.begin(9600,SERIAL_8N1); //
Serial1.begin(19200,SERIAL_8E1);
//=========================================================================================
// Main Loop starts here
//=========================================================================================
void loop()
{Serial.println("Starting main loop");
//=========================================================================================
// Read incoming data from Serial1, applying correction for DLE bytes
//=========================================================================================
int state = 1; // reset state to 'wait'
int n = 0; // reset pointer for data array
do{
Serial.println("Starting switch/case loop");
switch(state)
{ // start of switch/case loop
// state 1 = Wait; state 2 = Read; state 3 = Exit. Enter loop in "Wait" state.
//------------------------------------------------------
// State = "WAIT"
//------------------------------------------------------
case 1:
Serial.print("State = WAIT ");Serial.println(state);
while(true){
if (Serial1.available()>0){ // wait for data to be available
d = Serial1.read();
if (d == 0x7E){
break;
}
}
} // if data available, wait for 7E ( = start or end flag)
Serial.println("Found 7E!!");
if (Serial1.available()>0){
e = Serial1.read(); // read the next byte. If it is available, 7E must represent a "start" flag, so:
Serial.println(e);
data[n] = d; // save these first two bytes to the data array
n +=1;
data[n] = e;
n +=1;
state = 2; // return to the switch/case loop, and enter "Read" mode to read more data
break;
}
// otherwise, if the next byte is not available, 7E must represent an "end" flag. Return to the switch/case loop in "Wait" mode and keep waiting for more data
else{
break;
}
//------------------------------------------------------
// State = "READ"
//------------------------------------------------------
case 2:
Serial.print("State: READ ");Serial.println(state);
do {
if (Serial1.available()>0){
d = Serial1.read(); // read the next byte
}
// If the byte is not a stop (7E) or shift (7D) byte, it is data: add it to the array:
if ((d != 0x7E) && (d != 0x7D)){
//Serial.println("Collecting data");
data[n] = d;
n += 1;
}
// If the byte is 7D, then we need to read and shift the next byte:
if (d == 0x7D){
Serial.println("Byte shifted");
e = Serial1.read(); // read next byte
e ^= 0x20; // Bitwise XOR next byte with Ox20: so 7D5E => 7E, and 7D5D => 7D
data[n] = e; // and save the result to the array
n += 1;
}
// If the byte is 7E, then this must be a stop flag
if (d == 0x7E){
Serial.println("Stop flag");
data[n] = d; // add this 7E to the collected data
state = 3; //and change the state to allow exit from the switch/case loop
}
} while(state == 2);// continue to read frame until stop flag is found
break;
} (while state < 3);// end of switch/case loop
//------------------------------------------------------
// State = "EXIT"
//------------------------------------------------------
Serial.print("State = EXIT ");Serial.println(state);
Serial.print("Bytes collected: ");Serial.println(n);
Serial.flush(); //flush the buffers
Serial1.flush();
//continue with code to process data..
}
