Непрерывное чтение буфера последовательного порта и анализ данных в массив в C# - PullRequest
0 голосов
/ 08 января 2020

Здравствуйте. Я пытаюсь найти лучшее решение для непрерывного чтения буфера последовательного порта и парсинга данных в массив, последовательный последовательный порт в виде строки выглядит так:

"... G 130 g \ r \ nG 130 g \ r \ nG 124 г \ r \ nG 124 г \ r \ nG 124 г \ r \ nG ... "

Основная идея читается для примера последней 3 данные из широковещательной строки последовательного порта, анализ на двойной массив [124.0; 124,0; 124.0] и comapre, если равно.

Сейчас я использую этот простой код, но он недостаточно быстр:

_serialPortMainForm.DataReceived += new SerialDataReceivedEventHandler(Port_DataReceived);

.....

void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                byte[] data = new byte[_serialPortMainForm.BytesToRead];
                _serialPortMainForm.Read(data, 0, data.Length);
                string str = Encoding.ASCII.GetString(data);
                RawSerialPortData += str;
                if (RawSerialPortData.Length > Properties.Settings.Default.BufferSize) {
                    ProcessSerialPortData(RawSerialPortData);
                    RawSerialPortData = "";
                }
            }

И синтаксический анализ данных, подобных этому:

public void ProcessSerialPortData( string DataToProcess) {
            int count = 0;
            string PostFix = "";

            DataToProcess = DataToProcess.Substring(DataToProcess.IndexOf('G') + 1);
            DataToProcess = DataToProcess.Replace(" ", "");
            DataToProcess = DataToProcess.Replace(Environment.NewLine, "|");

            foreach (char c in DataToProcess) if (c == '|') count++;
            ProcessedData = new double[count-1];

            DataToProcess = DataToProcess.Replace("G", "");

            if (DataToProcess.Contains("kg")) { PostFix = "kg"; DataToProcess = DataToProcess.Replace("kg", ""); }
            if (DataToProcess.Contains("g")) { PostFix = "g"; DataToProcess = DataToProcess.Replace("g", ""); }

            UnitsController(PostFix);

            DataToProcess = DataToProcess.Replace(".", ",");
            string[] SplitData = DataToProcess.Split('|');

            int j = 0;
            while (j < count - 1) {

                Double.TryParse(SplitData[j], out ProcessedData[j]);
                j++;
            }
        }

Кг не имеют значения для этой ситуации, потому что граммов достаточно для этой ситуации

У кого-нибудь есть идея или простое и лучшее решение, как сделать это лучше и быстрее ??

1 Ответ

1 голос
/ 09 января 2020

Делая определенные предположения о строке в буфере, можно извлечь все значения с помощью Regex.

Объявить глобальную переменную вне метода и скомпилировать Regex для более быстрых результатов:

Regex _regex = new Regex(@"\d+\s+\w+", RegexOptions.Compiled);

Затем в вашем методе используйте следующее для извлечения всех значений:

var matches = _regex.Matches(DataToProcess)
    .Cast<Match>()
    .Select(m => 
    {
        var parts = m.Value.Split(' ');
        return new { Value = parts[0], Unit = parts[1] };
    });

//This is just for you to see the results in the console.
foreach (var value in matches)
{
    Console.WriteLine(value);
}

Предполагая, что DataToProcess содержит это:

var DataToProcess = @"G130 g\r\nG 130 g\r\nG 124 g\r\nG 124 g\r\nG 124 g\r\n";

Это приведет к следующему в консоли:

{Значение = 130, Единица = г}

{Значение = 130, Единица = г}

{Значение = 124, Единица = г}

{Значение = 124, Единица = г}

{Значение = 124, Единица = г}

Затем можно использовать это перечисление для проверки для единиц, значений и т. д. c.

Если вам нужны значения в виде массива значений типа double, просто используйте:

var ProcessedData = matches.Select(m => Convert.ToDouble(m.Value)).ToArray();

Наконец, camelCase обычно предпочтительнее в C# для имен переменных, и ваш код кажется не очень потокобезопасным. О чем подумать.

...