Serial.read

Hello,

I'm an Arduino newbie... I'm trying for some weks to decode APRS with arduino mega. I'm using a Terminal Node Controller between th radio and the Arduino; so the data frames I want to decode starts with "C0 00" and ends with "C0", the frames do not have a fixes lenght.

I made some test with buffer, and a lot of shearch on Internet, but now I don't know how to process this frames. My project is : - detect the frame, - decode some parts of the frame - print it in the over Serial port.

If you know where I can find parts of code witch can help me understand how to do, it'll be very helpfull. Thanks in advance (and sorry for my english :drooling_face:)

Which pin is the TNC connected to on the Arduino?

Pete

and if you have Arduino code, post it.

Pete

Hello Pete,

TNC connected (via TTL) to pin n°19 (Serial1). Serial1.available command is ok, so I think Arduino receive the data and wait for my code :)

For th moment I use this one found on the old French Forum.
I can monitor frames with a PC and this code do not permit to decod all the frame. I miss also the detection of the beginning and end of frame.


int tableau[200];
int buffer;
int nbrecar ;


void setup() {
  Serial1.begin(4800);
Serial.begin(9600);  // 
  Serial.println("Ready !");

}

int readCommande()
{
  if(!Serial1.available())
  {
    return 0;
  }

   byte i ;
  
  nbrecar = Serial1.available();
  for( i=0; i < nbrecar; i++ )
  {
  
  buffer=Serial1.read();
  
      tableau[i]=buffer; //on range l'octet recu dans le tableau
   
  }
return i;
}

void executeCommande()
{
  Serial.print("Number of character: ");
  Serial.println(nbrecar);

byte j ;
for (j=0; j<16; j++){
  Serial.print(tableau[j],HEX);
  Serial.print('/');
}
  Serial.println();

}

void loop()
{
  
  if (readCommande() != 0)
  {
    // si une commande complète est arrivée, on l'exécute
    executeCommande();
    }
}

Moderator: Code tags added, italics removed.

That code doesn't use Serial1.available correctly. I'll look at it and see if I can fix it up for you. Meanwhile, what generates the C0 00 at the start and the C0 at the end? That doesn't look like anything in the APRS/AX.25 spec. What sort of data do you expect between the two?

Pete

This compiles on a Mega but I can’t test it - give it a try.

unsigned char tableau[200];
int ib = 0;
int start_flag = 0;
int nbrecar;


void setup() {
  Serial1.begin(4800);
  Serial.begin(9600);  //
  Serial.println("Ready !");

}

int readCommande()
{
  unsigned char c;
  while(Serial1.available() > 0) {
    switch(start_flag) {
    case 0:
      // looking for C0
      if(Serial1.read() != 0xC0)continue;
      tableau[0] = 0xc0;
      start_flag = 1;
      continue;
    case 1:
      // Have C0, now looking for 00
      if((c = Serial1.read()) != 0x00) {
        // If we've just read C0 we can stay in this state
        // and see if the next one is 00
        if(c == 0xC0)continue;
        // but otherwise we have to go back to state zero again
        start_flag = 0;
        continue;
      }
      tableau[1] = 0x00;
      start_flag = 2;
      ib = 2;
      continue;
      
    case 2:
      // We've found C0 00 so just read everything else up to C0
      if((tableau[ib++] = Serial1.read()) != 0xC0) {
        // If there's too many chars in the packet return what we have
        if(ib >= 199) {
          start_flag = 0;
          return(ib);
        }
        continue;
      }
      // We've found the C0 at the end so return the length of the data
      start_flag = 0;
      return(ib);
    }
  }
  // Haven't finished yet - return zero
  return(0);       
}

void executeCommande()
{
  Serial.print("Number of character: ");
  Serial.println(nbrecar);

  byte j ;
  for (j=0; j<16; j++){
    Serial.print(tableau[j],HEX);
    Serial.print('/');
  }
  Serial.println();

}

void loop()
{

  if ((nbrecar = readCommande()) != 0)
  {
    // si une commande complète est arrivée, on l'exécute
    executeCommande();
  }
}

Pete

The TNC sends data in Kiss mode, frames bagan with C0 00 and ends with 00.

The looks like : - C0 00 - (7 bytes) destination adress -(7 bytes) source adress - (0to 56 bytes) digipeater adress - (0x03) control field -(0xF0) protocol ID - (1-256 bytes) information field -00

My goal is to extract destination, source, and information for lcd print and alarm (later....).

I tested your code, nothing happend after "Ready print" Regards Edger

I found a site that describes KISS mode. It starts with C0 and ends with C0. You had said it starts with C0 00 so my code wasn’t looking for the header properly.
I’ve modified the code:

unsigned char tableau[200];
int ib = 0;
int start_flag = 0;
int nbrecar;


void setup() {
  Serial1.begin(4800);
  Serial.begin(9600);  //
  Serial.println("Ready !");

}

int readCommande()
{
  unsigned char c;
  while(Serial1.available() > 0) {
    switch(start_flag) {
    case 0:
      // looking for C0
      if(Serial1.read() != 0xC0)continue;
      tableau[0] = 0xc0;
      start_flag = 1;
      ib = 1;
      continue;
      
    case 1:
      // We've found C0 so just read everything else up to C0
      if((tableau[ib++] = Serial1.read()) != 0xC0) {
        // If there's too many chars in the packet return what we have
        if(ib >= 199) {
          start_flag = 0;
          return(ib);
        }
        continue;
      }
      // We've found the C0 at the end so return the length of the data
      // but was there any data between the two C0?
      if(ib == 2) {
        // two C0 in a row are not a packet
        // perhaps the second one is the start of a new packet
        // stay in state 0 and try again
        ib = 1;
        continue;
      }
      start_flag = 0;
      return(ib);
    }
  }
  // Haven't finished yet - return zero
  return(0);       
}

void executeCommande()
{
  Serial.print("Number of character: ");
  Serial.println(nbrecar);

  byte j ;
  for (j=0; j<16; j++){
    Serial.print(tableau[j],HEX);
    Serial.print('/');
  }
  Serial.println();

}

void loop()
{

  if ((nbrecar = readCommande()) != 0)
  {
    // si une commande complète est arrivée, on l'exécute
    executeCommande();
    ib=0;
  }
}

Give that a try. It doesn’t handle the complete KISS spec but it should work for standard AX25 and text data.

Pete

You might want to check textfinder below for detecting the CO packet marker in a serial character string.

http://www.arduino.cc/playground/Code/TextFinder

Well, is a little bit late, comparing the dates of this post, but I’m trying the same thing more or less… Instead of serial though, I use OLED.
Indeed, the starting and ending frame is C0.

Another odd thing, is that the first bytes (after C0) containing destination, source and path, which is up to F0, comes with char value *2! So, you see on screen :

À‚ ž¨†bàj„h‚˜¤î®’ˆŠf@gð

but it really is :

`APOTC1p5B4ALRwWIDE3 3x (x is the F0 or ð “translated”)

seems that some special treatment is needed, p should be 0, w should be 7, the space between 3’s should be “-”.
Ideally, it should show: 5B4ALR-7>APOTC1-0>WIDE3-3

After F0, everything has the real char value, and the use of some special characters, is defining the kind of data you have (VERY VERY complicated! Compressed, timestamps, coordinates, altitude, course, speed, telemetry, text commends, in a variety of flavours!).

I modified a little bit the code el_supremo kindly shared with us, to use with OLED:

#include "U8glib.h"
 U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);
unsigned char tableau[200];
int ib = 0;
int start_flag = 0;
int nbrecar;

void setup() {
  Serial.begin(9600);
  u8g.setColorIndex(255);
  u8g.setFont(u8g_font_6x10);
  u8g.firstPage();
}

int readCommande()
{
  while(Serial.available() > 0) {
    switch(start_flag) {
    case 0:
      // looking for C0
      if(Serial.read() != 0xC0)continue;   
      tableau[0] = 0xC0;
      start_flag = 1;
      ib = 1;
      continue;
     
    case 1:
      // We've found C0 so just read everything else up to C0
      if((tableau[ib++] = Serial.read()) != 0xC0) {
        // If there's too many chars in the packet return what we have
        if(ib >= 199) {
          start_flag = 0;
          return(ib);
        }
        continue;
      }
      // We've found the C0 at the end so return the length of the data
      // but was there any data between the two C0?
      if(ib == 2) {
        // two C0 in a row are not a packet
        // perhaps the second one is the start of a new packet
        // stay in state 0 and try again
        ib = 1;
        continue;
      }
      start_flag = 0;
      return(ib);
    }
  }
  // Haven't finished yet - return zero
  return(0);       
}


void loop()
{
 if ((nbrecar = readCommande()) != 0)
  {
    u8g.firstPage();
    do
    {
    u8g.setPrintPos(0, 10);
    u8g.print("KissReaderOled5:");
    u8g.print(nbrecar);
    u8g.setPrintPos(0, 24);
    for (byte j=1; j<(ib - 1); j++){
    u8g.print(char(tableau[j]));
    if (j == 21)
          {
            u8g.setPrintPos(0, 34);
          }
          if (j == 42)
          {
            u8g.setPrintPos(0, 44);
          }
          if (j == 63)
          {
            u8g.setPrintPos(0, 54);
          }
          if (j == 84)
          {
            u8g.setPrintPos(0, 64);
          }
  }
  }
  while( u8g.nextPage() );  
    // si une commande complète est arrivée, on l'exécute
    ib=0;
  }
}

I made some attempts to add the rule to change the way it shows the first characters (up to F0), but I end up, either showing only this first part, or showing the first part correct and distort the rest :confused:

Obviously, I am a newbie to C++…

If someone cares to help, I will post my tries. Basically I tried to add a case, but… “continue” seems to confuse me.

Thanks for your time,
Stelios

The examples in Serial Input Basics take in all the data before trying to parse it. Maybe that would be helpful?

...R

I will definitely give it a try!

Thanks!