#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <windowsx.h> // Makros
#include <shlwapi.h> // nützliche Funktionen
#include <commctrl.h>
#include <ddeml.h>
#define elemof(x) (sizeof(x)/sizeof((x)[0]))
#define T(x) TEXT(x)
#define nobreak
HINSTANCE ghInstance;
HWND ghMainWnd;
TCHAR StdMBoxTitle[64];
unsigned gComNum;
HANDLE hCom;
void _fastcall InitStruct(LPVOID p, UINT len) {
LPUINT p2=(LPUINT)p;
*p2=len; len/=sizeof(UINT); len--;
if (len) do *++p2=0; while (--len);
}
int vMBox(HWND Wnd, LPCTSTR Text, UINT Type, va_list va) {
TCHAR buf[256],buf2[256];
if (!((DWORD_PTR)Text>>16)) {
LoadString(ghInstance,(UINT)(DWORD_PTR)Text,buf2,elemof(buf2));
Text=buf2;
}
wvnsprintf(buf,elemof(buf),Text,va);
return MessageBox(Wnd,buf,StdMBoxTitle,Type);
}
int _cdecl MBox(HWND Wnd, LPCTSTR Text, UINT Type, ...) {
return vMBox(Wnd,Text,Type,(va_list)(&Type+1));
}
BOOL OpenCom(void) {
TCHAR ComName[12];
wsprintf(ComName,T("\\\\.\\COM%u"),gComNum);
hCom=CreateFile(ComName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0);
if (hCom==INVALID_HANDLE_VALUE) {hCom=0; return FALSE;}
DCB dcb;
InitStruct(&dcb,sizeof(dcb));
GetCommState(hCom,&dcb);
dcb.BaudRate=9600; // default setting for big Fakespace box
dcb.ByteSize=8;
dcb.StopBits=TWOSTOPBITS;
SetCommState(hCom,&dcb);
static const COMMTIMEOUTS to={MAXDWORD,0,0,0,0};
return SetCommTimeouts(hCom,(LPCOMMTIMEOUTS)&to);
}
typedef struct {
unsigned char N;
unsigned short C[5];
}conn_t;
conn_t conn;
unsigned timeval;
static void SendString(const char*s) {
DWORD bw;
WriteFile(hCom,s,lstrlenA(s),&bw,NULL);
}
static void InvalHands(void) {
InvalidateRect(GetDlgItem(ghMainWnd,11),NULL,FALSE);
}
static void CheckDataArrival(void) {
DWORD br;
static unsigned char buf[64],c;
static unsigned idx;
for(;;) {
if (!ReadFile(hCom,&c,1,&br,NULL)) return;
if (!br) break;
if (idx==0) {
if (c>=0x80 && c<=0x82) buf[idx++]=c; // valid STX, otherwise discard the byte
}else{
if (idx<elemof(buf)) buf[idx++]=c;
if (c==0x8F) { // valid ETX, show message
TCHAR s[100], *p=s;
p+=wsprintf(p,T("%02X "),buf[0]);
if (buf[0]==0x82) {
p+=wsprintf(p,T("\""));
for (unsigned k=1; k<idx-1; k++) {
p+=wsprintf(p,T("%c"),buf[k]);
}
p+=wsprintf(p,T("\" "));
}else{
if (IsDlgButtonChecked(ghMainWnd,16)==2)
CheckDlgButton(ghMainWnd,16,buf[0]-0x80); // T state detected
for (unsigned k=1; k<idx-1; k++) {
p+=wsprintf(p,T("%02X "),buf[k]);
}
unsigned n=(idx-2)>>1; // number of connections
timeval=0;
if (buf[0]==0x81) {
n--;
timeval=(buf[idx-2]<<7)|buf[idx-3];
SetTimer(ghMainWnd,3,1000,NULL); // display time for 1 second
}
conn.N=n;
BYTE all_bits=0;
for (unsigned i=0; i<n; i++) {
BYTE lobyte=buf[(i<<1)+1];
BYTE hibyte=buf[(i<<1)+2];
conn.C[i]=MAKEWORD(lobyte,hibyte);
all_bits|=lobyte|hibyte;
}
if (all_bits&0x20 && IsDlgButtonChecked(ghMainWnd,17)==2)
CheckDlgButton(ghMainWnd,17,1); // G1 state detected
InvalHands();
}
p+=wsprintf(p,T("%02X\r\n"),buf[idx-1]);
HWND w=GetDlgItem(ghMainWnd,12);
DWORD Start,End,Len;
Len=Edit_GetTextLength(w);
SendMessage(w,EM_GETSEL,(WPARAM)&Start,(LPARAM)&End);
Edit_SetSel(w,Len,Len);
Edit_ReplaceSel(w,s);
if (Len==Start && Start==End); // update cursor
else Edit_SetSel(w,Start,End); // not update cursor
idx=0;
}
}
}
}
#define MAXCOMSEARCH 32
static BOOL CALLBACK ComSelDlgProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
case WM_INITDIALOG: {
SetTimer(Wnd,1,100,NULL);
}return TRUE;
case WM_DEVICECHANGE: SetTimer(Wnd,1,1500,NULL);
case WM_TIMER: {
KillTimer(Wnd,wParam);
HWND hCombo=GetDlgItem(Wnd,13);
ComboBox_ResetContent(hCombo);
HMODULE hLib=LoadLibraryA("cfgmgr32.dll");
for (UINT i=1; i<=MAXCOMSEARCH; i++) {
DWORD cclen;
TCHAR ComName[8];
COMMCONFIG cc;
InitStruct(&cc,cclen=sizeof(cc));
wnsprintf(ComName,elemof(ComName),T("COM%u"),i);
if (GetDefaultCommConfig(ComName,&cc,&cclen)) {
int idx=ComboBox_AddString(hCombo,ComName);
ComboBox_SetItemData(hCombo,idx,i);
if (i==gComNum) ComboBox_SetCurSel(hCombo,idx);
}
}
if (hLib) FreeLibrary(hLib);
}break;
case WM_COMMAND: switch (LOWORD(wParam)) {
case IDOK: {
HWND hCombo=GetDlgItem(Wnd,13);
int i=ComboBox_GetCurSel(hCombo);
if (i<0) {
MBox(Wnd,(LPCTSTR)2,MB_OK|MB_ICONEXCLAMATION);
SetFocus(hCombo);
break;
}
gComNum=(unsigned)ComboBox_GetItemData(hCombo,i);
}nobreak;
case IDCANCEL: EndDialog(Wnd,wParam); break;
}break;
}
return FALSE;
}
static void DrawCircle(HDC dc, POINT p) {
Ellipse(dc,p.x-5,p.y-10,p.x+5,p.y+10);
}
static const COLORREF colors[]={ // colors for connections
0x30F090,
0xF03030,
0x307090,
0x903070,
0x709030};
struct {
HFONT hFont;
HBRUSH hbrCircles[elemof(colors)];
HPEN hThickPen;
}gGdiObj;
static void DrawConn(HDC dc, BYTE bits, unsigned i) {
static const POINT pos[]={ // fingertip positions
{97,140},
{77,175},
{57,180},
{37,160},
{15,75},
{15,180}};
HPEN open=SelectPen(dc,GetStockPen(NULL_PEN));
SelectBrush(dc,
i<elemof(colors) ? gGdiObj.hbrCircles[i] : GetStockBrush(LTGRAY_BRUSH));
for (unsigned k=0; k<elemof(pos); k++) {
if (bits&(1<<k)) DrawCircle(dc,pos[k]);
}
SelectPen(dc,open);
}
static void DrawHand(HDC dc,BOOL right) {
static const POINT BezierPoints[]={
{10,0},{5,30},{5,30},{5,70},
{5,110},{25,110},{25,70},
{25,0},{30,0},{30,160},
{30,185},{45,185},{45,160},
{45,60},{50,60},{50,180},
{50,205},{65,205},{65,180},
{65,60},{70,60},{70,175},
{70,200},{85,200},{85,175},
{85,60},{90,60},{90,140},
{90,160},{105,160},{105,140},
{105,130},{105,20},{100,0}
};
PolyBezier(dc,BezierPoints,elemof(BezierPoints));
BYTE mask=0;
for (unsigned i=0; i<conn.N; i++) {
BYTE bits=right?HIBYTE(conn.C[i]):LOBYTE(conn.C[i]);
DrawConn(dc,bits,i); // set circles
mask|=bits;
}
DrawConn(dc,~mask,(unsigned)-1); // remove circles, don't flicker
}
static void DrawHands(LPDRAWITEMSTRUCT dis) {
SetMapMode(dis->hDC,MM_ANISOTROPIC);
SetViewportExtEx(dis->hDC,(dis->rcItem.right-dis->rcItem.left)>>1,
dis->rcItem.top-dis->rcItem.bottom,NULL);
SetViewportOrgEx(dis->hDC,(dis->rcItem.right+dis->rcItem.left)>>1,
dis->rcItem.bottom,NULL);
SelectPen(dis->hDC,gGdiObj.hThickPen);
SetWindowExtEx(dis->hDC,110,200,NULL);
DrawHand(dis->hDC,TRUE); // right hand
SetWindowExtEx(dis->hDC,-110,200,NULL);
DrawHand(dis->hDC,FALSE); // left hand
RECT r;
SetRect(&r,-25,120,25,140);
TCHAR s[32];
SelectFont(dis->hDC,GetStockFont(ANSI_VAR_FONT));
SetTextAlign(dis->hDC,TA_BOTTOM|TA_CENTER);
ExtTextOut(dis->hDC,0,120,ETO_OPAQUE|ETO_CLIPPED,&r,s,
wsprintf(s,timeval?T("%u ms"):T(""),timeval),NULL);
ExtTextOut(dis->hDC,0,170,0,NULL,T("GND"),3,NULL);
}
static void EnableControls(void) {
for (HWND w=GetDlgItem(ghMainWnd,13); w; w=GetNextSibling(w))
EnableWindow(w,hCom!=0);
}
void MakeGdiObj(void) {
gGdiObj.hFont=CreateFont(12,0,0,0,0,0,0,0,0,0,0,0,0,T("Lucidia Console"));
for (int i=0; i<elemof(colors); i++) {
gGdiObj.hbrCircles[i]=CreateSolidBrush(colors[i]);
}
gGdiObj.hThickPen=CreatePen(PS_SOLID,2,0);
}
void LoadConfig(void) {
HKEY key;
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,T("Software\\h#s\\glovetest"),
0,NULL,REG_OPTION_NON_VOLATILE,KEY_QUERY_VALUE,NULL,&key,NULL)) return;
DWORD size=sizeof(gComNum);
RegQueryValueEx(key,T("Com"),NULL,NULL,(LPBYTE)&gComNum,&size);
RegCloseKey(key);
}
void SaveConfig(void) {
HKEY key;
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,T("Software\\h#s\\glovetest"),
0,NULL,REG_OPTION_NON_VOLATILE,KEY_SET_VALUE,NULL,&key,NULL)) return;
TCHAR s[64];
RegSetValue(key,NULL,REG_SZ,s,LoadString(ghInstance,1,s,elemof(s))*sizeof(TCHAR));
RegSetValueEx(key,T("Com"),0,REG_DWORD,(LPBYTE)&gComNum,sizeof(gComNum));
RegCloseKey(key);
}
static BOOL CALLBACK MainDlgProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
case WM_INITDIALOG: {
ghMainWnd=Wnd;
LoadConfig();
MakeGdiObj();
SetClassLong(Wnd,GCL_HICON,(LONG)(ULONG_PTR)
LoadImage(ghInstance,MAKEINTRESOURCE(100),IMAGE_ICON,32,32,LR_SHARED));
SetClassLong(Wnd,GCL_HICONSM,(LONG)(ULONG_PTR)
LoadImage(ghInstance,MAKEINTRESOURCE(100),IMAGE_ICON,16,16,LR_SHARED));
SendDlgItemMessage(Wnd,12,WM_SETFONT,(WPARAM)gGdiObj.hFont,FALSE);
SetTimer(Wnd,1,100,NULL);
}return TRUE;
case WM_TIMER: switch (wParam) {
case 1: { // initialization timer
KillTimer(Wnd,wParam);
HMENU SysMenu=GetSystemMenu(Wnd,FALSE);
TCHAR s[64];
LoadString(ghInstance,4,s,elemof(s)); // insert a menu item
InsertMenu(SysMenu,SC_CLOSE,0,0x40,s);
do{
if (gComNum && OpenCom()) { SendString("CP"); break; }
}while (DialogBox(0,MAKEINTRESOURCE(101),Wnd,ComSelDlgProc)==IDOK);
EnableControls();
CheckDlgButton(Wnd,16,2);
CheckDlgButton(Wnd,17,2);
if (hCom) SetTimer(Wnd,2,100,NULL);
}break;
case 2: { // cyclic timer that queries the serial port
// (not best - for maximum responsiveness use a thread or overlapped operation)
CheckDataArrival();
}break;
case 3: { // remove timestamp from hands display
KillTimer(Wnd,wParam);
timeval=0;
InvalHands();
}break;
}break;
case WM_DRAWITEM: DrawHands((LPDRAWITEMSTRUCT)lParam); break;
case WM_COMMAND: switch (LOWORD(wParam)) {
case 13: SendString("CL"); break;
case 14: SendString("CR"); break;
case 15: SendString("CP"); break;
case 16:
case 17: {
char s[3];
s[0]=LOWORD(wParam)==17 ? 'G' : 'T';
s[1]=IsDlgButtonChecked(Wnd,LOWORD(wParam))?'0':'1';
s[2]=0;
SendString(s);
CheckDlgButton(Wnd,LOWORD(wParam),s[1]-'0');
}break;
case 18: {
SetDlgItemText(Wnd,12,T(""));
}break;
}break;
case WM_SYSCOMMAND: switch (wParam&0xFFF0) {
case 0x40: {
if (DialogBox(0,MAKEINTRESOURCE(101),Wnd,ComSelDlgProc)==IDOK) {
CloseHandle(hCom); hCom=0;
OpenCom();
SendString("CP");
}
}break;
}break;
case WM_CLOSE: {
SaveConfig();
EndDialog(Wnd,2);
}break;
case WM_ENDSESSION: if (wParam) SaveConfig(); break;
}
return FALSE;
}
int _stdcall WinMainCRTStartup(void) {
ghInstance=GetModuleHandle(NULL);
InitCommonControls();
ExitProcess((UINT)DialogBox(0,MAKEINTRESOURCE(100),0,MainDlgProc));
}
Detected encoding: ANSI (CP1252) | 4
|
|