Попытка распечатать интенсивные входящие последовательные данные в richtextbox - PullRequest
1 голос
/ 06 мая 2020

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

Есть 2 основные c функции - чтение последовательных данных и визуализация их в richtextbox , запись последовательных данных, а также визуализация их в richtextbox. Возникает проблема, когда связь очень интенсивная (arduino отправляет строку так быстро, как только может), и пользовательский ввод разрезает некоторые из полученных строк пополам. Я создал алгоритм для отделения входных строк от выходных в richtextbox, установив флаги отправки / получения. Однако это сделало программу странной. Иногда команда, отправленная на , arduino просто не отображает в richtextbox , но данные из arduino визуализируются отлично. Я пробовал устанавливать точки останова в методе визуализации пользовательского ввода, и они редко активировались. Более того, я также установил точки останова для визуализации метода чтения данных, и они также редко активировались. Однако форма не запаздывала и не зависала, и команды «летели» в поле richtext, вопреки наблюдаемому поведению точек останова. Алгоритм печати тяжелый, потому что я реализовал многоцветную печать.

Что я пробовал:

- пробовал подход с блокировкой сбора. Просто поместите действия печати в очередь и выполните действия одно за другим, используя 2 дополнительных потока к основному (Task.Factory.StartNew). Проблема заключалась в том, что очередь была заполнена более чем 3000 действиями в течение минуты, и все это отставало примерно на 15 секунд.

-i попытался запустить новый Task.Factory для каждого метода приема / отправки для каждой печати новой команды и блокировки потока до тех пор, пока команда не будет напечатана в richtextbox. Это тоже слишком медленно.

Наконец Мне пришла в голову идея просто установить флаги и разрешить или запретить событие печати. При использовании этого подхода вводимые пользователем данные почти никогда не печатаются в richtextbox. : (

Алгоритм печати:

    void printToConsole(string print, Color txtColor, string part, Color partColor, bool isMsg, bool endNL)
    {
        while (print.Contains('\r'))
            print = print.Replace("\r", "");

        for (int i = 0; i < print.Length; i++)
        {
            if (newString)
            {
                newString = false;
                printTimeAndPart(part, partColor);
            }
            else if (i == 0 && !prevStrHadNL && isMsg != prevWasMsg)
            {
                printNLTimeAndPart(part, partColor);
            }
            else if (i == 0 && prevStrHadNL)
            {
                printNLTimeAndPart(part, partColor);
            }
            else if (i == print.Length - 1)
            {
                if (print[i] == '\n')
                {
                    if (endNL && isMsg != prevWasMsg)
                        AppendText("\n");
                    prevStrHadNL = true;
                    break;
                }
                else
                {
                    if (endNL)
                        AppendText("\n");
                    prevStrHadNL = false;
                }
            }

            if (print[i] == '\n')
            {
                printNLTimeAndPart(part, partColor);
            }
            else
                AppendText(print[i].ToString(), txtColor);
        }
        prevWasMsg = isMsg;
    }

    private void printNLTimeAndPart(string part, Color partColor)
    {
        AppendText("\n");
        printTimeAndPart(part, partColor);
    }

    private void printTimeAndPart(string part, Color partColor)
    {
        if (timestamp == 1)
            AppendText(DateTime.Now.ToString("HH:mm:ss.fff"), timeColor);
        AppendText(part, partColor);
    }

    private void AppendText(string txt, Color clr)
    {
        if (serialControl.ReadAllowed)
        {
            if (rtArea.InvokeRequired)
            {
                MethodInvoker mi = delegate ()
                { rtArea.AppendText(txt, clr); };
                Invoke(mi);
            }
            else
                rtArea.AppendText(txt, clr);
        }
    }

    private void AppendText(string txt)
    {
        if (serialControl.ReadAllowed)
        {
            if (rtArea.InvokeRequired)
            {
                MethodInvoker mi = delegate ()
                { rtArea.AppendText(txt); };
                Invoke(mi);
            }
            else
                rtArea.AppendText(txt);
        }
    }

Печать данных последовательного чтения:

wait1 и wait2 - флаги. Если wait1 имеет значение false, текущее сообщение, вводимое пользователем, не печатается. Когда wait2 имеет значение false, пользовательский ввод может быть распечатан. Если доступ к операции печати был запрещен, он выполняется после операция, которая его заблокировала. (По крайней мере, это идея)

    private void Port_dataRecieved(string a)
    {
        if (!consoleUsed)
        {
            newString = true;
            consoleUsed = true;
        }

        inputVal = a;
        if (!wait1)
        {
            inputAccDenied = false;
            wait2 = true;
            PrintInput(inputVal);
            wait2 = false;
        }
        else
            inputAccDenied = true;

        if (msgAccDenied)
        {
            PrintMsg(msgVal);
            msgAccDenied = false;
        }
    }


    private void PrintInput(string input)
    {
        printToConsole(input, inTxtColor, inPrefix, inPrefColor, false, false);
    }

Это метод dataReceived из моего класса последовательного контроллера: Я пробовал несколько способов чтения последовательных данных и раскомментированных один - самый стабильный, который я пробовал.

    private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
    /*    byte[] buffer = new byte[blockLimit];
          Action kickoffRead = null;
          kickoffRead = delegate
          {
              port.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate (IAsyncResult ar)
              {
                  try
                  {
                      int actualLength = port.BaseStream.EndRead(ar);
                      byte[] received = new byte[actualLength];
                      Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
                      string rcv = Encoding.Default.GetString(received);
                      dataRecieved(rcv);
                  }
                  catch (IOException exc)
                  {
                      //handleAppSerialError(exc);
                  }
                  kickoffRead();
              }, null);
          };
          kickoffRead(); 
        */
        if (ReadAllowed)
        {
            string a = port.ReadExisting();
            //port.DiscardInBuffer();
            dataRecieved(a); //Raise event and pass the string to Form1 serial_dataReceived
        }
    }

Итак, мне нужен совет о том, как именно печатать многоцветные сообщения, не врезаясь друг в друга, печатать каждый раз, быстро, с низкой загрузкой процессора (сейчас это примерно 35% при полной нагрузке (интенсивная передача Arduino) на i5-4310m). Я был бы рад, если бы вы тоже могли привести несколько примеров.

...