因为近段时间接触Hid相对来说多一些,由此忽略了串口中获取cbInQue这个重要的东西,下面是错误代码
// Win32SerialPortLib.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include "Win32SerialPortLib.h"
#include
HANDLE hcomm;
EXTERN_C WIN32SERIALPORTLIB_API bool Open(char *com, int baud)
{
char szDCB[];
sprintf_s(szDCB, "baud=%d parity=%c data=%d stop=%d", baud, 'N', , );
hcomm = CreateFileA(com,
GENERIC_READ | GENERIC_WRITE,
,
NULL,
OPEN_EXISTING,
,
);
if (hcomm == INVALID_HANDLE_VALUE) return false;
return true;
}
EXTERN_C WIN32SERIALPORTLIB_API int Read(unsigned char *data, DWORD len)
{
DWORD readed;
BOOL rt = ReadFile(hcomm, data, len, &readed, NULL);
if (!rt)
{
PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT);
return ;
}
return readed;
}
EXTERN_C WIN32SERIALPORTLIB_API void Write(unsigned char *data, DWORD len)
{
if (hcomm == INVALID_HANDLE_VALUE) return;
DWORD writed;
BOOL rt = WriteFile(hcomm, data, len, &writed, NULL);
if (!rt)
{
PurgeComm(hcomm, PURGE_TXCLEAR | PURGE_TXABORT);
return;
}
}
EXTERN_C WIN32SERIALPORTLIB_API void Close()
{
if (hcomm != INVALID_HANDLE_VALUE)
{
CloseHandle(hcomm);
hcomm = INVALID_HANDLE_VALUE;
}
}
经过测试
// Win32SerialPortTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include "Win32SerialPort.h"
using namespace std;
bool _stoprequired = false;
void read_callback();
void printhex(unsigned char *data, int len);
int _tmain(int argc, _TCHAR* argv[])
{
Open("COM5", );
thread read_t(read_callback);
read_t.detach();
cout << endl;
cout << "continue in main thread." << endl;
//ab 69 42 01 fe c0 00 00 c0
unsigned char data\[\] = { 0xab, 0x69, 0x42, 0x01, 0xfe, 0xc0, 0x00, 0x00, 0xc0 };
Write(data, sizeof(data) / sizeof(unsigned char));
// 获取标准输入输出设备句柄
HANDLE hOut = GetStdHandle(STD\_OUTPUT\_HANDLE);
HANDLE hIn = GetStdHandle(STD\_INPUT\_HANDLE);
DWORD dwRes, dwState = ;
INPUT\_RECORD keyRec;
COORD crHome = { , }, crPos;
char ch;
CONSOLE\_SCREEN\_BUFFER\_INFO bInfo;
while (true)
{
ReadConsoleInput(hIn, &keyRec, , &dwRes);
if (keyRec.EventType == KEY\_EVENT)
{
// Press key down
if (keyRec.Event.KeyEvent.bKeyDown)
{
// 基础功能键
switch (keyRec.Event.KeyEvent.wVirtualKeyCode)
{
// 回车
case VK\_RETURN:
printf("\\n");
break;
// 空格
case VK\_SPACE:
Write(data, sizeof(data) / sizeof(unsigned char));
break;
case VK\_BACK: // 按删除时删掉一个字符(只能当前行操作)
GetConsoleScreenBufferInfo(hOut, &bInfo);
crPos = bInfo.dwCursorPosition;
if (crPos.X != )
{
crPos.X -= ;
}
SetConsoleCursorPosition(hOut, crPos);
printf(" ");
SetConsoleCursorPosition(hOut, crPos);
break;
case VK\_ESCAPE: // 按ESC键时退出
\_stoprequired = true;
Close();
Sleep();
CloseHandle(hOut); // 关闭标准输出设备句柄
CloseHandle(hIn); // 关闭标准输入设备句柄
return ;
default:
break;
}
// 打印字符
ch = keyRec.Event.KeyEvent.uChar.AsciiChar;
// 输出可以打印的字符(详参ASCII表)
if (ch > 0x20 && ch < 0x7e)
{
putchar(ch);
}
}
}
}
return ;
}
void read_callback()
{
unsigned char buff[];
while (!_stoprequired)
{
int n = Read(buff, );
if (n > )
{
printhex(buff, n);
}
//cout << "detach test." << endl;
//this_thread::sleep_for(chrono::seconds(1));
}
}
void printhex(unsigned char *data, int len)
{
for (int i = ; i < len; i++)
{
printf("%2x ", data[i]);
}
printf("\n");
}
表现现象是Read函数不单单是阻塞,还会让Write函数也阻塞,这种情况是是没有留意到的地方,此处作一个记录.
异步IO版本,异步代码上方的注释为同步IO版本
// Win32SerialPortLib.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include "Win32SerialPortLib.h"
#include
HANDLE hcomm;
OVERLAPPED ovw;
OVERLAPPED ovr;
EXTERN_C WIN32SERIALPORTLIB_API HANDLE Open(char *com, int baud)
{
char szDCB[];
sprintf_s(szDCB, "baud=%d parity=%c data=%d stop=%d", baud, 'N', , );
//hcomm = CreateFileA(com,
// GENERIC_READ | GENERIC_WRITE,
// 0,
// NULL,
// OPEN_EXISTING,
// 0,
// 0);
hcomm = CreateFileA(com,
GENERIC_READ | GENERIC_WRITE,
,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
);
if (hcomm == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
// 设置缓冲大小
BOOL rt = SetupComm(hcomm, , );
if (!rt) return INVALID_HANDLE_VALUE;
// 设置超时
COMMTIMEOUTS commtimeouts;
commtimeouts.ReadIntervalTimeout = ;
commtimeouts.ReadTotalTimeoutConstant = ;
commtimeouts.ReadTotalTimeoutMultiplier = ;
commtimeouts.WriteTotalTimeoutConstant = ;
commtimeouts.WriteTotalTimeoutMultiplier = ;
rt = SetCommTimeouts(hcomm, &commtimeouts);
if (!rt) return INVALID_HANDLE_VALUE;
// 设置DCB
DCB dcb;
#ifdef UNICODE
DWORD num = MultiByteToWideChar(CP_ACP, , szDCB, -, NULL, );
wchar_t *pwStr = new wchar_t[num];
MultiByteToWideChar(CP_ACP, , szDCB, -, pwStr, num);
#else
DWORD num = strlen(szDCB) + ;
char *pwStr = new char[num];
strcpy(pwStr, szDCB);
#endif
rt = GetCommState(hcomm, &dcb);
if (!rt) return INVALID_HANDLE_VALUE;
rt = BuildCommDCB(pwStr, &dcb);
if (!rt) return INVALID_HANDLE_VALUE;
delete[] pwStr;
rt = SetCommState(hcomm, &dcb);
if (!rt) return INVALID_HANDLE_VALUE;
// 清空串口缓冲区
rt = PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_TXABORT);
if (!rt) return INVALID_HANDLE_VALUE;
return hcomm;
}
EXTERN_C WIN32SERIALPORTLIB_API int Read(unsigned char *data, DWORD len)
{
DWORD read_size = ;
if (hcomm == INVALID_HANDLE_VALUE) return ;
COMSTAT comstat;
DWORD error;
ClearCommError(hcomm, &error, &comstat);
// 串口有错误
if (error > )
{
PurgeComm(hcomm, PURGE_RXCLEAR | PURGE_RXABORT);
return read_size;
}
if (comstat.cbInQue > )
{
//BOOL rt = ReadFile(hcomm, data, comstat.cbInQue, &read_size, NULL);
//if (!rt) return 0;
BOOL rt = ReadFile(hcomm, data, comstat.cbInQue, &read_size, &ovr);
if (!rt)
{
rt = GetLastError();
if (rt == ERROR_IO_PENDING)
{
// 此时是否需要对IO状态作处理看需求,处理与否不会影响IO
//rt = WaitForSingleObject(hcomm, 50);
//switch (rt)
//{
//case WAIT_OBJECT_0:
// cout << "指定的对象处于有信号状态" << endl;
// if (GetOverlappedResult(hcomm, &ovr, &read_size, FALSE))
// cout << "read " << read_size << " bytes" << endl;
// break;
//case WAIT_TIMEOUT:
// cout << "等待超时" << endl;
// break;
//case WAIT_FAILED:
// cout << "出现错误,CODE [" << GetLastError() << "]" << endl;
// break;
//case WAIT_ABANDONED:
// cout << "当Handle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值" << endl;
// break;
//}
}
else
{
CancelIo(hcomm);
return ;
}
}
}
return read\_size;
}
EXTERN_C WIN32SERIALPORTLIB_API void Write(unsigned char *data, DWORD len)
{
DWORD write_size;
if (hcomm == INVALID_HANDLE_VALUE) return;
COMSTAT comstat;
DWORD error;
BOOL rt = ClearCommError(hcomm, &error, &comstat);
if (!rt) return;
// 串口有错误
if (error > )
{
PurgeComm(hcomm, PURGE_TXCLEAR | PURGE_TXABORT);
return;
}
WriteFile(hcomm, data, len, &write\_size, NULL);
rt = WriteFile(hcomm, data, len, &write\_size, &ovw);
if (!rt)
{
rt = GetLastError();
if (rt == ERROR\_IO\_PENDING)
{
// 此时是否需要对IO状态作处理看需求,处理与否不会影响IO
//rt = WaitForSingleObject(hcomm, 50);
//switch (rt)
//{
//case WAIT\_OBJECT\_0:
// cout << "指定的对象处于有信号状态" << endl;
// if (GetOverlappedResult(hcomm, &ovr, &write\_size, FALSE))
// cout << "write " << write\_size << " bytes" << endl;
// break;
//case WAIT\_TIMEOUT:
// cout << "等待超时" << endl;
// break;
//case WAIT\_FAILED:
// cout << "出现错误,CODE \[" << GetLastError() << "\]" << endl;
// break;
//case WAIT\_ABANDONED:
// cout << "当Handle为mutex时,如果拥有mutex的线程在结束时没有释放核心对象会引发此返回值" << endl;
// break;
//}
}
else
{
CancelIo(hcomm);
return;
}
}
}
EXTERN_C WIN32SERIALPORTLIB_API void Close()
{
if (hcomm != INVALID_HANDLE_VALUE)
{
CancelIo(hcomm);
CloseHandle(hcomm);
hcomm = INVALID_HANDLE_VALUE;
}
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章