Nishikant Tayade Ответов: 2

Использование кольцевого буфера для считывания данных из последовательного порта


В настоящее время я использую байт[] для хранения ответа, отправленного последовательным портом.

Но необходимо хранить данные в круговом буфере (используя круговой буфер, предоставленный на GitHub) и по мере поступления данных в него

1.если данные получены не полностью, отбросьте их.
2.взять какие-то данные
3.и разберите его так, как E0 означает начало данных.


В основном круговая буферная операция-это то, что я ищу?

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

Вот это буфера

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


namespace SerialPortCommunicationWithStateMachines
{
    public class DataReceiveHandle
    {
        public static int MAX_PACKET_LENGTH = ChannelDataCount.count;

        public bool newData = false;

        public int rxOffset = 0;

        public byte[] rxBuffer = new byte[MAX_PACKET_LENGTH];

      
        public byte[] rxPackage = new byte[MAX_PACKET_LENGTH];

     

        public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
           // var xbuffer = new CircularBuffer<byte>(10);
            if (e.EventType != SerialData.Chars) return;

            SerialPort port = (SerialPort)sender;

            

            int bytesCount = port.BytesToRead;
          
            port.Read(rxBuffer, rxOffset, bytesCount);


            rxOffset = rxOffset + bytesCount;

            if (HasCompletePackage())
            {
                Console.WriteLine("Full packet has been received");
                rxBuffer.CopyTo(rxPackage, 0);
                rxOffset = 0;

                newData = true;
            }

            if (newData == true)
            {
                if (rxPackage[0] == 224
                    && rxPackage[1] == 242
                    && rxPackage[2] == 1
                    && rxPackage[3] == 0
                    && rxPackage[4] == 60
                    && rxPackage[5] == 37
                    && rxPackage[6] == 133
                    && rxPackage[7] == 0
                    && rxPackage[8] == 0)
                {
                    Console.WriteLine("Header Content is:");
                    for (int i = 0; i <= 8; i++)
                    {
                        Console.WriteLine(rxPackage[i]);
                    }
                }

                Console.WriteLine("Message Content is: ");

                for (int i = 9; i < MAX_PACKET_LENGTH; i++)
                {
                    Console.WriteLine(rxPackage[i]);
                }

            }


        }
        private bool HasCompletePackage()
        {
            if (rxOffset == 60)
                return true;
            else
                return false;
        }
    }
    }

Mehdi Gholam

А ваш вопрос таков?

Nishikant Tayade

@MehdiGholam, поскольку по умолчанию отсутствует реализация циклического буфера

Как я могу прочитать данные,отправленные последовательным портом в циклический буфер(предоставленный на Git), чтобы прочитать их, разобрать их?

относительно деталей:
https://stackoverflow.com/questions/49593013/how-can-i-read-and-calculate-serial-port-with-circular-buffer-c-sharp

Nishikant Tayade

@MehdiGholam не могли бы вы поделиться решением или другим выходом из этой проблемы прямо сейчас?

Richard MacCutchan

Вам нужно ответить человеку, с которым вы хотите связаться.

Patrice T

Чтобы ответить на комментарий, используйте кнопку "ответить" слева от имени пользователя (поверх комментария).

Nishikant Tayade

Хорошо.Не могли бы вы помочь мне сейчас?

Eric Lynch

Looking at your attempted implementation, you are missing a few elements. With a circular buffer, one would expect your pointer rxOffset to proceed towards the end of the buffer (at buffer size) wrapping (or resetting) to the start. You seem to be missing logic to consider this case. Typically, a circular buffer would also have two pointers, which "chase" each other. One indicates where you next add data to the buffer and the other indicates where you next remove data from the buffer (aka read/write). You would also need to add logic to handle buffer overflow, mb making sure the write pointer doesn't overtake the read pointer. Finally, you probably need to handle a partial read at the buffer boundary (when a wrap occurs)...dividing your read into two parts. I have bad connectivity right now, or I'd include some sample code. I'd just Google it. It's a well-established, fairly simple pattern. There should be truckloads of samples / explanations available.

Смотрите: https://en.m.wikipedia.org/wiki/Circular_buffer
Смотрите также: http://geekswithblogs.net/blackrob/archive/2014/09/01/circular-buffer-in-c.aspx

Nishikant Tayade

@EricLynch решение,которое вы предоставили, совершенно верно, в моем классе связи последовательного порта я использую новую реализацию кольцевого буфера, предоставленную на GitHub
https://github.com/xorxornop/RingBuffer/blob/master/PartiallyConcurrent/RingBuffer.cs

