#c# #asynchronous #delegates #timer
#c# #асинхронный #делегаты #таймер
Вопрос:
Я пишу программное обеспечение, которое взаимодействует с 4 устройствами через последовательный порт. Один из них, модуль ввода / вывода (ICP CON), имеет 4 входных канала (DL) и 4 выходных канала (RL). Мне нужно отслеживать состояние каналов DL, а затем, когда обнаруживается сигнал, я должен выполнить некоторую обработку, которая зависит от того, какой сигнал был обнаружен.
Я вызываю 4 метода асинхронно, каждые 500 мс (таймер), вот событие tick:
//stop the timer
timer1.Stop();
//open com port 2
Tester.Devices.ICP.OpenICPPort(2, 9600);
//dl 0
ic = new CheckDLStatus(0, this);
ic.Execute();
//dl 1
ic = new CheckDLStatus(1, this);
ic.Execute();
//dl 2
ic = new CheckDLStatus(2, this);
ic.Execute();
//dl3
ic = new CheckDLStatus(3, this);
ic.Execute();
//close com port 2
Tester.Devices.ICP.CloseICPPort(2);
//enable the timer again
timer1.Enabled = true;
public CheckDLStatus(int DL, Form1 F1)
{
//form 1 instance
f1 = F1;
// setup the delegate to call
switch (DL)
{
case (0):
{
checkDL_delegate = new checkDL(
BusinessLogicLayer.Classes.
DevicesCommunication.CheckDl0);
break;
}
case (1):
{
checkDL_delegate = new checkDL(
BusinessLogicLayer.Classes.
DevicesCommunication.CheckDl1);
break;
}
case (2):
{
checkDL_delegate = new checkDL(
BusinessLogicLayer.Classes.
DevicesCommunication.CheckDl2);
break;
}
case (3):
{
checkDL_delegate = new checkDL(
BusinessLogicLayer.Classes.
DevicesCommunication.CheckDl3);
break;
}
}
}
public static void CheckDl2()
{
//declare
bool currentStatus;
try
{
//input
currentStatus = DevicesCommunication.Dl_2_On;
//should be false at the start of the test,
//so when it becomes true, the change is detected immediately
//dl2?
if (ICP.LookForSignal_DL2((short)2,
Util.Classes.Util.ResolveComPortNumber(
Cache.settings.icpModulePort),
Convert.ToInt32(Cache.settings.icpModuleBaudRate)))
{
//signal detected
DevicesCommunication.Dl_2_On = true;
}
else
{
//signal not detected
DevicesCommunication.Dl_2_On = false;
}
//check, if status of DL2 has been changed
//(from true to false, from false to true)
if (currentStatus != DevicesCommunication.Dl_2_On)
{
//status from before checking signal is different
// from status read from the device so
//status has changed
if (DevicesCommunication.Dl_2_On)
{
DevicesCommunication.DL2_apperancesCounter = 1;
//TODO
//process
//ProcessDL2();
}
}
else
{
//status did not change
//just clear buffer
ClearBuffer();
}
return;
}
catch (Exception ex)
{
Util.Classes.ErrorLogging.LogError(ex, true);
//EndCurrentTest();
return;
}
}
Execute()
метод, который вызывает делегат:
public void Execute()
{
// call the method on the thread pool
checkDL_delegate.BeginInvoke(
this.CallBack, null);
//checkDL_delegate.Invoke();
}
Метод, который вызывается для проверки состояния DL2:
public static bool LookForSignal_DL2(short DL_number, int port, int baudRate)
{
//declare
bool iBit;
try
{
//check if there is a signal at specified Dl_number
iBit = DCON.Read_DI_Bit(Convert.ToByte(port), 1, -1,
DL_number, 16, 0, 100);
//return resposne
return iBit; //true/false
}
catch (Exception ex)
{
Util.Classes.ErrorLogging.LogError(ex, true);
return false;
}
}
Моя проблема в том, что когда я включаю сигнал на канале DL2, и я вызываю LookForSignal_DL2
так, без таймера и асинхронных вызовов (только для теста):
private void button25_Click(object sender, EventArgs e)
{
ICP.OpenICPPort(2, 9600);
if (ICP.LookForSignal_DL2(2, 2, 9600))
{
MessageBox.Show("True");
}
else
{
MessageBox.Show("false!");
}
ICP.CloseICPPort(2);
}
Это работает — возвращает true .
Если в Execute()
методе, который я использую Invoke
, который делает вызов метода синхронным — он работает (возвращает true), но таким образом я могу проверять только 1 сигнал одновременно.
Если в Execute()
методе, который я использую BeginInvoke
, он не работает, он возвращает false, даже если в DL2 есть сигнал.
Я признаю, что не знаю, что происходит. У вас есть какие-нибудь идеи?
Комментарии:
1. Что такое
this.Callback
?2. обратный вызов private void(IAsyncResult ar) { checkDL_delegate. EndInvoke(ar); updateStatus_delegate = новый статус обновления(f1.UpdateDLStatus); if (f1.InvokeRequired) { f1.Invoke(updateStatus_delegate); } else { f1.UpdateDLStatus(); } }
3. И что делает
CheckDLStatus
метод? Было бы действительно полезно, если бы вы могли обновить свой вопрос, включив в него весь вызываемый вами код.4. BeginInvoke() возвращается немедленно и не блокируется, это означает, что он не ждет сигнала DL2, а LookForSignal_DL2 возвращает false . Скажите мне, если я ошибаюсь.
5. Когда он возвращает false в асинхронном режиме .. есть ли ошибка, записанная в вашем журнале? Я заметил, что вы возвращаете false при ошибке .. может быть, выбрасываете исключение, пока не отследите его? Я признаю, что прошло несколько лет с тех пор, как я занимался последовательным портом, и это было в .net 2 … но что я помню, так это открытие порта, а затем ожидание запуска события, сообщающего мне, что поступил сигнал. Ваш метод опроса порта кажется мне немного странным.. но тогда я не знаю ваших системных требований… просто подумал, что стоит упомянуть об этом на случай, если вы выберете сложный маршрут, чтобы сделать что-то простое (как я часто делаю :))
Ответ №1:
Я понял это, если это кому-нибудь поможет, я допустил ошибку здесь (жирный текст):
//stop the timer
timer1.Stop();
//open com port 2
Tester.Devices.ICP.OpenICPPort(2, 9600);
//dl 0
ic = new CheckDLStatus(0, this);
ic.Execute();
//dl 1
ic = new CheckDLStatus(1, this);
ic.Execute();
//dl 2
ic = new CheckDLStatus(2, this);
ic.Execute();
//dl3
ic = new CheckDLStatus(3, this);
ic.Execute();
Тестер.Devices.ICP.CloseICPPort(2);
Я запускал свои методы асинхронно, но выполнение кода продолжалось, и каждый раз порт закрывался до того, как какой-либо из методов мог проверить наличие сигнала. К сожалению, библиотека SDK в этом случае не возвращает никаких ошибок, поэтому она просто продолжала возвращать false .
Спасибо за ваши комментарии.