Немного предыстории моего кода:
Пишу библиотеку для связи с 8-дорожечным рекордером Sound Devices 788T. Я использую его USB-порт для связи с ним по собственному протоколу RS232 под названием «C. Link», разработанному Sound Devices. Используя документацию по протоколу, выпущенную Sound Devices, я успешно смог отправлять команды, читать настройки и, по сути, выполнять все необходимые мне задачи по одной. Проблема, с которой я сталкиваюсь, возникает, когда я отправляю запрошенное пользователем сообщение во время обычной функции «тик», которая обновляет постоянно меняющиеся переменные с машины, т. е. сгенерированный тайм-код SMPTE, показания счетчиков и т. д.
Сообщение отправляется, я получаю ответ, и функция галочки продолжает обновляться как следует еще несколько секунд. После этого чтение из открытого последовательного порта замедляется до одного байта в секунду. Я не понимаю, почему. Если я не отправлю сообщение, моя тестовая программа сможет бесконечно отправлять и получать обычные тиковые сообщения с ожидаемой скоростью. Но я сам отправляю команду и получаю ответ, тиковые сообщения принимаются с ожидаемой скоростью только в течение нескольких секунд, а затем резко останавливаются со скоростью один байт в секунду. Он не падает или что-то в этом роде. Он продолжает отправлять и получать правильные данные, он просто считывает их из последовательного порта со скоростью один байт в секунду.
И пользовательские сообщения, и тиковые сообщения используют одну и ту же функцию для отправки и получать данные через последовательный порт. Вот код с кратким объяснением классов. Пожалуйста, извините меня за все мои команды Debug.WriteLine. Я использовал их и счетчик, чтобы выяснить, все ли работает в правильном порядке, и это так.
Буду очень признателен за любую помощь!
VM - виртуальная машина, представляющая реальный рекордер 788T. Он получает такие вещи, как тайм-код физического устройства, счетчики, статистику записи и т. д., и сохраняет их, чтобы мы могли получить к ним доступ без необходимости постоянно запрашивать их у реальной машины или до тех пор, пока они не изменятся. Этот класс обрабатывает генерацию сообщений C. Link и отправляет их командиру для отправки через последовательный порт.
Commander — отвечает за все, что связано с последовательным соединением. Он отправляет и получает последовательные данные, а также отправляет все ответы, полученные от физической машины, обратно на виртуальную машину.
Вот процедура проверки виртуальной машины:
Код: Выделить всё
private void DoPreTick(object ?source, ElapsedEventArgs e)
{
Debug.WriteLine("DoPreTick()" + counter + ": Tick timer triggered! Disabling timer...");
tickTimer.Enabled = false;
if(!bIsTickAllowed)
{
Debug.WriteLine("DoPreTick()" + counter + ": Tick not allowed. Won't be ticking this go around!");
}
if (!IsTicking())
{
Debug.WriteLine("DoPreTick()" + counter + ": Doing pre-tick!");
if (GetCLinkState() == CLinkState.Online && !commander.CommsAreBusy())
{
//Process our outbox first
if (bOutboxFullToken && !bIsProcessingUserMessage && !bOutboxProcessedToken)
{
Debug.WriteLine("DoPreTick()" + counter + ": Processing user message: " + outbox.ToBytes()[3]);
Task t = Task.Factory.StartNew(() => ProcessNextUserMessage());
t.Wait();
}
Debug.WriteLine("DoPreTick()" + counter + ": Ending pre-tick!");
if (!IsTicking() && bIsTickAllowed)
{
Debug.WriteLine("DoPreTick()" + counter + ": Tick allowed, running tick!");
DoTick();
}
}
}
Debug.WriteLine("DoPreTick()" + counter + ": All ticking completed! Re-enabling tick timer...");
tickTimer.Enabled = true;
}
private void DoTick()
{
Debug.WriteLine("DoTick()" + counter + ": Doing Tick!");
SetIsTicking(true);
if (GetCLinkState() == CLinkState.Online && !commander.CommsAreBusy() && !bIsProcessingUserMessage && !bOutboxFullToken)
{
//Regular upkeep
GetUnitTC();
GetUnitMeters();
}
SetIsTicking(false);
Debug.WriteLine("DoTick()" + counter + ": Tick Finished!");
} //Tick is called every tickInterval while we are connected to a 788
private void ProcessNextUserMessage()
{
counter++;
Debug.WriteLine("ProcessNextUserMessage()" + counter + ": Setting bIsProcessingUserMessage to true!");
bIsProcessingUserMessage = true;
if (outbox.GetUnitID() == 0xFE)
{
commander.SendCLinkBytes(outbox, false);
Debug.WriteLine("ProcessNextUserMessage()" + counter + ": Message was 0xFE, not getting reply!");
Thread.Sleep(250);
}
else
{
Debug.WriteLine("ProcessNextUserMessage()" + counter + ": Message needs a reply, overwriting outbox with reply!");
CLinkMessage reply = commander.SendCLinkBytes(outbox, true);
outbox = reply;
}
Debug.WriteLine("ProcessNextUserMessage()" + counter + ": All done. Setting user message TCS to true, setting outboxfulltoken to false, setting outboxProcessedToken to true!");
bOutboxProcessedToken = true;
bIsProcessingUserMessage = false;
bOutboxFullToken = false;
Debug.WriteLine("ProcessNextUserMessage()" + counter + ": Re-enabling tick!");
bIsTickAllowed = true;
}
Код: Выделить всё
public CLinkMessage SendCLinkMessage(CLinkMessage message)
{
if (IsTicking())
{
Debug.WriteLine("SendCLinkMessage()" + counter + ": Message Received while ticking!");
}
lock (userMessageTCS)
{
Debug.WriteLine("SendCLinkMessage(): Disabling tick for next go around!");
bIsTickAllowed = false;
if (IsAcceptingCLinkMessages())
{
SetIsAcceptingUserMessages(false);
outbox = message;
counter++;
Debug.WriteLine("SendCLinkMessage()" + counter + ": Message added to outbox. Setting outboxfulltoken to true, setting outboxprocessed token to false.");
bOutboxFullToken = true;
bOutboxProcessedToken = false;
Debug.WriteLine("SendCLinkMessage()" + counter + ": All done for now. waiting for usermessagetcs result...");
userMessageTCS = new TaskCompletionSource();
userMessageTCS.Task.Wait();
}
}
Debug.WriteLine("SendCLinkMessage()" + counter + ": Message send successful. Setting acceptingUsereMessages to true and returning contents of outbox...");
SetIsAcceptingUserMessages(true);
return outbox;
}
Код: Выделить всё
public CLinkMessage SendCLinkBytes(CLinkMessage message, bool bReturnResponse = false)
{
if (CommsAreBusy())
{
Debug.WriteLine("Commander: ERROR Comms are busy!");
}
if (commPort.IsOpen && !CommsAreBusy())
{
Debug.WriteLine("Commander: Comms not busy, sending message - " + BitConverter.ToString(message.ToBytes()));
SetCommsAreBusy(true);
byte[] messageBytes = message.ToBytes();
try
{
commPort.Write(messageBytes, 0, messageBytes.Length);
}
catch (Exception e)
{
Debug.WriteLine("Commander: ERROR writing bytes to commPort: " + e.Message);
}
if (bReturnResponse)
{
List reply = new List();
try
{
Debug.WriteLine("Commander.SendCLinkBytes(): Reading Byte 1: header");
byte b = new byte();
//Header check
//Debug.WriteLine("Commander: Reading reply...");
b = (byte)commPort.ReadByte();
if (b == 0xA5)
{
//Debug.WriteLine("Response detected!");
reply.Add(b);
//UnitID check
Debug.WriteLine("Commander.SendCLinkBytes(): Reading Byte 2: unitID");
b = (byte)commPort.ReadByte();
if (b < 63 || b == 0xFE)
{
reply.Add(b);
//Length
Debug.WriteLine("Commander.SendCLinkBytes(): Reading Byte 3: Length");
b = (byte)commPort.ReadByte();
if (b > 2 && b
Подробнее здесь: [url]https://stackoverflow.com/questions/78172950/c-sharp-com-port-slowing-down-to-read-one-byte-a-second-after-sending-message[/url]
Мобильная версия