Как я могу использовать EventWaitHandle для создания события?
Я пишу программу, которая слушает через последовательный порт. У меня уже есть код, который использует драйверы VCP (виртуальный COM-порт), чтобы открыть последовательное соединение, а затем добавить обработчик событий для любого времени получения данных. Этот код выглядит примерно так:
public void OpenPort(string portNumber)
{
_port = new SerialPort(
portName: portNumber,
baudRate: 9600,
parity: Parity.None,
dataBits: 8,
stopBits: StopBits.One
);
_port.DataReceived += ReadData;
}
private void ReadData(object sender, SerialDataReceivedEventArgs e)
{
string data = _port.ReadExisting().Trim();
Console.WriteLine("Received: " + data);
}
Это прекрасно работает. Мне очень легко понять, как настроить события, используя +=
нотации. Но я пытаюсь переключиться с использования драйверов VCP на использование драйверов D2XX, предоставляемых FTDI. У меня есть большая часть эквивалентного кода, который мне нужно написать, за исключением того, что я могу читать данные всякий раз, когда происходит событие "данные получены".
Драйвер D2XX включает в себя один метод для настройки обработчиков событий при получении данных, называемый SetEventNotification
, Вот как выглядит сигнатура метода:
SetEventNotification(UInt32 eventMask, EventWaitHandle eventHandle);
Первый параметр достаточно прост (у них есть некоторые предопределенные уинты, которые вы можете передать, чтобы определить, когда должно сработать событие), но я никогда раньше не работал напрямую с EventWaitHandles, и мне было трудно понять документацию, поэтому я ' У меня проблемы с началом работы.
В конце дня... Я хотел бы иметь метод прослушивателя событий, который выполняет задачу чтения и который я могу назначить, используя +=
оператор, как я делал выше с драйвером VCP.
Исходя из того, что я читал, похоже, мне придется создать новый Thread
что по сути опрашивает непрерывно для сигнала EventWaitHandle? Или что-то типа того? Будем благодарны за любые примеры или примеры кода, чтобы начать (или закончить!).
Вот что у меня так далеко:
public void OpenPort(string portNumber)
{
_port = new FTDI();
var status = _port.OpenBySerialNumber(portNumber);
if (FTDI.FT_STATUS.FT_OK != status) throw new Exception();
status = _port.SetBaudRate((UInt32) 9600);
if (FTDI.FT_STATUS.FT_OK != status) throw new Exception();
status = _port.SetDataCharacteristics(
DataBits: FTDI.FT_DATA_BITS.FT_BITS_8,
StopBits: FTDI.FT_STOP_BITS.FT_STOP_BITS_1,
Parity: FTDI.FT_PARITY.FT_PARITY_NONE
);
if (FTDI.FT_STATUS.FT_OK != status) throw new Exception();
var evHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "");
_port.SetEventNotification(FTDI.FT_EVENTS.FT_EVENT_RXCHAR, evHandle);
// ... now what?
}
public void ReadData(object sender, EventArgs e)
{
UInt32 bytesAvailable = 0;
_port.GetRxBytesAvailable(ref bytesAvailable);
string data;
UInt32 bytesRead = 0;
_port.Read(out data, bytesAvailable, ref bytesRead);
data = data.Trim();
Console.WriteLine("Received: " + data);
}
1 ответ
Мне нужно будет создать новый поток, который будет непрерывно опрашивать сигнал EventWaitHandle.
Опросов нет. Но ждет, да. Все, что может сделать дескриптор события, это позволить потоку спать до тех пор, пока событие не будет сигнализировано. Обратите внимание, что "событие" здесь означает нечто совершенно отличное от "события" в C#, хотя, конечно, вы можете использовать первое как часть реализации последнего.
Честно говоря, не совсем понятно, почему вы идете вниз по этой части. Вы имеете дело с данными, передаваемыми через стандартный последовательный порт? Если так, то никогда не должно быть необходимости использовать какой-либо сторонний API; Windows и.NET предоставляют все, что вам нужно, и вы должны придерживаться этого. Что с помощью этого стороннего API дает вам то, что вы не можете достичь с помощью стандартного SerialPort
учебный класс?
Что касается самого события, без дополнительного контекста (и нет, вряд ли кто-то просмотрит PDF-файл, на который вы ссылаетесь, чтобы выяснить, как создать решение "под ключ"), все, что можно предложить, - это общее описание того, как Вы можете использовать дескриптор события для реализации события:
public event EventHandler DataReceived;
private bool _done;
private void PortListener(EventWaitHandle waitHandle)
{
while (true)
{
waitHandle.WaitOne();
if (_done)
{
break;
}
EventHandler handler = DataReceived;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
public void StartListening(EventWaitHandle waitHandle)
{
_done = false;
new Thread(() => PortListener(waitHandle)).Start()
}
public void StopListening(EventWaitHandle waitHandle)
{
_done = true;
waitHandle.Set();
}
Вышеуказанное обеспечивает DataReceived
Событие C#, которое возникает каждый раз, когда дается сигнал ожидания дескриптора. Предполагается событие автоматического сброса. Вы также можете использовать ручной сброс, просто (разумеется) вручную сбрасывая дескриптор события в любое время, когда он сигнализирует и вы вызвали событие C#.
Для этого он просто поддерживает внутренний флаг _done
указывает, должен ли поток работать или нет, и предоставляет Start...
а также Stop...
методы, которые очищают флаг и запускают поток с его циклом, а также устанавливают флаг и сигнализируют событие соответственно.