S
S
Sechih2021-10-19 19:08:30
USB
Sechih, 2021-10-19 19:08:30

Process byte stream from USB CDC C#?

Hello, I'm trying to write a winform application that accepts data via usb-cdc, I can only say that I'm getting to know C # in a dense way, I'm gradually learning. I only know pure C, I write under stm32. Using examples from the Internet, I wrote data reception in a separate thread, in debugging you can see how everything is saved to the _bufer array. Now we need to process the data and calculate / check the CRC, and display it in the listview. What is the best way to do this (I want to initially learn how to write correctly)? The idea to create another method, through a "pointer" for example ref, refer to _bufer inside the method, and inside the created method to process this data and display it in the listview, can even call this method in a separate thread?
How to properly get data from this buffer, in fact, they are stored in item which is the same array with var?
They break the perception of classes a little after the usual structures in SI, you can try to play around with static methods or classes, but in the video tutorials they say that they should not be used in all cases.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;


namespace PS_aide_1._0
{
    public partial class Form1 : Form
    {
        bool flag_btn_StartStop_click ;
        bool flag_btn_open_click;

        private const int DataSize = 39;    //  число в байтах
        private readonly byte[] _bufer = new byte[DataSize];
        private int _stepIndex;
        private bool _startRead;

        public Form1()
        {
            InitializeComponent();
            SerialPortFind();
        }

        private void SerialPortFind()
        {
            try
            {
                String[] ports = SerialPort.GetPortNames();
                cboPort.Items.AddRange(ports);
                cboPort.SelectedIndex = 0;
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            
        }
        private void SerialPortInit(bool flag) 
        {
            if (flag == true)
            {
                serialPort1 = new SerialPort();
                serialPort1.PortName = cboPort.Text;
                serialPort1.Open();
            }
            else {
                serialPort1.Close();
            }

        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void OpenPort_Btn_Click(object sender, EventArgs e)
        {
            flag_btn_open_click ^= true;
           if (flag_btn_open_click)
            {
                OpenPort_Btn.Text = "Close";
                Start_Stop_button.Enabled = true;
                try
                {SerialPortInit(flag_btn_open_click);}
                catch (Exception ex)
                {MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
                 return; }
            }
            else
            {
                OpenPort_Btn.Text = "Open";
                Start_Stop_button.Text = "Start";
                Start_Stop_button.Enabled = false;
                SerialPortInit(flag_btn_open_click);
                flag_btn_StartStop_click = false;
            }



        }

        private void Start_Stop_button_Click(object sender, EventArgs e)
        {
            flag_btn_StartStop_click ^= true;
            if (flag_btn_StartStop_click)
            {
                Start_Stop_button.Text = "Stop";
                //Thread thread = new Thread( delegate (){/*вызываемый метод*/}  );
                //thread.Start();
                //или так
                // Thread thread = new Thread(()=>{/*вызываемый метод*/});
                //thread.Start();
                //или так
                //new Thread(() => {/*вызываемый метод*/}).Start();
                new Thread(() => {

                        serialPort1.DataReceived += serialPort1_DataReceived;
                      
                }) { Priority = ThreadPriority.Normal }.Start();
                
                //Parallel.Invoke(() => {/*task1*/}, ()=> { /*task2*/}, ()=> {/*task3*/});

                //byte[] buf = new byte[38];
                ////serialPort1.Read(buf,0,38);
                //string temp = mySerialPort.ReadExisting();
                //    listBox1.Items.Add(temp);     
            }
            else
            {
                Start_Stop_button.Text = "Start";
            }

        }

       private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            var port = (SerialPort)sender;
            try
            {
                //  узнаем сколько байт пришло
                int buferSize = port.BytesToRead;
                for (int i = 0; i < buferSize; ++i)
                {   
                    byte bt = (byte)port.ReadByte();//  читаем по одному байту
                    if (0x02 == bt)  //  если встретили начало кадра (0xFF) - начинаем запись в _bufer
                    {
                        _stepIndex = 0;
                        _startRead = true;
                        // >>> закомментировать если надо сохранять этот байт
                        //_bufer[_stepIndex] = bt;
                        //++_stepIndex;
                        //<<<
                    }
                    if (_startRead) //  дописываем в буфер все остальное
                    {
                        _bufer[_stepIndex] = bt;
                        ++_stepIndex;
                    }

                    if (_stepIndex == DataSize && _startRead) //  когда буфер наполнился данными
                    {

                       
                        var item = _bufer[39];//здесь хранятся данные
                        _startRead = false;
                    }
                }

            }
            catch { }
        }


    }
}

616eec22308d2067262599.jpeg
616eed0d03f48908044816.png

Answer the question

In order to leave comments, you need to log in

1 answer(s)
I
Ilya Golets, 2021-10-28
@igolets

  1. It would be nice to put the code that works with the equipment (reads data) into a separate class and make an interface for it. Why is it necessary - if you need to separate the work of the "hardware" and the interface programmer, the second one can be given the opportunity to run the program with a "stub" so that he saws the interface without access to the hardware. Well, or to demonstrate the program, run without access to the hardware.
  2. Accordingly, according to the event on the form (start / stop), some methods of the class of working with iron are called and data is received / accumulated. Depending on the logic of this class, events are called (upon receipt of a byte, or a complete packet)
  3. According to the event (the form code hung event handlers when initializing the code working with the hardware), the form already refers to an instance of the class that works with the hardware and receives data from it (most likely in raw binary form) and does something with them. For example, it converts to a model class, which is added to the bindingsors (List), which is used as a DataSource for the ListView
  4. It is also better to put the code for translating binary data into a model into a separate class. I can assume that there may be different forms of data presentation.

Briefly so.
Well, the simulation class code will simulate the work of a real class, cause the necessary events and give pre-recorded data, or generate it according to some algorithm. Switching between a stub and a real class is implemented, for example, using Dependency Injection, for C # you can use something like https://habr.com/en/post/50845/ . The config file specifies which class is used and that's it, the same code in runtime uses different classes. Personally, for example, this is how I implement work with fiscal apparatuses and plastic card payment terminals.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question