Win32APIによるシリアル受信
Posted: 2014年4月03日(木) 16:47
環境
Win7 32bit
VS2010 VC++
随分昔に作ったWin32APIをシリアル受信のソースなのですが、上記環境にソース流用して使用したところ
おかしな現象が発生しています。
●発生している現象
1.WaitCommEventで止まらない
起動直後でまだ何も受信していない時はWaitCommEventで止まるのですが、
シリアルから受信後、イベントリセットしてWaitCommEventを再度行うと、
未受信なのにEV_RXCHARで抜けてしまいます。
しかし、受信データ長(COMSTATのcbInQue)は0です。
2.受信が遅い
端末から送信してからGetOverlappedResultで受信完了となるまで約3秒かかります。
このソース以外のツールでれば即座に受信するので、受信ハードや送信側の問題は無さそうです。
1、2の原因について教えていただけないでしょうか。
ソース(受信スレッド内から一部抜粋)
シリアルポート作成部分
Win7 32bit
VS2010 VC++
随分昔に作ったWin32APIをシリアル受信のソースなのですが、上記環境にソース流用して使用したところ
おかしな現象が発生しています。
●発生している現象
1.WaitCommEventで止まらない
起動直後でまだ何も受信していない時はWaitCommEventで止まるのですが、
シリアルから受信後、イベントリセットしてWaitCommEventを再度行うと、
未受信なのにEV_RXCHARで抜けてしまいます。
しかし、受信データ長(COMSTATのcbInQue)は0です。
2.受信が遅い
端末から送信してからGetOverlappedResultで受信完了となるまで約3秒かかります。
このソース以外のツールでれば即座に受信するので、受信ハードや送信側の問題は無さそうです。
1、2の原因について教えていただけないでしょうか。
ソース(受信スレッド内から一部抜粋)
SetCommMask(m_hComm, EV_RXCHAR); // EV_RXCHAR = 1 文字受信し、入力バッファに入れたとき。
ovlpd_rd.Offset = 0;
ovlpd_rd.OffsetHigh = 0;
ovlpd_rd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ovlpd_com.Offset = 0;
ovlpd_com.OffsetHigh = 0;
ovlpd_com.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
MSG msg;
while (1) {
WaitCommEvent(m_hComm, &dwEvent, &ovlpd_com); // 一文字受信するのを待つ
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if ((dwEvent & EV_RXCHAR) == EV_RXCHAR) {
dwReadlength = 0;
dwLrc = 0;
if (ReadFile(m_hComm, RcvBuf, sizeof(RcvBuf), &dwReadlength, &ovlpd_rd) == 0) {
// ポートリード
dwLrc = GetLastError();
dwReadlength = 0;
if (dwLrc == ERROR_IO_PENDING) { // 読み取り実行中である
dwEndtime = timeGetTime() + (30 * 1000);
while (!GetOverlappedResult(m_hComm, &ovlpd_rd, &dwReadlength, FALSE)) {
// 読み取り完了まで待つ
if (timeGetTime() > dwEndtime) {
// タイムアウト
ERRMSG("受信タイムアウト発生\n");
break;
}
}
}
}
if (dwLrc == 0 || dwLrc == ERROR_IO_PENDING) { // リード成功
if (pFunc)
{
// 受信処理
(*pFunc)(dwReadlength, RcvBuf);
}
}
}
// イベントリセット
ResetEvent(ovlpd_rd.hEvent);
ResetEvent(ovlpd_com.hEvent);
}
// デバイスのオープン
m_hComm_ = CreateFile(PortName,
(GENERIC_READ | GENERIC_WRITE),
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, // 非同期 I/O を許す
NULL);
if (m_hComm_ == INVALID_HANDLE_VALUE)
return FALSE;
// 入出力バッファの許容量設定
SetupComm(m_hComm_, 2000L, 2000L);
// タイムアウト情報のセット
COMMTIMEOUTS m_CommTime;
m_CommTime.ReadIntervalTimeout = 0xFFFFFFFF;
m_CommTime.ReadTotalTimeoutMultiplier = 0;
m_CommTime.ReadTotalTimeoutConstant = ReadTimeOut;
m_CommTime.WriteTotalTimeoutMultiplier = 0;
m_CommTime.WriteTotalTimeoutConstant = WriteTimeOut;
// タイムアウトの設定
SetCommTimeouts(m_hComm_, &m_CommTime);
// 通信デバイス情報の取得
GetCommState(m_hComm_, &m_Dcb_);
// 通信デバイス情報の修正
m_Dcb_.BaudRate = BaudRate;
m_Dcb_.ByteSize = ByteSize;
m_Dcb_.Parity = Parity;
m_Dcb_.StopBits = StopBits;
m_Dcb_.fRtsControl = RTS;
m_Dcb_.fDtrControl = DTR;
if (!SetCommState(m_hComm_, &m_Dcb_)) {
CloseHandle(m_hComm_);
m_hComm_ = INVALID_HANDLE_VALUE;
return FALSE;
}