Я работаю над проектом последовательного монитора на основе последовательного монитора 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). Я был бы рад, если бы вы тоже могли привести несколько примеров.