#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <windowsx.h> // Makros
#include <setupapi.h>
#include <devguid.h>
#include <commctrl.h>
//#include <ddeml.h>
#include <stdio.h>
//#include <stdlib.h>
#include <tchar.h>
#include <richedit.h>
#define elemof(x) (sizeof(x)/sizeof((x)[0]))
#define T(x) TEXT(x)
#define nobreak
#define WM_CONTINUEINIT (WM_USER+0x100)
HINSTANCE ghInstance;
HWND ghMainWnd;
HFONT gBigFont;
TCHAR StdMBoxTitle[64];
struct RECTS{short left,top,right,bottom;};
struct{
RECTS winpos;
char showCmd;
BYTE ComNum;
BYTE motornum;
BYTE demotime; // Stillstand in Sekunden
BYTE speed; // =4
BYTE accel; // =1
}config;
LPTSTR posinfo; // LocalAlloc-String, tab-separiert
/****************
* aus WUTILS.C *
****************/
//Win32-typische Strukturen mit DWORD-Ausrichtung initialisieren
void _fastcall InitStruct(LPVOID p, UINT len) {
LPUINT p2=(LPUINT)p; // sonst hat C++ Verdauungsstörungen
*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;
}
_vsntprintf(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));
}
/***********************
* Motor positionieren *
***********************/
HANDLE hCom;
static void OpenCom(void) {
TCHAR ComName[12];
_sntprintf(ComName,elemof(ComName),T("\\\\.\\COM%u"),config.ComNum);
hCom=CreateFile(ComName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0);
if (hCom==INVALID_HANDLE_VALUE) {hCom=0; return;}
DCB dcb;
InitStruct(&dcb,sizeof(dcb));
dcb.BaudRate=38400;
dcb.ByteSize=8;
dcb.fBinary=TRUE;
SetCommState(hCom,&dcb);
static const COMMTIMEOUTS to={0,0,100,0,0};
SetCommTimeouts(hCom,(LPCOMMTIMEOUTS)&to);
}
enum MOVEHOW {MOVEABS=1, MOVEREL=5, SYNC=2};
static bool Move(MOVEHOW how, int pos=0, int speed=0, int accel=0) {
if (!hCom) return false;
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
#pragma pack(1)
struct{
BYTE cmd;
BYTE len;
BYTE how;
char accel;
short speed;
long pos;
}data={
0x80+config.motornum,
0x08,
how,
accel,
speed,
pos
};
#pragma pack()
DWORD dwBytes;
if (WriteFile(hCom,&data,sizeof(data),&dwBytes,NULL)
&& dwBytes==sizeof(data)) {
return true;
}
return false;
}
/*
static bool SetPos(int pos=0) {
#pragma pack(1)
struct{
BYTE cmd;
BYTE len;
BYTE ofs;
long pos;
}data={
0x98+config.motornum,
0x05,
0x04,
pos
};
#pragma pack()
DWORD dwBytes;
if (WriteFile(hCom,&data,sizeof(data),&dwBytes,NULL)
&& dwBytes==sizeof(data)) {
return true;
}
return false;
}
*/
static void InitCom(void) {
OpenCom();
if (hCom) {
}else{
MBox(ghMainWnd,(LPCTSTR)8,MB_OK|MB_ICONEXCLAMATION,config.ComNum);
SendMessage(ghMainWnd,WM_COMMAND,0x40,0); // sofort zur Konfiguration
}
}
#define LNAN 0x80000000;
struct MOTORINFO {
BYTE phase;
char accel;
short speed;
long pos;
bool Query();
};
// Abfrage der Position in Mikroschritt, 256 µSchritt = Halbschritt
bool MOTORINFO::Query() {
if (hCom) {
char c='A'+config.motornum;
DWORD dwBytes;
WriteFile(hCom,&c,1,&dwBytes,NULL);
if (ReadFile(hCom,this,sizeof(*this),&dwBytes,NULL)
&& dwBytes==sizeof(*this)) {
return true;
}
}
return false;
}
/*************
* Dialog(e) *
*************/
static INT_PTR CALLBACK HardwareDlgProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
case WM_INITDIALOG: {
SetTimer(Wnd,1,1,NULL);
SetDlgItemInt(Wnd,16,config.motornum,FALSE);
SetDlgItemInt(Wnd,17,config.demotime,FALSE);
SetDlgItemText(Wnd,22,posinfo);
}return TRUE;
case WM_DEVICECHANGE: SetTimer(Wnd,1,1500,NULL);
case WM_TIMER: {
KillTimer(Wnd,wParam);
// serielle Schnittstellen (neu) listen (bei jedem WM_DEVICECHANGE bspw. für USB)
HWND hCombo=GetDlgItem(Wnd,13);
ComboBox_ResetContent(hCombo);
HANDLE devs=SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS,NULL,0,DIGCF_PRESENT);
if (devs!=INVALID_HANDLE_VALUE) {
SP_DEVINFO_DATA devInfo;
devInfo.cbSize=sizeof devInfo;
for (DWORD i=0; SetupDiEnumDeviceInfo(devs,i,&devInfo); i++) {
HKEY hKey;
TCHAR s[16];
DWORD slen=sizeof s;
DWORD num;
if ((hKey=SetupDiOpenDevRegKey(devs,&devInfo,DICS_FLAG_GLOBAL,0,DIREG_DEV,KEY_READ))
==INVALID_HANDLE_VALUE) continue;
if (!RegQueryValueEx(hKey,T("PortName"),NULL,NULL,(LPBYTE)s,&slen)
&& _stscanf(s,T("COM%u"),&num)==1) { // LPTx ausfiltern
int idx=ComboBox_AddString(hCombo,s);
ComboBox_SetItemData(hCombo,idx,num);
if (num==config.ComNum) ComboBox_SetCurSel(hCombo,idx);
}
RegCloseKey(hKey);
}
SetupDiDestroyDeviceInfoList(devs);
}
}break;
case WM_COMMAND: switch (LOWORD(wParam)) {
case 10: switch (HIWORD(wParam)) {
case EN_CHANGE: SetTimer(Wnd,10,200,NULL); break;
}break;
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;
}
config.ComNum=(BYTE)ComboBox_GetItemData(hCombo,i);
config.motornum=(BYTE)GetDlgItemInt(Wnd,16,NULL,FALSE);
config.demotime=(BYTE)GetDlgItemInt(Wnd,17,NULL,FALSE);
LocalFree(posinfo);
HWND hEdit=GetDlgItem(Wnd,22);
int len=GetWindowTextLength(hEdit)+1;
posinfo=(LPTSTR)LocalAlloc(LMEM_FIXED,len*sizeof(TCHAR));
GetWindowText(hEdit,posinfo,len);
}nobreak;
case IDCANCEL: EndDialog(Wnd,wParam); break;
}break;
}
return FALSE;
}
/****************
* Hauptfenster *
****************/
static void LoadConfig(void) {
HKEY key;
if (RegOpenKeyEx(HKEY_CURRENT_USER,T("Software\\h#s\\Teller"),
0,KEY_QUERY_VALUE,&key)) return;
DWORD size=sizeof(config);
if (!RegQueryValueEx(key,T("Config"),NULL,NULL,(LPBYTE)&config,&size)) {
WINDOWPLACEMENT wp;
InitStruct(&wp,sizeof(wp));
GetWindowPlacement(ghMainWnd,&wp);
wp.rcNormalPosition.left=config.winpos.left;
wp.rcNormalPosition.top=config.winpos.top;
wp.rcNormalPosition.right=config.winpos.right;
wp.rcNormalPosition.bottom=config.winpos.bottom;
wp.showCmd=config.showCmd;
SetWindowPlacement(ghMainWnd,&wp);
}
size=0;
RegQueryValueEx(key,T("PosInfo"),NULL,NULL,NULL,&size);
posinfo=(LPTSTR)LocalAlloc(LMEM_FIXED,size);
if (size) {
RegQueryValueEx(key,T("PosInfo"),NULL,NULL,(LPBYTE)posinfo,&size);
}
RegCloseKey(key);
}
static void FillListbox() {
HWND lb=GetDlgItem(ghMainWnd,17);
ListBox_ResetContent(lb);
LPTSTR p=posinfo;
while (p && *p) {
LPTSTR q=_tcschr(p,'\n');
LPTSTR n;
if (!q) {
q=p+_tcslen(p);
n=q;
}else n=q+1;
if (*--q!='\r') q++;
if (q>p+1) { // keine Leerzeilen
TCHAR save=*q;
*q=0;
ListBox_AddString(lb,p);
*q=save;
}
p=n;
}
}
static void SaveConfig(void) {
HKEY key;
if (RegCreateKeyEx(HKEY_CURRENT_USER,T("Software\\h#s\\Teller"),
0,NULL,REG_OPTION_NON_VOLATILE,KEY_SET_VALUE,NULL,&key,NULL)) return;
RegSetValue(key,NULL,REG_SZ,StdMBoxTitle,(_tcslen(StdMBoxTitle)+1)*sizeof(TCHAR));
WINDOWPLACEMENT wp;
InitStruct(&wp,sizeof(wp));
GetWindowPlacement(ghMainWnd,&wp);
config.winpos.left=(short)wp.rcNormalPosition.left;
config.winpos.top=(short)wp.rcNormalPosition.top;
config.winpos.right=(short)wp.rcNormalPosition.right;
config.winpos.bottom=(short)wp.rcNormalPosition.bottom;
config.showCmd=wp.showCmd;
RegSetValueEx(key,T("Config"),0,REG_BINARY,(LPBYTE)&config,sizeof(config));
if (posinfo) {
RegSetValueEx(key,T("PosInfo"),0,REG_SZ,(LPBYTE)posinfo,(_tcslen(posinfo)+1)*sizeof(TCHAR));
}
RegCloseKey(key);
}
static int Countdown;
static void InitCountdown() {
Countdown=config.demotime+1;
}
static SIZE prevsize;
#define PERIOD (400<<8)
static void ChangePos(UINT id, int x, int y, int w, int h) {
HWND wnd=GetDlgItem(ghMainWnd,id);
RECT r;
GetWindowRect(wnd,&r);
r.right-=r.left;
r.bottom-=r.top;
ScreenToClient(ghMainWnd,(LPPOINT)&r);
MoveWindow(wnd,r.left+x,r.top+y,r.right+w,r.bottom+h,TRUE);
}
BOOL CALLBACK MainDlgProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
case WM_INITDIALOG: {
ghMainWnd=Wnd;
RECT r;
GetClientRect(Wnd,&r);
prevsize.cx=r.right;
prevsize.cy=r.bottom;
gBigFont=CreateFont(48,0,0,0,0,0,0,0,0,0,0,0,0,T("Arial"));
HWND riched=GetDlgItem(Wnd,16);
SendMessage(riched,WM_SETFONT,(WPARAM)gBigFont,FALSE);
PARAFORMAT2 pf;
pf.cbSize=sizeof pf;
pf.dwMask=PFM_ALIGNMENT;
pf.wAlignment=PFA_CENTER;
SendMessage(riched,EM_SETPARAFORMAT,0,(LPARAM)&pf);
SendMessage(riched,EM_SETBKGNDCOLOR,0,RGB(192,192,192));
SETTEXTEX st={ST_DEFAULT/*|ST_UNICODE*/,1200};
SendMessage(riched,EM_SETTEXTEX,(WPARAM)&st,(LPARAM)L"{\\rtf RE50W by Jim Dunne Copyright (C) 2005\\par http://www.topjimmy.net/tjs \\par {\\field{\\*\\fldinst{HYPERLINK mailto:jim@dunnes.net }}{\\fldrslt{\\cf1\\ul jim@dunnes.net}}}}");
LoadConfig();
FillListbox();
InitCountdown();
PostMessage(Wnd,WM_CONTINUEINIT,0,0);
}return TRUE;
case WM_CONTINUEINIT: {
if (config.ComNum) InitCom();
else SendMessage(Wnd,WM_COMMAND,0x40,0); // beim ersten Start sofort zur Konfiguration
SetTimer(Wnd,100,100,NULL);
}break;
case WM_TIMER: { // Position abfragen; Demo-Modus ablaufen lassen
MOTORINFO info;
if (info.Query()) {
long p=info.pos;
/*
if ((unsigned)p>=PERIOD) {
if (p<0) p+=PERIOD;
else p-=PERIOD; // in Bereich 0..<400 Schritt bringen
SetPos(p);
}
*/
SetDlgItemInt(Wnd,19,p>>8,TRUE);
if (!(info.phase&0x0F) && IsDlgButtonChecked(Wnd,18) && !--Countdown) {
HWND lb=GetDlgItem(Wnd,17);
int n=ListBox_GetCount(lb);
int i=ListBox_GetCurSel(lb);
i++; if (i>=n) i=0;
ListBox_SetCurSel(lb,i);
SendMessage(Wnd,WM_COMMAND,MAKELONG(17,LBN_SELCHANGE),(LPARAM)lb);
InitCountdown();
}
}
}break;
case WM_SIZE: {
if (wParam==SIZE_RESTORED && prevsize.cx) {
SIZE newsize={LOWORD(lParam),HIWORD(lParam)};
int dx=newsize.cx-prevsize.cx;
int dy=newsize.cy-prevsize.cy;
ChangePos(16,0,0,dx,0);
ChangePos(17,0,0,dx,dy);
ChangePos(18,0,dy,dx,0);
ChangePos(19,dx,dy,0,0);
prevsize=newsize;
}
}break;
case WM_COMMAND:
switch (wParam) {
case 2: EndDialog(Wnd,wParam); break;
case MAKELONG(17,LBN_SELCHANGE): {
int i=ListBox_GetCurSel((HWND)lParam);
TCHAR s[256];
ListBox_GetText((HWND)lParam,i,s); // Pufferüberlauf droht!!
LPTSTR tab=_tcschr(s,'\t');
if (tab) {
SetDlgItemText(Wnd,16,tab+1); // Großen Text mitführen
}
long pos=_ttoi(s)<<8;
Move(MOVEABS,pos,config.speed,config.accel);
}break;
case 18: {
InitCountdown();
}break;
case 0x40: if (DialogBox(ghInstance,MAKEINTRESOURCE(100),Wnd,HardwareDlgProc)==IDOK) {
if (hCom) CloseHandle(hCom);
InitCom();
FillListbox();
SaveConfig();
}break;
}break;
case WM_DESTROY: {
SaveConfig();
if (hCom) CloseHandle(hCom);
if (gBigFont) DeleteFont(gBigFont);
}break;
case WM_ENDSESSION: if (wParam) SaveConfig(); break;
}
return FALSE;
}
/******************************
* Hauptprogramm (lächerlich) *
******************************/
int _stdcall WinMainCRTStartup(void) {
WNDCLASS wc={
CS_DBLCLKS,
DefDlgProc,
0,
DLGWINDOWEXTRA,
ghInstance=GetModuleHandle(NULL),
LoadIcon(ghInstance,MAKEINTRESOURCE(100)),
LoadCursor(0,IDC_ARROW),
(HBRUSH)(COLOR_BACKGROUND+1),
NULL,
T("Teller")
};
RegisterClass(&wc);
// static const INITCOMMONCONTROLSEX icc={sizeof(icc),ICC_WIN95_CLASSES|ICC_USEREX_CLASSES};
// InitCommonControlsEx((INITCOMMONCONTROLSEX*)&icc);
InitCommonControls(); // wichtig für Teletubbieoptik!
// LoadLibrary(T("riched20.dll"));
LoadLibrary(T("msftedit.dll"));
LoadString(ghInstance,1,StdMBoxTitle,elemof(StdMBoxTitle));
ExitProcess(DialogBox(0,MAKEINTRESOURCE(101),0,MainDlgProc));
}
Detected encoding: ANSI (CP1252) | 4
|
|