Nishikant Tayade Ответов: 2

Разбор пакета данных, полученного из последовательного порта


Выходные данные - это в основном представление dec байтов. а аппаратное обеспечение ,подключенное к последовательному порту ,отправляет его в следующем формате E0 ,F2,идентификатор устройства,длина 2 байта, текущая дата, текущее время(хранить как текущую дату, так и текущее время более чем в 2 байтах путем сдвига вправо и некоторые другие данные)

Я получаю данные кусками иногда по 4 байта, иногда по 8 байт.То, что я хочу сделать, это 1.я хочу сначала проверить, что я получил в этом пакете данных, как заголовок 2.затем, когда я получил следующий блок данных, я хочу проверить не заголовок, а следующую информацию, такую как дата и время, и так далее..

в основном я хочу разобрать входящий пакет.

может ли кто-нибудь привести небольшой пример?Это будет очень полезно.

Спасибо.

Что я уже пробовал:

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SerialPortHexCommunication
{
public class Program
{
    static void Main(string[] args)
    {

        SerialPort port = new SerialPort();
        port.PortName = "COM5";
        port.Parity = Parity.None;
        port.BaudRate = 9600;
        port.DataBits = 8;
        port.StopBits = StopBits.One;

        if (port.IsOpen)

        {
            port.Close();
            port.Dispose();
        }
         port.Open();

        byte[] bytesToSend = new byte[6] { 0xD0, 0xF2, 0xFF, 0x00, 0x06, 0xC7 };

        port.Write(bytesToSend, 0, bytesToSend.Length);


        port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

        Console.ReadKey();
        port.Close();
        port.Dispose();




    }

    private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
    {
        Console.WriteLine("Data receive at time "+ DateTime.Now.TimeOfDay);
        SerialPort port = (SerialPort)sender;

        int bytes = port.BytesToRead;
        byte[] buffer = new byte[bytes];

        if (port.BytesToRead > 1)
        {
            port.Read(buffer, 0, bytes);
        }

        foreach (byte item in buffer)
        {
            Console.WriteLine(item);

        }


    }
}

2 Ответов

Рейтинг:
19

Jochen Arndt

Прием последовательных данных-это асинхронная операция, и обычно вы получаете не все данные из пакета с одним событием.

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

Очень простой пример с нуля:

// Private class members.
// Note that these are used by the receive handler which is executed 
//  in another thread
bool newData = false;
int rxOffset = 0;
byte[] rxBuffer = new byte[MAX_PACKAGE_LENGTH];
// To hold a package after it has been received
byte[] rxPackage = new byte[MAX_PACKAGE_LENGTH];

private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort port = (SerialPort)sender;
    int bytes = port.BytesToRead;
    port.Read(rxBuffer, rxOffset, bytes);
    rxOffset += bytes;
    // Check here if a complete package has been received
    if (HasCompletePackage())
    {
        rxBuffer.CopyTo(rxPackage, 0);
        rxOffset = 0;
        // Or signal the main thread that a new package is available
        newData = true;
    }
}
Обратите внимание, что вышеизложенное не включает в себя дополнительные проверки, такие как переполнение приемного буфера, обнаружение неполных пакетов (например, при запуске) и блокировка доступа к общим переменным (здесь: newData и rxPackage).


Nishikant Tayade

Спасибо @JochenArndt.Я могу поработать над этим сейчас.

Рейтинг:
1

OriginalGriff

Последовательные данные называются так потому, что они поступают последовательно, байт за байтом, а не как "управляемый пакет" информации: каждый байт может вызвать срабатывание отдельного события DataReceived.
Поэтому сохраните его в буфере и обработайте буфер, чтобы решить, что делать.
Я бы начал с базовой машины состояний: "ожидание заголовка", "построение сообщения" как минимум.
Вы начинаете с "ожидания" и обрабатываете каждый байт по мере его получения, пока не получите код, который указывает на начало фактических данных. Затем вы переключаетесь на "построение" и сохраняете сообщение до тех пор, пока не дойдете до конца - в этот момент оно возвращается к "ожиданию", и вы можете обработать весь сохраненный блок данных.


Nishikant Tayade

@OriginalGriff Спасибо за ответ,но что вы имели в виду, строя государственную машину?Не могли бы вы дать фрагмент кода,чтобы его было лучше понять.

OriginalGriff

Базовая машина состояний-это просто перечисление и переменная для тестирования и выяснения того, что вы должны делать, когда получаете событие!

Для получения более продвинутой версии, проверьте wiki!

Nishikant Tayade

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

OriginalGriff

Ты ведь знаешь, что такое перечисление, да?
Ты ведь знаешь, ЧТО ТАКОЕ переменная, да?
Вы знаете, что такое утверждение "если" и / или "переключить" да?

Если вы не можете собрать эти три вместе без посторонней помощи, то последовательная связь слишком развита, чтобы вы могли войти в нее! :смеяться: