Я пытаюсь написать простой класс для работы с последовательным портом в Windows, используя стандартную библиотеку Windows.
Мне нужно проверить, пуст ли входной буфер.
До сих пор я пытался использовать SetCommEvent с опцией EV_RXCHAR, однако этот метод не работает. Функция, кажется, ждет прибытия нового символа. Если бы я попытался отправить char, заснуть на секунду и применить это, функция не вернулась бы - она продолжает ждать.
bool isEmpty()
{
DWORD dwEventMask = 0;
DWORD Status = 0;
if (CheckAsyncRead())
return false;
if (!SetCommMask(hPort, EV_RXCHAR)) //wait for char receival
std::cout << "Error in creating Overlapped event" << std::endl;
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (WaitCommEvent(hPort, &dwEventMask, &osReader))
{
//close event handle
return false;
}
Status = WaitForSingleObject(osReader.hEvent, 10);
//I wait for 10 ms in case the function doesn't return immediately
//Close event handle
if (Status == WAIT_OBJECT_0)
{
return false;
}
else
return true;
}
Я надеялся, что WaitCommEvent или WaitForSingleObject вернутся, если в буфере присутствуют какие-либо символы, но этого не происходит, если между получением символа и вызовом функции ожидания есть более длительная пауза.
да. Сейчас у меня следующие настройки: ReadIntervalTimeout = 2; ReadTotalTimeoutConstant = 0; tReadTotalTimeoutMultiplier = 0; WriteTotalTimeoutConstant = 0; WriteTotalTimeoutMultiplier = 3;
Вы можете использовать ЧитатьФайл() с дескриптором, открытым с помощью СоздатьФайл() с флагом FILE_FLAG_OVERLAPPED. Если функции ReadFile() нечего возвращать, она вернет последнюю ошибку ERROR_IO_PENDING, что означает, что ваш буфер в настоящее время пуст.
Настройки тайм-аута также имеют значение. На самом деле имеют значение только настройки таймаута.
Вы можете использовать Функция ClearCommError, чтобы узнать размер данных, хранящихся в буфере.
В результате вызова cbInQue из Структура КОМСТАТ, подлежащего уведомлению, имеет размер данных, хранящихся во входном буфере.
Спасибо. Именно то, что мне было нужно.
Будьте осторожны, потому что ClearCommError()
имеет побочные эффекты. Не относитесь к нему как к пассивному добытчику! (Эти побочные эффекты являются источником серьезной ошибки в классе .NET SerialPort.)
@Ben Voigt, если есть подробная информация или ссылка о причине и мерах, пожалуйста, представьте.
Побочные эффекты описаны на странице MSDN, на которую вы ссылаетесь.
@Ben Voigt Является ли преждевременный возврат WaitCommEvent одним из этих побочных эффектов? Потому что я в настоящее время столкнулся с такой проблемой.
@RadekHlavinka: Вы уверены, что не видите побочного эффекта SetCommMask
? Документально подтверждено, что WaitCommEvent
возвращается немедленно. Возможно, замешан ClearCommError
, но, скорее всего, виновато задокументированное взаимодействие. Я имел в виду тот факт, что вся информация об ошибке очищается вызовом. Ошибка в .NET состоит в том, что два потока вызывают ClearCommError
, один использует информацию об ошибке, другой использует длину входного буфера и отбрасывает ошибки.
@Ben Voigt: я уверен. Я попытался выполнить код шаг за шагом и добавил простые маркеры к любому использованию SetCommEvent
(простая запись в std::cout
). Поток входит в состояние ожидания и через некоторое время выходит из него, переходя к ReadFile
, где он ожидает бесконечно, потому что буфер пуст, данные не отправляются, и я не использую Total timeout
. Что меня действительно озадачивает, так это то, что это появляется только во втором проходе потока - в 1-м проходе поток ожидает получения символа, как и предполагалось.
@Radek Hlavinka, было бы лучше задать новый вопрос вместе с подробной информацией.
@RadekHlavinka: Это SetCommMask
, а не SetCommState
(и я даже не вижу функции с именем SetCommEvent
), которая прерывает WaitCommEvent
.
@RadekHlavinka: я бы все же предложил вам разработать свой класс, чтобы вам не нужно было спрашивать, сколько данных находится в буфере. Вместо этого просто получите все имеющиеся данные (установите нулевой общий тайм-аут чтения, как описано в COMMTIMEOUTS
), а затем проверьте длину полученных данных. Даже если не считать побочных эффектов ClearCommError
, длина полученного вами буфера устаревает еще до того, как функция вернется к вам, поэтому вы вынуждены совершить логическую ошибку TOCTOU.
Я создал новый вопрос, в котором попытался лучше объяснить проблему (stackoverflow.com/questions/55697983/…). Также я не использую ClearCommError
для получения количества данных во входном буфере, просто чтобы посмотреть, есть ли они.
Вы звоните
SetCommTimeouts
? С какими ценностями?