Я не знаю, сколько байт пакета я получу, и это главная проблема, поэтому я пытаюсь использовать круговой/кольцевой буфер,

открытый класс DataReceiveHandle
{
public static int MAX_PACKET_LENGTH = ChannelDataCount.count;

public static bool newData = false;

public static int rxOffset = 0;
public static int rxWrite = 0;
public static int rxRead = 0;


public static byte[] rxBuffer = новый байт[MAX_PACKET_LENGTH];


public static byte[] rxPackage = новый байт[MAX_PACKET_LENGTH];




общественная статический недействительным DataReceivedHandler(объект отправителя, SerialDataReceivedEventArgs е)
{



if (e.EventType != SerialData.Chars) возврат;

Последовательный порт Порт = (последовательный порт)отправителя;



int bytesCount = порт.BytesToRead;

port.Read(rxBuffer, rxOffset, bytesCount);



SequentialRingBuffer rBuffer = новый SequentialRingBuffer(4096, rxBuffer, true);

rxWrite=rBuffer.CurrentLength;



// rxOffset = rxOffset + bytesCount;

byte[] tempArray = новый байт[256];
tempArray=rBuffer.Метод toArray();

foreach (байтовый элемент в tempArray)
{
Приставка.WriteLine(item);
}



}
Я попробовал другой способ, но не смог сделать правильную реализацию, не могли бы вы взглянуть на него?

Gerry Schmitz

И точка вашего "кругового буфера" - это...?

Я нахожу много "интересных" предметов в Princess Auto, хотя и не всегда знаю, для чего они предназначены.

2 Ответов

Рейтинг:
20

Jochen Arndt

Примечание:
Ответил на это в репосте этого вопроса, но собираюсь добавить его и здесь, потому что репост может быть удален. Добавил также еще кое-какую информацию.

Я все еще не думаю, что здесь есть необходимость в кольцевом буфере.

У вас уже есть буфер: rxBuffer Чтобы сделать это кольцевым буфером, все, что вам нужно сделать, - это обработать доступ на запись с помощью rxOffset соответственно:

// Check if we have to wrap to the begin of the buffer
int bytesToRead = min(bytesCount, rxBuffer.Length - rxOffset);
port.Read(rxBuffer, rxOffset, bytesToRead); 
rxOffset += bytesToRead;
if (rxOffset >= rxBuffer.Length)
{
    bytesToRead = bytesCount - bytesToRead;
    port.Read(rxBuffer, 0, bytesToRead); 
    rxOffset = bytesToRead;
}
Теперь у вас есть кольцевой буфер. В зависимости от того, что с этим делать, вы можете реализовать считыватель, имеющий другую переменную уровня класса, определяющую текущую позицию чтения (и проверяющую это rxOffset не будет переполнять эту позицию чтения).

Но, реализуя вышеизложенное, вы можете признать, что это не решает вашу проблему. На самом деле ваша проблема заключается не в том, как реализовать кольцевой буфер, а в том, чтобы определить, как полученные данные должны обрабатываться (обрабатываться). Это задача, которую необходимо выполнить перед написанием любой строки кода. Как только вы определили это, вы можете подумать о возможных реализациях.

Предполагая, что у вас есть начальная последовательность и поле длины, сделайте это с каждым получателем:
  • Найдите начальную последовательность, если она еще не обнаружена
  • Если обнаружен запуск и получено достаточно следующих байтов (присутствует поле длины), получите это
  • Если длина присутствует, принимайте до тех пор, пока не будут получены все байты пакета
  • Если были получены полные данные пакета, обработайте их
Обратите также внимание, что вышеизложенное определяет "состояния", как упоминалось в ответе на ваш предыдущий вопрос.

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


CPallini

5.

Рейтинг:
0

OriginalGriff

Цитата:
нет реализации по умолчанию кольцевой буфер/кольцо с#
А как вы думаете, что это такое? Класс Очереди[^] есть?
Цитата:
Этот класс реализует очередь в виде кругового массива. Объекты, хранящиеся в очереди, вставляются с одного конца и удаляются с другого.

Очереди и стеки полезны, когда вам нужно временное хранилище для информации; то есть, когда вы можете отказаться от элемента после получения его значения. Используйте Queue, если вам нужно получить доступ к информации в том же порядке, в котором она хранится в коллекции ...