Обработка/чтение потоков данных последовательного порта, вызывающих сбой программы

Я работаю над простой программой для чтения непрерывного потока данных из простого старого последовательного порта. Программа написана на Processing. Выполнение простого чтения данных и сброс в консоль работает отлично, но всякий раз, когда я добавляю в программу какие-либо другие функции (графики, запись в БД), порт начинает десинхронизироваться, и все данные из последовательного порта начинают стать коррумпированным.

Входящие данные из последовательного порта имеют следующий формат:
A [TAB] //стартовый флаг
Данные 1 [TAB]
Данные 2 [TAB]
Данные 3 [TAB]
> Данные 4 [TAB]
Данные 5 [TAB]
Данные 6 [TAB]
Данные 7 [TAB]
Данные 8 [TAB]
COUNT [TAB] //счет числа отправленных сообщений
Z [CR] //флаг конца, за которым следует возврат каретки

Итак, как уже говорилось, если я запускаю приведенную ниже программу и просто вывожу ее на консоль, она работает без проблем в течение нескольких часов. Если я добавлю графическую функциональность или подключение к базе данных, последовательные данные начнут поступать в искаженном виде, и обработчик последовательного порта больше никогда не сможет правильно декодировать сообщение. Я пробовал всевозможные обходные пути для этой проблемы, думая, что это проблема синхронизации, но снижение скорости последовательного порта, похоже, не вносит изменений.

Если вы видите обработчик последовательного порта, я предоставляю большой буфер на случай, если завершающий символ Z будет обрезан. Я проверяю, чтобы символы A и Z были в правильном месте и, в свою очередь, чтобы созданная «подстрока» имела правильную длину. Когда программа начинает давать сбой, подстрока будет постоянно терпеть неудачу в этой проверке, пока программа не рухнет. Любые идеи? Я пробовал несколько разных способов чтения последовательного порта и только начинаю задаваться вопросом, не упустил ли я здесь что-то глупое.

//Serial Port Tester
import processing.serial.*;
import processing.net.*;
import org.gwoptics.graphics.graph2D.Graph2D;
import org.gwoptics.graphics.graph2D.traces.ILine2DEquation;
import org.gwoptics.graphics.graph2D.traces.RollingLine2DTrace;
import de.bezier.data.sql.*;

SQLite db;
RollingLine2DTrace r1,r2,r3,r4;
Graph2D g;
Serial mSerialport;                    //the serial port
String[] svalues = new String[8];      //string values
int[] values = new int[8];             //int values
int endflag = 90;       //Z
byte seperator = 13;  //carriage return

class eq1 implements ILine2DEquation {
  public double computePoint(double x,int pos) {
    //data function for graph/plot
    return (values[0] - 32768);
  }
}

void connectDB()
{
  db = new SQLite( this, "data.sqlite" );  
  if ( db.connect() )
  {
    db.query( "SELECT name as \"Name\" FROM SQLITE_MASTER where type=\"table\"" );
    while (db.next())
    {
      println( db.getString("Name") );
    }
  }
}

void setup () {
  size(1200, 1000);        
  connectDB();
  println(Serial.list());
  String portName = Serial.list()[3];
  mSerialport = new Serial(this, portName, 115200);
  mSerialport.clear();
  mSerialport.bufferUntil(endflag); //generate serial event when endflag is received

  background(0);
  smooth();
  //graph setup
  r1  = new RollingLine2DTrace(new eq1(),250,0.1f);
  r1.setTraceColour(255, 0, 0);
  g = new Graph2D(this, 1080, 500, false);
  g.setYAxisMax(10000);
  g.addTrace(r1);
  g.position.y = 50;
  g.position.x = 100;
  g.setYAxisTickSpacing(500);
  g.setXAxisMax(10f);
}

void draw () {
  background(200);
  //g.draw(); enable this and program crashes quickly
}

void serialEvent (Serial mSerialport) 
{
  byte[] inBuffer = new byte[200];
  mSerialport.readBytesUntil(seperator, inBuffer);
  String inString = new String(inBuffer);
  String subString = "";
  int startFlag = inString.indexOf("A");
  int endFlag = inString.indexOf("Z");
  if (startFlag == 0 && endFlag == 48)
  {
    subString = inString.substring(startFlag+1,endFlag);
  }
  else 
  {
    println("ERROR: BAD MESSAGE DISCARDED!");
    subString = "";
  }

  if ( subString.length() == 47) 
  {
    svalues = (splitTokens(subString)); 
    values = int(splitTokens(subString)); 
    println(svalues);

    //   if (db.connect()) //enable this and program crashes quickly
    //    {
    //      if ( svalues[0] != null && svalues[7] != null) 
    //      {
    //      statement = svalues[7] + ", " + svalues[0] + ", " + svalues[1] + ", " + svalues[2] + ", " + svalues[3] + ", " + svalues[4] + ", " + svalues[5] + ", " + svalues[6];
    //      db.execute( "INSERT INTO rawdata (messageid,press1,press2,press3,press4,light1,light2,io1) VALUES (" + statement + ");" );
    //      }
    //   }
  }
}

person mhilmi    schedule 29.01.2011    source источник


Ответы (1)


Хотя я не знаком с вашей конкретной платформой, моя первая мысль после прочтения вашего описания проблемы заключается в том, что у вас все еще есть проблема с синхронизацией. При скорости 115 200 бит/с данные поступают довольно быстро — более 10 символов каждую миллисекунду. Таким образом, если вы тратите драгоценное время на открытие базы данных (медленный файловый ввод-вывод) или рисование графики (также потенциально медленное), вы, возможно, не сможете идти в ногу с данными.

Таким образом, может быть хорошей идеей поместить обработку последовательного порта в отдельный поток, прерывание и т. д. Это может значительно упростить многозадачность. Опять же, это всего лишь обоснованное предположение.

Кроме того, вы говорите, что ваша программа «вылетает», когда вы включаете другие операции. Вы имеете в виду, что весь процесс на самом деле дает сбой, или что вы получаете поврежденные данные, или и то, и другое? Возможно ли, что вы переполняете свои 200 байт в буфере []? При скорости 115 кбит/с это займет всего 20 мс.

person Eric Pi    schedule 29.01.2011
comment
Проблема странная - это, как правило, комбинация данных, которые повреждаются, а вскоре после этого происходит сбой. Как вы сказали, это, похоже, проблема времени. Я попытался исправить это, переместив вставку базы данных в функцию draw(), чтобы она не вызывалась так часто. Я также полностью удалил проверку для db.connect(), что небезопасно, но кажется, что накладные расходы для этой функции приводили к дерьму. Я также удвоил скорость передачи данных, но оставил постоянной скорость, с которой данные отправляются на порт. Эти вещи, казалось, помогли, но все еще оставляют меня любопытным. - person mhilmi; 30.01.2011