📄 dt3.cpp
字号:
// DT3.cpp : Defines the entry point for the application.
// This program is a "minimum feature" USB Dumb Terminal program
// It's goal is to show how a simple serial device can be simply connected to USB using
// a USB I/O device. This example uses the EZ-USB microcontroller and the firmware to
// implement the USB-to-serial-to-USB conversion is also available as an example program.
//
// See the accompanying documentation for a description of this example program
//
// Please send any corrections or enhancements to john@USB-By-Example.com
#include "stdafx.h"
#include "resource.h"
extern "C" {
// Declare the C libraries used
#include "setupapi.h"
#include "hidsdi.h"
#include "process.h"
}
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
HWND MainWindow; // Handle for main window
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];
char Buffer[2000]; // A screen full of characters
int BufferIndex; // A pointer into Buffer
const char *SignOn = "\n Select Connect from the File menu to search for 'Serial1' USB I/O device -";
const char *Found = "-> found\n";
const char *Special = " ** F1 Pressed ** ";
HANDLE ReadHandle, WriteHandle;
bool FullDuplex;
// Forward declarations of functions included in this program
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
BOOL OpenUSBdevice(char*);
DWORD WINAPI ListenToUSB(LPVOID);
DWORD DisplayError(const char*);
// Entry point for this program
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
// Declare local variables
MSG msg;
HACCEL hAccelTable;
// Initialize global variables
FullDuplex = true; ReadHandle = 0; WriteHandle = 0;
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_DT3, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Initialize application
if (!InitInstance (hInstance, nCmdShow)) { return FALSE; }
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_DT3);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
// Register the window class. (required)
ATOM MyRegisterClass(HINSTANCE hInstance) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_DT3);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_DT3;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
// Initialize the program and create main window
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd) { return FALSE; }
MainWindow = hWnd;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
// Processe messages for the main window.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
int ID, Event, Success, i;
PAINTSTRUCT ps;
HDC hdc;
RECT rt;
HANDLE ThreadHandle;
HMENU hMainMenu, hSubMenu;
char WriteBuffer[2];
DWORD BytesWritten, ThreadID;
switch (message) {
case WM_COMMAND:
ID = LOWORD(wParam); Event = HIWORD(wParam);
// Parse the menu selections:
switch (ID) {
case IDM_ABOUT: DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); return 0;
case IDM_EXIT: DestroyWindow(hWnd); return 0;
case IDM_FULLDUPLEX:
// Toggle the Full/Half Duplex flag
hMainMenu = GetMenu(hWnd); hSubMenu = GetSubMenu(hMainMenu, 0);
if (FullDuplex = !FullDuplex) { CheckMenuItem(hSubMenu, IDM_FULLDUPLEX, MF_BYCOMMAND | MF_CHECKED); }
else { CheckMenuItem(hSubMenu, IDM_FULLDUPLEX, MF_BYCOMMAND | MF_UNCHECKED);}
return 0;
case IDM_CONNECT:
// Look for the Serial1 USB device
if (!OpenUSBdevice("Serial1")) { DisplayError("Could not find 'Serial1' device"); }
else {
for (i = 0; i<(int)strlen(Found); i++) { Buffer[BufferIndex++] = Found[i]; }
InvalidateRect(MainWindow, NULL, 1);
// Serial USB device is open, create a thread to listen for characters
ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ListenToUSB, NULL, 0, &ThreadID);
if ((int)ThreadHandle == 0) { DisplayError("Could not start USB Listener Thread"); }
// Send an initial character to let the USB I/O device know we are ready
WriteBuffer[0] = 0; WriteBuffer[1] = 0;
Success = WriteFile(WriteHandle, WriteBuffer, 2, &BytesWritten, NULL);
if (Success == 0) { DisplayError("Could not write to the 'Serial1' device"); }
}
return 0;
}
break; // and send unprocessed menu message to Windows
case WM_PAINT:
// This is a minimal repaint.
// A "real" terminal program would process characters such as BS, TAB, CR, LF
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rt);
DrawText(hdc, Buffer, BufferIndex, &rt, 0);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY: PostQuitMessage(0); return 0;
case WM_CHAR:
// Send the character to the USB I/O device
WriteBuffer[0] = 0; // Report ID
WriteBuffer[1] = (char)wParam;
Success = WriteFile(WriteHandle, WriteBuffer, 2, &BytesWritten, NULL);
// Create a local echo if required
if (!FullDuplex) { Buffer[BufferIndex++] = (char)wParam; InvalidateRect(hWnd, NULL, 1); }
return 0;
case WM_KEYDOWN:
// Note that WM_CHAR does not process the Function keys
WriteBuffer[0] = 0;
if ((char)wParam == 112) { // F1 Function Key, send a string
for (i=0; i<(int)strlen(Special); i++) {
WriteBuffer[1] = Special[i];
Success = WriteFile(WriteHandle, WriteBuffer, 2, &BytesWritten, NULL);
}
}
if ((char)wParam == 113) { // F2 Function key, request a string
WriteBuffer[1] = (char)wParam;
Success = WriteFile(WriteHandle, WriteBuffer, 2, &BytesWritten, NULL);
}
return 0;
case WM_CREATE:
// Say Hello to the User
for (BufferIndex = 0; BufferIndex<(int)strlen(SignOn); BufferIndex++) { Buffer[BufferIndex] = SignOn[BufferIndex]; }
InvalidateRect(hWnd, NULL, 1);
return 0;
}
// Pass unprocessed messages back to Windows
return DefWindowProc(hWnd, message, wParam, lParam);
}
// Mesage handler for About box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
int ID = LOWORD(wParam);
switch (message) {
case WM_INITDIALOG: return TRUE;
case WM_COMMAND: if (ID == IDOK || ID == IDCANCEL) { EndDialog(hDlg, ID); return TRUE; }
break;
}
return FALSE;
}
// Support routines
BOOL OpenUSBdevice(char DeviceName[]) {
// Search through the attached HID devices for "DeviceName"
// Declare the local data structures used
struct _GUID HidGuid;
SP_INTERFACE_DEVICE_DATA DeviceInterfaceData;
struct {DWORD cbSize; char DevicePath[256];} FunctionClassDeviceData;
int Success, HidDevice, i;
HANDLE PnPHandle, HidHandle;
unsigned long BytesReturned;
char buffer[256];
BOOL Openned;
// First, get my class identifier
HidD_GetHidGuid(&HidGuid);
// Get a handle for the Plug and Play node and request currently active HID devices
PnPHandle = SetupDiGetClassDevs(&HidGuid,0,0,0x12);
if (int(PnPHandle) == -1) { DisplayError("Could not attach to PnP node"); return FALSE; }
Openned = false;
// Lets look for a maximum of 20 HID devices
for (HidDevice = 0; (HidDevice < 20) && !Openned; HidDevice++) {
// Give the user some feedback
Buffer[BufferIndex++] = 45; // "-"
InvalidateRect(MainWindow, NULL, 1);
// Initialize our Data
DeviceInterfaceData.cbSize = 28; // Length of data structure in bytes
// Is there a HID device at this table entry
Success = SetupDiEnumDeviceInterfaces(PnPHandle, 0, &HidGuid, HidDevice, &DeviceInterfaceData);
if (Success == 1) {
// There is a device here, get it's name
FunctionClassDeviceData.cbSize = 5;
Success = SetupDiGetDeviceInterfaceDetail(PnPHandle, &DeviceInterfaceData,
PSP_INTERFACE_DEVICE_DETAIL_DATA(&FunctionClassDeviceData), 256, &BytesReturned, 0);
if (Success == 0) { DisplayError("Could not find the system name for this HID device"); return FALSE; }
// Can now open this HID device
HidHandle = CreateFile(FunctionClassDeviceData.DevicePath, 0xC0000000, 3, NULL, 3, 0, NULL);
if ((int)HidHandle == -1) { DisplayError("Could not open HID device"); return FALSE; }
// Is it OUR HID device?
if (HidD_GetProductString(HidHandle, buffer, sizeof(buffer))) {
// Compare incoming string with UNICODE string
Openned = true; i = 0;
while (DeviceName[i] != 0) { if (buffer[2*i] != DeviceName[i]) {Openned = false;} i++;}
if (Openned) {
// We have found our device. Open two handles to it (one for each thread)
ReadHandle = CreateFile(FunctionClassDeviceData.DevicePath, 0xC0000000, 3, NULL, 3, 0, NULL);
WriteHandle = CreateFile(FunctionClassDeviceData.DevicePath, 0xC0000000, 3, NULL, 3, 0, NULL);
}
}
CloseHandle(HidHandle);
} // if (SetupDiEnumDeviceInterfaces . .
} // for (HidDevice = 0; (HidDevice < 20) && !Openned; HidDevice++)
CloseHandle(PnPHandle);
return Openned;
}
// Declare the thread that will wait for characters from the USB device
DWORD WINAPI ListenToUSB(LPVOID Param) {
// Collect characters from the USB device and send them to the display
char ReadBuffer[2];
int Success;
unsigned long BytesReturned;
while (1) {
Success = ReadFile(ReadHandle, ReadBuffer, 2, &BytesReturned, NULL);
if (ReadBuffer[1] != 0) { Buffer[BufferIndex++] = ReadBuffer[1]; InvalidateRect(MainWindow, NULL, 1); }
};
return 0;
}
// Display various error messages
DWORD DisplayError (const char ErrorText[]) {
int i = MessageBox(MainWindow, ErrorText, "Error", MB_ICONSTOP);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -