#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <setupapi.h>
#include <devguid.h>
#include "sm.h"
#include "TabDlg.h"
#include <stdio.h>
#include <tchar.h>
#include <malloc.h>
#include <math.h>
#define elemof(x) (sizeof(x)/sizeof((x)[0]))
#define T(x) TEXT(x)
#define nobreak
#define offsetof(T,x) (int)&(((T*)NULL)->x)
EXTERN_C int _fltused;
int _fltused;
__forceinline __int64 rndint64(double f) {
__int64 i;
_asm fld f
_asm fistp i
return i;
}
HINSTANCE ghInstance;
TCHAR StdMBoxTitle[64];
char sDecimal[4]; // je nach Windows-Einstellung
char sNegativeSign[4];
struct config_t{
POINTS winpos; // Linke obere Ecke beim Speichern (nur für Hauptfenster)
BYTE ViewMode; // 0..2 (mit Einheit, Ganzschritte, native), Bit 2 = hex
BYTE CurTab; // Aktueller "Reiter"
BYTE ComNum; // 0 = COM1 usw. (ungenutzt bei Sekundärfenstern!!)
BYTE MotorNum; // 0..5 (Hauptfenster)
move_t soll;
void LoadConfig(HWND);
void SaveConfig(HWND);
};
struct CDLG { // Dialog-Daten
config_t c; // Was in die Registry geht
struct :DLGHDR{ // Verwaltung der Tabs
DLGPAGE room[2];
}p;
union{
char nk[4]; // Ausgerechnete Nachkommastellen für den aktuellen Motor
DWORD nka;
};
ram_t ram;
BYTE RamWriteOffset;
void IncRamWriteOffsetTo(BYTE newval);
void Page0Change(BYTE m=0xFF);
void Page1Change(BYTE m=0xFF);
void SetValue(HWND,long v,int e);
void SetValue(HWND w, UINT id, long v, int e) {SetValue(GetDlgItem(w,id),v,e);}
void SetJerk (HWND w, UINT id, long v) {SetValue(w,id,v,3);}
void SetAccel(HWND w, UINT id, long v) {SetValue(w,id,v,2);}
void SetSpeed(HWND w, UINT id, long v) {SetValue(w,id,v,1);}
void SetPos (HWND w, UINT id, long v) {SetValue(w,id,v,0);}
void SetUnit (HWND,int e);
void SetUnit (HWND w, UINT id, int e) {SetUnit(GetDlgItem(w,id),e);}
bool GetValue(HWND w, long*p, int e=0);
bool GetJerk (HWND w,BYTE &p) {return GetValue(w,(long*)&p,3);}
bool GetAccel(HWND w,char &p) {return GetValue(w,(long*)&p,2);}
bool GetSpeed(HWND w,short&p) {return GetValue(w,(long*)&p,1);}
bool GetPos (HWND w,long &p) {return GetValue(w,&p);}
void OnMotorChange();
void PeriodicAction();
void ViewModeChanged() {Page0Change(4);Page1Change(4);}
bool Fahrt(bool);
};
CDLG main;
// Für ComboBoxEx (serielle Schnittstellen)
SP_CLASSIMAGELIST_DATA SetupDiClassImageList;
#define ghMainWnd main.p.hwndDlg
//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));
}
void SetCheckboxGroup(HWND Wnd, UINT u, UINT o, UINT v) {
for(;u<=o; u++,v>>=1) CheckDlgButton(Wnd,u,v&1);
}
// Punkt->Komma
void pk(char*s) {
char*p=strpbrk(s,sDecimal);
if (p) *p=sDecimal[0];
p=strpbrk(s,sNegativeSign);
if (p) *p=sNegativeSign[0];
}
char Inf[3][8]; // Infinite-Strings
const char* infstr(int v) {
unsigned u=v-0x7FFFFFFE;
if (u>=3) return NULL;
return Inf[u];
}
EXTERN_C _declspec(naked) _cdecl _alloca_probe() {_asm{
pop ecx
sub esp,eax
jmp ecx
}}
int fromUTF8(char*s, int sl) {
WCHAR *buf=(WCHAR*)_alloca(sl<<1);
int l=MultiByteToWideChar(CP_UTF8,0,s,-1,buf,sl);
#ifdef UNICODE
memcpy(s,buf,l<<1);
#else
WideCharToMultiByte(CP_ACP,0,buf,l,s,sl,NULL,NULL);
#endif
return sl;
}
int toUTF8(char*s, int sl) {
#ifdef UNICODE
int l=wcslen((PWSTR)s)+1; // String-Länge in Zeichen, inklusive \0
WCHAR *buf=(WCHAR*)_alloca(l<<1);
memcpy(buf,s,l<<1);
#else
WCHAR *buf=(WCHAR*)_alloca(sl<<1);
int l=MultiByteToWideChar(CP_ACP,0,s,-1,buf,sl);
#endif
return WideCharToMultiByte(CP_UTF8,0,buf,l,s,sl,NULL,NULL);
}
static HANDLE ComOpen(int n) {
TCHAR ComName[12];
_sntprintf(ComName,elemof(ComName),T("\\\\.\\COM%u"),n+1);
HANDLE h=CreateFile(ComName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
if ((int)h<0) h=0;
if (h) {
DCB dcb;
InitStruct(&dcb,sizeof dcb);
dcb.BaudRate=38400,
dcb.fBinary=TRUE;
dcb.ByteSize=8; // Alles andere bleibt 0 (NOPARITY,ONESTOPBIT,NOHANDSHAKE)
SetCommState(h,&dcb);
static const COMMTIMEOUTS to={0,0,100,0,0};
SetCommTimeouts(h,(LPCOMMTIMEOUTS)&to);
}
return h;
}
static int trafo(int v, int u, int o, int U, int O) {
return MulDiv(v-u,O-U,o-u)+U;
}
static double trafo(int v, int u, int o, double U, double O) {
return (v-u)*(O-U)/(o-u)+U;
}
/***************************
* Noch mehr globale Daten *
***************************/
HANDLE hCom; // Aktive serielle Schnittstelle
OVERLAPPED o;
union{
struct{
EeCtrl h; // 8 Byte Header
EeMotor m[6]; // 48 Byte Motordaten (zumeist 6mal)
};
BYTE data[512]; // Speicherabzug des gesamten EEPROMs
}Eeprom;
int Query(const void *q, int ql, void *a, int al) {
DWORD dw;
WriteFile(hCom,q,ql,&dw,&o);
GetOverlappedResult(hCom,&o,&dw,TRUE);
ReadFile(hCom,a,al,&dw,&o);
GetOverlappedResult(hCom,&o,&dw,TRUE);
return dw;
}
void QueryBasicParams() {
char s[100];
memset(s,0,sizeof(s));
s[99]='?';
s[Query(s,100,s,99)]=0;
fromUTF8(s,100);
SetDlgItemText(ghMainWnd,18,(PTSTR)s);
// EEPROM (komplett) auslesen
read_t q={0xA0,4,0,0x81,0x80};
for(;q.a<512;q.a+=q.l) {
Query(&q,sizeof q,Eeprom.data+q.a,q.l);
}
SendDlgItemMessage(ghMainWnd,22,UDM_SETRANGE32,0,(Eeprom.h.nm&0x0F)-1);
}
void SerComboUpdate(HWND hCombo) {
COMBOBOXEXITEM cbei;
cbei.mask=CBEIF_TEXT|CBEIF_IMAGE|CBEIF_SELECTEDIMAGE|CBEIF_OVERLAY|CBEIF_LPARAM;
cbei.iItem=0;
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[64];
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
cbei.lParam=--num;
SetupDiGetDeviceRegistryProperty(devs,&devInfo,SPDRP_ENUMERATOR_NAME,NULL,(PBYTE)s,sizeof s,NULL);
SetupDiGetClassImageIndex(&SetupDiClassImageList,(LPGUID)
_tcsicmp(s,T("usb"))?&GUID_DEVCLASS_PORTS:&GUID_DEVCLASS_USB,&cbei.iImage);
cbei.iSelectedImage=cbei.iImage;
SetupDiGetDeviceRegistryProperty(devs,&devInfo,SPDRP_FRIENDLYNAME,NULL,(PBYTE)s,sizeof s,NULL);
cbei.pszText=s;
cbei.iOverlay=0;
if (num!=main.c.ComNum) {
HANDLE h=ComOpen(num);
if (h) CloseHandle(h); else cbei.iOverlay=2; // rotes X: Port besetzt
}
SendMessage(hCombo,CBEM_INSERTITEM,0,(LPARAM)&cbei);
if (num==main.c.ComNum) ComboBox_SetCurSel(hCombo,cbei.iItem);
cbei.iItem++;
}
RegCloseKey(hKey);
}
SetupDiDestroyDeviceInfoList(devs);
}
}
/********************
* Registry-Zugriff *
********************/
void config_t::LoadConfig(HWND Wnd) {
HKEY key;
if (RegOpenKeyEx(HKEY_CURRENT_USER,T("Software\\h#s\\smc2"),
0,KEY_QUERY_VALUE,&key)) return;
DWORD size=sizeof(*this);
if (!RegQueryValueEx(key,T("Config"),NULL,NULL,(LPBYTE)this,&size)) {
WINDOWPLACEMENT wp;
InitStruct(&wp,sizeof(wp));
GetWindowPlacement(Wnd,&wp);
OffsetRect(&wp.rcNormalPosition,
winpos.x-wp.rcNormalPosition.left,
winpos.y-wp.rcNormalPosition.top);
SetWindowPlacement(Wnd,&wp);
}
RegCloseKey(key);
}
void config_t::SaveConfig(HWND Wnd) {
HKEY key;
if (RegCreateKeyEx(HKEY_CURRENT_USER,T("Software\\h#s\\smc2"),
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(Wnd,&wp);
winpos.x=(short)wp.rcNormalPosition.left;
winpos.y=(short)wp.rcNormalPosition.top;
RegSetValueEx(key,T("Config"),0,REG_BINARY,(LPBYTE)this,sizeof(*this));
RegCloseKey(key);
}
/**************************
* Dialog-Objekt-Routinen *
**************************/
void GetWindowTextU(HWND w, char*s, int slen) {
GetWindowText(w,(PTSTR)s,slen/sizeof(TCHAR));
toUTF8(s,slen);
}
void SetWindowTextU(HWND w, char*s, int buflen) {
fromUTF8(s,buflen);
SetWindowText(w,(PTSTR)s);
}
void CDLG::SetValue(HWND Wnd, long v, int e) {
char s[32];
double f=Eeprom.m[c.MotorNum].PerUnit;
long k=Eeprom.h.fv;
switch (e) {
case 0: k=1; break;
case 1: {
switch (v) {
case -32768: v= LNAN; break;
case -32767: v=-LINF; break;
case +32767: v= LINF; break;
}
}break;
case 2: {
k=k*k>>-Eeprom.h.ea;
switch (v) {
case -128: v= LNAN; break;
case -127: v=-LINF; break;
case +127: v= LINF; break;
}
}break;
}
f/=k;
const char *p=infstr(v);
if ((c.ViewMode&3)==1 && !e) v>>=Eeprom.h.xs; // Nur die Positionen auf Ganzschritte reduzieren
switch (c.ViewMode&7) {
case 1: if (p) goto infinite;
nobreak;
case 2: _snprintf(s,sizeof s,"%d",v); break;
case 5: if (p) goto infinite;
if (v<0) _snprintf(s,elemof(s),"%c%X",*sNegativeSign,-v);
else _snprintf(s,sizeof s,"%X",v); break;
case 6:
if (e) v&=(1<<(1<<(5-e)))-1; // Überflüssige FFFFs entfernen
_snprintf(s,sizeof s,"%0*X",1<<(3-e),v); break; // Mit fester Stellenzahl (8-4-2-1) ausgeben
default: if (p) goto infinite;
_snprintf(s,sizeof s,"%.*f",nk[e],v/f); pk(s); break;
infinite: _snprintf(s,sizeof s,"%s",p);
}
SetWindowTextU(Wnd,s,sizeof s);
}
// Wert lesen / Gültigkeit überprüfen / speichern
// e = Exponent der Sekunden, daher e==0 für Position,
// e==1 für Geschwindigkeit, e==2 für Beschleunigung, e==3 für Ruck
// Bei e==1 ist p vom Typ short*, bei e>1 vom Typ char*!
// Das Ergebnis ist von <ViewMode> sowie <Eeprom..PerUnit,xs,fv> abhängig
bool CDLG::GetValue(HWND w, long*p, int e) {
char s[16];
GetWindowTextU(w,s,sizeof s);
long v;
for (v=0; v<3; v++) if (!_stricmp(s,Inf[v])) { // Unendlich und NaN auswerten
if (p) switch (e) {
case 0: v-=0x7FFFFFFE; break;
case 1: v-=0x7FFE; break;
default: v-=0x7E;
}
goto okay;
}
char*q;
if (c.ViewMode&3) {
v=strtol(s,&q,c.ViewMode&4?16:10);
if (*q) return false;
if ((c.ViewMode&3)==1 && !e) v<<=Eeprom.h.xs; // Bei Positionangaben Null-Bits einschieben
}else{
double f=strtod(s,&q);
if (*q) return false;
long k=Eeprom.h.fv;
switch (e) {
case 0: k=1; break;
case 1: break;
default: k=k*k>>-Eeprom.h.ea;
}
v=(long)rndint64(f/k*Eeprom.m[c.MotorNum].PerUnit);
}
okay:
if (p) switch (e) {
case 0: *p=v; break;
case 1: *(short*)p=(short)v; break;
case 2: *(char*)p=(char)v; break;
case 3: *(BYTE*)p=*(BYTE*)p&0xF0|v&0x0F; break; // Low-Nibble setzen
}
return true;
}
void CDLG::SetUnit(HWND Wnd, int e) {
char s[16];
if (!(c.ViewMode&3)) {
const char*p=Eeprom.m[c.MotorNum].Unit; // in UTF-8
memcpy(s,p,8); s[8]=0; // nullterminierten String erzeugen
}else s[0]=0; // TODO: Faktoren bei e!=0 dazuschreiben
if (e) {
strcat(s,"/s");
if (e>1) strcat(s,e==2?"²":"³"); // UTF8-Hochstellungen
}
SetWindowTextU(Wnd,s,sizeof s);
}
// m = was sich ändert:
// Bit 0 = Erstinitialisierung
// Bit 1 = Motor-Nummer
// Bit 2 = Einheiten
// Bit 3 = Timer
void CDLG::Page0Change(BYTE m) {
HWND hPage=p.page[0].hWnd;
if (!hPage) return;
if (hPage!=p.hwndDisplay) return;
int n=Eeprom.h.nm&0x0F; // Anzahl Achsen
bool validmotor=(unsigned)c.MotorNum<(unsigned)n;
if (m&5 && (validmotor || (c.ViewMode&3)==2)) {
SetAccel(hPage,16,c.soll.accel);
SetSpeed(hPage,18,c.soll.speed);
SetPos (hPage,52,c.soll.pos);
SetUnit (hPage,17,2);
SetUnit (hPage,19,1);
SetUnit (hPage,54,0);
}
if ((unsigned)c.MotorNum>=(unsigned)n) return; // ungültiger Index!
if (m&3) {
const char *p=(char*)&Eeprom.m[n]; // hinter alle Achskonstanten
for (int i=c.MotorNum; i; i--) p+=strlen(p)+1; // vorrücken (UTF8-String-Liste)
char s[64];
strncpy(s,p,sizeof s);
fromUTF8(s,sizeof s);
SetDlgItemText(hPage,43,(PTSTR)s);
}
if (m&1) {
SetCheckboxGroup(hPage,20,22,c.soll.flags);
}
if (m&9) {
char cmd='A'+c.MotorNum;
move_t m;
Query(&cmd,1,&m,8);
SetCheckboxGroup(hPage,32,36,m.flags);
SetAccel(hPage,40,m.accel);
SetSpeed(hPage,41,m.speed);
SetPos (hPage,42,m.pos);
struct{
BYTE cmd;
BYTE len2;
BYTE ofs;
BYTE len;
}q={0x90+c.MotorNum,2,8,1};
if (Query(&q,sizeof q, &cmd, 1)==1) {
CheckDlgButton(hPage,37,cmd>>1&1);
}
}
}
void CDLG::IncRamWriteOffsetTo(BYTE m) {
if (RamWriteOffset<m) RamWriteOffset=m;
EnableWindow(GetDlgItem(p.page[1].hWnd,3),TRUE);
}
void CDLG::Page1Change(BYTE m) {
HWND hPage=p.page[1].hWnd;
if (!hPage) return;
if (hPage!=p.hwndDisplay) return;
int n=Eeprom.h.nm&0x0F; // Anzahl Achsen
if ((unsigned)c.MotorNum>=(unsigned)n) return; // ungültiger Index!
if (m&7) {
struct{
BYTE cmd;
BYTE len2;
BYTE ofs;
BYTE len;
}q={0x90+c.MotorNum,2,8,sizeof ram};
if (Query(&q,sizeof q, &ram, sizeof ram)==sizeof ram) {
SetAccel(hPage,17,ram.MaxAccel);
SetSpeed(hPage,21,ram.MaxSpeed);
SetPos (hPage,25,ram.Soll);
SetPos (hPage,29,ram.Anfang);
SetPos (hPage,33,ram.Ende);
SetPos (hPage,37,ram.Pilger);
SetJerk (hPage,41,ram.Jerk&0x0F);
RamWriteOffset=0; // Schreiboffset
EnableWindow(GetDlgItem(hPage,3),FALSE);
}
SetUnit(hPage,19,2);
SetUnit(hPage,23,1);
SetUnit(hPage,27,0);
SetUnit(hPage,31,0);
SetUnit(hPage,35,0);
SetUnit(hPage,39,0);
SetUnit(hPage,43,3);
}
if (m&0x10) {
char s[16];
_snprintf(s,sizeof s,"%02X",ram.flags);
SetWindowTextU(GetDlgItem(hPage,64),s,sizeof s);
// SetCheckboxGroup(hPage,66,73,ram.flags);
}
}
//#define LOG2E 1.4426950408889634
struct Double{
Double(double v):val(v){}
operator double() const {return val;}
Double& operator <<= (int exp) {val=ldexp(val,exp); return *this;}
double operator << (int exp) const {return ldexp(val,exp);}
Double& operator >>= (int exp) {return *this<<=-exp;}
double operator >> (int exp) const {return *this<<-exp;}
Double& operator /= (int n) {val/=n; return *this;}
Double& operator %=(double n) {val=fmod(val,n); return *this;}
double operator % (double n) const {return fmod(val,n);}
Double& operator ^=(double n) {val=pow(val,n); return *this;}
double operator ^ (double n) const {return pow(val,n);}
double operator & (double n) const {return hypot(val,n);} // Betrag des Vektors
double operator | (double n) const {return 1/(1/val+1/n);} // Parallelschaltung (von Widerständen)
double operator ~ () const {return 1/val;} // Inversion
private: double val;
};
void CDLG::OnMotorChange() {
EeCtrl &h=Eeprom.h;
EeMotor &e=Eeprom.m[c.MotorNum];
Double u=fabs(e.PerUnit);
nka=0;
nk[0]=(char)ceil(log10(u>>h.xs)); if (nk[0]<0) nk[0]=0;
u/=h.fv;
nk[1]=(char)ceil(log10(u)); if (nk[1]<0) nk[1]=0;
u/=h.fv;
nk[2]=(char)ceil(log10(u<<h.ea)); if (nk[2]<0) nk[2]=0;
nk[3]=nk[2]; // Vorschrift noch undefiniert für Ruck
Page0Change(); // alles
Page1Change();
}
// alle 100 ms
void CDLG::PeriodicAction() {
load_t load;
if (Query("%",1,&load,4)==4) {
EeCtrl &h=Eeprom.h;
TCHAR s[8];
_sntprintf(s,elemof(s),T("%d %%"),trafo(load.min,h.le,h.lf,0,100));
SetDlgItemText(ghMainWnd,23,s);
_sntprintf(s,elemof(s),T("%d %%"),trafo(load.max,h.le,h.lf,0,100));
SetDlgItemText(ghMainWnd,24,s);
_sntprintf(s,elemof(s),T("%d %%"),trafo(load.avg,h.le<<8,h.lf<<8,0,100));
SetDlgItemText(ghMainWnd,25,s);
}
Page0Change(8);
Page1Change(8);
}
bool CDLG::Fahrt(bool reffahrt) {
struct{
BYTE cmd;
BYTE len;
move_t m;
}m;
m.cmd=0x80+c.MotorNum;
m.len=8;
m.m=c.soll;
m.m.flags=reffahrt ? m.m.flags<<1&0x0C|2 : m.m.flags<<2&4|1; // korrigieren
return Query(&m,sizeof m,NULL,0)==0;
}
struct INCDEC{
char *s,*endp1,*p,*caret;
void Inc();
bool Dec();
};
// Funktioniert auch mit Ausdrücken wie -123.45E-67
// Inkrementiert *Betrag* der Mantisse oder des Exponents
// String wird ggf. länger (bspw. bei 999 -> 1000)
void INCDEC::Inc() {
if (s==p) {
insertone:
memmove(p+1,p,(endp1-p-1)*sizeof(TCHAR));
*p='1';
caret++;
return;
}
char c=*--p;
if (strchr(sDecimal,c)) Inc();
else if (!_istdigit(c)) goto insertone;
else if (c=='9') {
*p='0';
Inc();
}else *p=++c;
}
// Dekrementiert *Betrag* der Mantisse oder des Exponents
// String wird ggf. kürzer (bspw. 1000 -> 999 oder -1 -> 0) oder länger (0 -> -1)
// Vorzeichenwechsel wird mit Rückgabe <true> angezeigt (d.h. ab da mit "Inc()" fortfahren)
bool INCDEC::Dec() {
if (s==p) return false;
char c=*--p;
if (strchr(sDecimal,c)) Dec();
else if (c=='0') {
*p='9';
Dec();
}else{
*p=--c;
if (c=='0' && _istdigit(p[1]) && !_istdigit(p[-1])) {
memmove(p,p+1,(endp1-p-1)*sizeof(TCHAR));
caret--;
}
}
return false;
}
static void IncDec(char*s, int buflen, int&caret, int delta) {
if (!*s) return;
if (!delta) return;
INCDEC incdec={s,s+buflen,NULL,s+caret};
char *pSign=strpbrk(s,sNegativeSign);
if (pSign && pSign>incdec.caret) pSign=NULL; // ohne Beachtung
if (pSign) delta=-delta;
if (delta>0) do{
incdec.p=incdec.caret;
incdec.Inc();
}while(--delta);
else do{
incdec.p=incdec.caret;
incdec.Dec();
}while(++delta);
caret=incdec.caret-s;
}
static WNDPROC DefEditProc;
static LRESULT MyEditProc(HWND Wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (msg==EM_SETSEL && wParam==0 && lParam==-1) return 0;
LRESULT r=CallWindowProc(DefEditProc,Wnd,msg,wParam,lParam);
if (msg==WM_GETDLGCODE)
r&=~DLGC_HASSETSEL;
return r;
}
static BOOL Page0Proc(HWND Wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
CDLG *o=(CDLG*)GetWindowLong(GetParent(Wnd),DWL_USER);
switch (msg) {
case WM_INITDIALOG: {
o->p.page[0].hWnd=o->p.hwndDisplay=Wnd;
o->Page0Change();
HWND hEdit=GetDlgItem(Wnd,52);
DefEditProc=SubclassWindow(hEdit,MyEditProc);
}break;
case WM_COMMAND: switch (wParam) {
case MAKELONG(16,EN_UPDATE): {
o->GetAccel((HWND)lParam,o->c.soll.accel);
}break;
case MAKELONG(18,EN_UPDATE): {
o->GetSpeed((HWND)lParam,o->c.soll.speed);
}break;
case 20:
case 21:
case 22: o->c.soll.flags^=1<<(wParam-20); break; // Flags
case MAKELONG(52,EN_UPDATE): {
o->GetPos((HWND)lParam,o->c.soll.pos);
}break;
case 48: o->Fahrt(true); break; // Referenzfahrt
case 49: { // Referenzierung aufheben
BYTE cmd='u'+o->c.MotorNum;
Query(&cmd,1,NULL,0);
}break;
case 50: { // Position nullen
BYTE cmd='n'+o->c.MotorNum;
Query(&cmd,1,NULL,0);
}break;
case 51: { // Einzelmotor abbremsen
BYTE cmd=20+o->c.MotorNum;
Query(&cmd,1,NULL,0);
}break;
case 55: o->Fahrt(false); break; // Zielfahrt
}break;
case WM_NOTIFY: {
NMHDR *nm=(NMHDR*)lParam;
switch (nm->idFrom) {
case 53: switch (nm->code) {
case UDN_DELTAPOS: {
NMUPDOWN *ud=(NMUPDOWN*)nm;
HWND hEdit=(HWND)SendMessage(ud->hdr.hwndFrom,UDM_GETBUDDY,0,0);
char s[32];
GetWindowTextU(hEdit,s,sizeof s);
int caret;
SendMessage(hEdit,EM_GETSEL,NULL,(LPARAM)&caret);
IncDec(s,sizeof s,caret,-ud->iDelta);
SetWindowTextU(hEdit,s,sizeof s);
SendMessage(hEdit,EM_SETSEL,caret,caret);
SetWindowLong(Wnd,DWL_MSGRESULT,1);
}return TRUE;
}break;
}
}break;
}
return FALSE;
}
static BOOL Page1Proc(HWND Wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
CDLG *o=(CDLG*)GetWindowLong(GetParent(Wnd),DWL_USER);
switch (msg) {
case WM_INITDIALOG: {
o->p.page[1].hWnd=o->p.hwndDisplay=Wnd;
o->Page1Change();
}break;
case WM_COMMAND: switch (wParam) {
case MAKELONG(1,BN_CLICKED): {
o->Page1Change();
}break;
case MAKELONG(3,BN_CLICKED): {
struct{
BYTE cmd;
BYTE len;
ram_t ram;
}q;
q.cmd=0x88+o->c.MotorNum;
q.len=2+o->RamWriteOffset;
q.ram=o->ram; // Strukturkopie
Query(&q,sizeof q,NULL,0);
}break;
case 64: {
char s[32];
GetWindowTextU((HWND)lParam,s,sizeof s);
o->ram.flags=(BYTE)strtol(s,NULL,16);
SetCheckboxGroup(Wnd,66,73,o->ram.flags);
}
case 66:
case 68:
case 69:
case 70:
case 71:
case 72:
case 73: {
o->ram.flags^=1<<(wParam-66);
o->Page1Change(0x10);
o->IncRamWriteOffsetTo(offsetof(ram_t,flags)+sizeof(o->ram.flags));
}break;
}break;
}
return FALSE;
}
static BOOL MainDlgProc(HWND Wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
CDLG *o=(CDLG*)GetWindowLong(Wnd,DWL_USER);
switch (msg) {
case WM_INITDIALOG: {
o=(CDLG*)lParam;
SetWindowLong(Wnd,DWL_USER,lParam);
o->p.hwndDlg=Wnd;
SendDlgItemMessage(Wnd,16,CBEM_SETIMAGELIST,0,(LPARAM)SetupDiClassImageList.ImageList);
SendMessage(Wnd,WM_WININICHANGE,0,0);
o->c.LoadConfig(Wnd);
SetDlgItemInt(Wnd,21,o->c.MotorNum,FALSE);
CheckDlgButton(Wnd,80+(o->c.ViewMode&3),TRUE);
if (o->c.ViewMode&4) CheckDlgButton(Wnd,83,TRUE); // Hexadezimal-Bit
if (!(o->c.ViewMode&3)) EnableWindow(GetDlgItem(Wnd,83),FALSE);
HWND cb=GetDlgItem(Wnd,16);
SerComboUpdate(cb);
SendMessage(Wnd,WM_COMMAND,MAKELONG(16,CBN_SELCHANGE),(LPARAM)cb);
o->p.hwndTab=GetDlgItem(Wnd,30);
o->p.nPages=3;
o->p.page[0].szTemplate=MAKEINTRESOURCE(101);
o->p.page[0].dlgProc=Page0Proc;
o->p.page[1].szTemplate=MAKEINTRESOURCE(102);
o->p.page[1].dlgProc=Page1Proc;
o->p.page[2].szTemplate=MAKEINTRESOURCE(103);
o->p.OnInit();
}return TRUE;
case WM_DEVICECHANGE: {
SetTimer(Wnd,1,1500,NULL); // aktualisieren lassen
}break;
case WM_WININICHANGE: {
GetLocaleInfoA(LOCALE_USER_DEFAULT,LOCALE_SDECIMAL,sDecimal,sizeof sDecimal);
sDecimal[1]='.';
sDecimal[2]=',';
sDecimal[3]=0;
GetLocaleInfoA(LOCALE_USER_DEFAULT,LOCALE_SNEGATIVESIGN,sNegativeSign,sizeof sNegativeSign);
sNegativeSign[1]='-';
sNegativeSign[2]=0;
#ifdef UNICODE
const char *p="\342\210\236";
#else
const char *p="INF";
#endif
_snprintf(Inf[0],8,"%s%s",sNegativeSign,p);
Inf[0][0]=sNegativeSign[0];
_snprintf(Inf[1],8,"NaN");
_snprintf(Inf[2],8,"+%s",p);
}break;
case WM_TIMER: switch (wParam) {
case 1: {
KillTimer(Wnd,wParam);
SerComboUpdate(GetDlgItem(Wnd,16));
}break;
case 2: o->PeriodicAction(); break;
}break;
case WM_ENDSESSION: {
if (wParam) o->c.SaveConfig(Wnd);
}break;
case WM_CLOSE: {
o->c.SaveConfig(Wnd);
if (hCom) CloseHandle(hCom);
EndDialog(Wnd,wParam);
}break;
case WM_COMMAND: switch (wParam) {
case IDCANCEL: {
BYTE cmd='c';
Query(&cmd,1,NULL,0); // Alle Achsen stoppen
}break;
case MAKELONG(16,CBN_SELCHANGE): {
KillTimer(Wnd,2);
if (hCom) CloseHandle(hCom);
COMBOBOXEXITEM cbei;
cbei.mask=CBEIF_LPARAM;
cbei.iItem=ComboBox_GetCurSel((HWND)lParam);
if (cbei.iItem>=0) {
SendMessage((HWND)lParam,CBEM_GETITEM,0,(LPARAM)&cbei);
main.c.ComNum=(BYTE)cbei.lParam;
hCom=ComOpen(cbei.lParam);
if (hCom) {
QueryBasicParams();
o->OnMotorChange();
SetTimer(Wnd,2,100,NULL);
}
}
}break;
case MAKELONG(21,EN_UPDATE): if (o) {
o->c.MotorNum=GetDlgItemInt(Wnd,21,NULL,FALSE);
if (hCom) o->OnMotorChange();
}break;
case 80:
case 81:
case 82: {
o->c.ViewMode=o->c.ViewMode&0xFC|wParam-80;
EnableWindow(GetDlgItem(Wnd,83),o->c.ViewMode&3?TRUE:FALSE);
o->ViewModeChanged();
}break;
case 83: {
o->c.ViewMode^=0x04;
o->ViewModeChanged();
}break;
}break;
case WM_NOTIFY: {
NMHDR *n=(NMHDR*)lParam;
switch (n->idFrom) {
case 30: switch (n->code) {
case TCN_SELCHANGE: {
o->p.OnSelChange();
}break;
}break;
}
}break;
}
return FALSE;
}
EXTERN_C void CALLBACK WinMainCRTStartup() {
WNDCLASS wc={
CS_DBLCLKS,
DefDlgProc,
0,
DLGWINDOWEXTRA,
ghInstance=GetModuleHandle(NULL),
LoadIcon(ghInstance,MAKEINTRESOURCE(1)),
LoadCursor(0,IDC_ARROW),
(HBRUSH)(COLOR_BACKGROUND+1),
NULL,
T("smc2")
};
RegisterClass(&wc);
InitCommonControls();
LoadString(ghInstance,1,StdMBoxTitle,elemof(StdMBoxTitle));
SetupDiClassImageList.cbSize=sizeof(SetupDiClassImageList);
SetupDiGetClassImageList(&SetupDiClassImageList);
ExitProcess(DialogBoxParam(0,MAKEINTRESOURCE(100),0,MainDlgProc,(LPARAM)&main));
}
Detected encoding: UTF-8 | 0
|