/* Hauptprogramm zu PiezoMess, ein Schnellemachefix-Programm.
Läuft mit msvcrt.dll, benötigt keine skurrile msvcrXX.dll.
150504 erstellt, heha
*230921 Umstellung Rundung auf lrint() und llrint(), 64 Bit
-230925 Graf-Linienbreite 0, sonst ist das Programm unerträglich lahm
Diverse strukturelle Umstellungen
*/
#include "PiezoMess.h"
/************
* Globales *
************/
HINSTANCE ghInstance;
HWND ghMainWnd;
HWND hGain,hOffs; // Amplitude und Offset (Schieberegler am oberen Rand)
GDI gdi; // Gemeinsam genutzte GDI-Objekte
CONFIG Config;
TCHAR StdMBoxTitle[64];
TCHAR gCsvName[MAX_PATH];
TCHAR sDecimal[2]; // je nach Windows-Einstellung
TCHAR sNegativeSign[2];
TCHAR sPositiveSign[2];
DWORD gDdeInst;
UINT CF_XlTable; // Clipboard-Format
extern "C" void _cdecl _fltused() {}; // Linker ruhig stellen
//Trace traces[2];
const ScaleCfg scalecfg={T("Arial"),16};
const Divider divider[2]={{RGB(128,128,128)},{RGB(64,64,64)}};
/*
EXTERN_C long _declspec(naked) _cdecl _ftol2_sse() {_asm{
push eax
fistp dword ptr [esp]
fwait
pop eax
ret
}}
*/
#ifdef _DEBUG
void _cdecl DebugPrintf(const char*s,...) {
char buf[256];
va_list va;
va_start(va,s);
_vsnprintf(buf,elemof(buf),s,va);
OutputDebugStringA(buf);
}
#endif
FEATURE feature;
ADCMEAN adcmean;
int FloatToStringW(double f, int nk, PWSTR s, int slen) {
int ret=_snwprintf(s,slen,L"%.*f",nk,f);
PWSTR p=wcschr(s,'-');
if (p) *p=sNegativeSign[0];
p=wcschr(s,'.');
if (p) *p=sDecimal[0];
return ret;
}
int FloatToStringA(double f, int nk, PSTR s, int slen) {
int ret=_snprintf(s,slen,"%.*f",nk,f);
PSTR p=strchr(s,'-');
if (p && !(sNegativeSign[0]&~0x7F)) *p=(char)sNegativeSign[0]; // prüfen auf ASCII-Zeichen …
p=strchr(s,'.');
if (p) *p=(char)sDecimal[0];
return ret;
}
void GDI::init() {
int i;
for (i=0; i<4; i++) fntScale[i]=CreateFont(
scalecfg.fontsize,0,
i&1?900:0, i&1?900:0,
i&2?700:0,
0,0,0,0,0,0,0,0,
scalecfg.fontname);
Trace const *traces[] = {sweep.amp.trace,sweep.pha.trace};
for (i=0; i<elemof(traces); i++) penGraph[i]=CreatePen(
traces[i]->penstyle,traces[i]->penwidth,traces[i]->color);
for (i=0; i<elemof(divider); i++) penDivider[i]=CreatePen(
divider[i].penstyle,divider[i].penwidth,divider[i].color);
}
void GDI::done() {
HGDIOBJ *p=(HGDIOBJ*)this;
do if (*p && DeleteObject(*p)) *p=0;
while ((char*)++p<(char*)this+sizeof(*this));
}
/****************
* aus WUTILS.C *
****************/
//Win32-typische Strukturen mit DWORD-Ausrichtung initialisieren
void _fastcall InitStruct(LPVOID p, UINT len) {
ZeroMemory(p,len);
*(UINT*)p=len;
}
int vMBox(HWND Wnd, LPCTSTR Text, DWORD Type, va_list va) {
TCHAR buf[256];
if (IS_INTRESOURCE(Text)) {
TCHAR s[256];
LoadString(ghInstance,(UINT)(DWORD_PTR)Text,s,elemof(s));
Text = s;
}
DWORD e;
if (Type&MB_ErrorText) e = va_arg(va,DWORD);
int l = _vsntprintf(buf,elemof(buf),Text,va);
if (Type&MB_ErrorText) {
TCHAR s[120];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,e,0,s,elemof(s),0);
_sntprintf(buf+l,elemof(buf)-l,T("\n\n%s"),s);
}
if (Type&MB_Sound) MessageBeep(Type&MB_ICONMASK);
return MessageBox(Wnd,buf,StdMBoxTitle,Type&~MB_Sound);
}
int _cdecl MBox(HWND Wnd, LPCTSTR Text, DWORD Type, ...) {
va_list va;
va_start(va,Type);
return vMBox(Wnd,Text,Type,va);
}
/****************
* Hauptfenster *
****************/
void LoadConfig(void) {
HKEY key;
if (RegOpenKey(HKEY_CURRENT_USER,T("Software\\h#s\\Piezomess"),&key)) return;
DWORD size=sizeof Config;
RegQueryValueEx(key,T("Config"),NULL,NULL,(LPBYTE)&Config,&size);
size=sizeof gCsvName;
RegQueryValueEx(key,T("CsvName"),NULL,NULL,(LPBYTE)&gCsvName,&size);
RegCloseKey(key);
if (Config.ShowCmd) {
WINDOWPLACEMENT wp;
wp.length=sizeof wp;
GetWindowPlacement(ghMainWnd,&wp);
Config.WndPos.toRect(wp.rcNormalPosition);
wp.showCmd=Config.ShowCmd;
SetWindowPlacement(ghMainWnd,&wp);
}
if (!Config.GuiDelay) {
Config.GuiDelay=80;
Config.flags|=0x80; // setze bRunningUpdate
}
}
void SaveConfig(void) {
WINDOWPLACEMENT wp;
wp.length=sizeof wp;
GetWindowPlacement(ghMainWnd,&wp);
if (wp.showCmd) {
Config.WndPos=wp.rcNormalPosition;
Config.ShowCmd=wp.showCmd;
}
HKEY key;
if (RegCreateKey(HKEY_CURRENT_USER,T("Software\\h#s\\Piezomess"),&key)) return;
TCHAR s[64]; // zuerst eine Klartext-Beschreibung setzen
RegSetValueEx(key,NULL,0,REG_SZ,(LPBYTE)s,LoadString(ghInstance,1,s,elemof(s))*sizeof(TCHAR));
RegSetValueEx(key,T("Config"),0,REG_BINARY,(LPBYTE)&Config,sizeof Config);
RegSetValueEx(key,T("CsvName"),0,REG_SZ,(LPBYTE)&gCsvName,(lstrlen(gCsvName)+1)*sizeof(TCHAR));
RegCloseKey(key);
}
void ReposChilds() {
HDWP wpi=BeginDeferWindowPos(4);
const int Y=32;
int midx=sweep.bbox.midx();
wpi=DeferWindowPos(wpi,GetPrevSibling(hGain),0,sweep.bbox.left,Y,midx-sweep.bbox.left,sweep.bbox.top-Y,SWP_NOZORDER);
wpi=DeferWindowPos(wpi,hGain,0,sweep.bbox.left,0,midx-sweep.bbox.left,Y,SWP_NOZORDER);
wpi=DeferWindowPos(wpi,GetPrevSibling(hOffs),0,midx,Y,sweep.bbox.right-midx,sweep.bbox.top-Y,SWP_NOZORDER);
wpi=DeferWindowPos(wpi,hOffs,0,midx,0,sweep.bbox.right-midx,Y,SWP_NOZORDER);
EndDeferWindowPos(wpi);
}
LRESULT CALLBACK MainWndProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
case WM_CREATE: {
ghMainWnd=Wnd;
HMENU SysMenu=GetSystemMenu(Wnd,FALSE);
SendMessage(Wnd,WM_WININICHANGE,0,0);
SendMessage(Wnd,WM_QUERYOPEN,0,0); // Titel setzen
LoadConfig();
gdi.init();
CheckMenuItem(GetMenu(Wnd),0x30,Config.flags&0x80?MF_CHECKED:0);
SetWindowFont(CreateWindowEx(0,T("static"),T("Treiber-&Amplitude"),WS_VISIBLE|WS_CHILD|WS_GROUP|SS_CENTER,
0,0,0,0,Wnd,(HMENU)-1,ghInstance,NULL),GetStockFont(DEFAULT_GUI_FONT),false);
hGain=CreateWindowEx(0,TRACKBAR_CLASS,NULL,WS_VISIBLE|WS_CHILD|WS_TABSTOP|WS_GROUP|TBS_AUTOTICKS|TBS_TOOLTIPS,
0,0,0,0,Wnd,(HMENU)11,ghInstance,NULL);
SetWindowFont(CreateWindowEx(0,T("static"),T("Treiber-&Offset"),WS_VISIBLE|WS_CHILD|WS_GROUP|SS_CENTER,
0,0,0,0,Wnd,(HMENU)-1,ghInstance,NULL),GetStockFont(DEFAULT_GUI_FONT),false);
hOffs=CreateWindowEx(0,TRACKBAR_CLASS,NULL,WS_VISIBLE|WS_CHILD|WS_TABSTOP|WS_GROUP|TBS_AUTOTICKS|TBS_TOOLTIPS,
0,0,0,0,Wnd,(HMENU)11,ghInstance,NULL);
SendMessage(hGain,TBM_SETRANGE,TRUE,MAKELONG(-2046,2046));
SendMessage(hGain,TBM_SETTICFREQ,128,0);
SendMessage(hOffs,TBM_SETRANGE,TRUE,MAKELONG(-2046,2046));
SendMessage(hOffs,TBM_SETTICFREQ,128,0);
SetFocus(hGain);
PostMessage(Wnd,WM_ContinueInit,0,0);
}break;
case WM_ContinueInit: {
if (Config.ShowCmd) w.start(Wnd);
else Send_WM_Command(Wnd,0x40,0,0); // beim ersten Start sofort zur Konfiguration
}break;
case WM_ComFail: { // aus Worker-Tread
if (MBox(Wnd,(LPCTSTR)6,
MB_ICONERROR|MB_OKCANCEL|MB_Sound|MB_ErrorText,
(DWORD)wParam,Config.SerialNo+1)==IDOK)
Send_WM_Command(Wnd,0x40,0,0);
}break;
case WM_WININICHANGE: { // TODO: Windows-Funktion FormatFloat o.ä. gefunden!
GetProfileString(T("intl"),T("sDecimal"), T("."),sDecimal, elemof(sDecimal));
GetProfileString(T("intl"),T("sNegativeSign"),T("-"),sNegativeSign,elemof(sNegativeSign));
GetProfileString(T("intl"),T("sPositiveSign"),T(""), sPositiveSign,elemof(sPositiveSign));
}return 0;
case WM_SIZE: {
if (wParam!=SIZE_MINIMIZED) {
if (gdi.fntBig) DeleteFont(gdi.fntBig);
gdi.fntBig=CreateFont(-GET_Y_LPARAM(lParam),GET_X_LPARAM(lParam)/12,0,0,0,0,0,0,0,0,0,0,0,T("Arial"));
sweep.Resize(lParam);
ReposChilds();
}
}break;
case WM_Update: {
if (!IsIconic(Wnd)) InvalidateRect(Wnd,&sweep.bbox,FALSE);
// DdePostAdvise(gDdeInst,0,0);
}break;
case WM_UpdateFeature: {
SendMessage(hGain,TBM_SETPOS,TRUE,feature.g);
SendMessage(hOffs,TBM_SETPOS,TRUE,feature.o);
sweep.ChangeScale();
if (hSweepDlg) PostMessage(hSweepDlg,Msg,wParam,lParam);
}break;
case WM_ChangeFeature: {
sweep.ChangeScale();
w.post('C'|0x80,&feature,sizeof feature); // senden lassen
}break;
case WM_PAINT: {
PAINTSTRUCT ps;
BeginPaint(Wnd,&ps);
RECT dummy;
if (SubtractRect(&dummy,&ps.rcPaint,&sweep.bbox)) SendMessage(Wnd,WM_PRINTCLIENT,(WPARAM)ps.hdc,0);
else sweep.Draw(ps.hdc,false); // nur das Oszibild
EndPaint(Wnd,&ps);
}return 0;
case WM_PRINTCLIENT: {
// RECT r;
// GetClientRect(Wnd,&r);
// SelectFont((HDC)wParam,gdi.fntBig);
// SetTextAlign((HDC)wParam,TA_BOTTOM|TA_CENTER);
// ExtTextOut((HDC)wParam,r.right/2,r.bottom,ETO_OPAQUE,&r,gAnzeige,lstrlen(gAnzeige),NULL);
sweep.Draw((HDC)wParam);
}break;
case WM_QUERYOPEN: {
TCHAR s[64];
LoadString(ghInstance,1,s,elemof(s));
SetWindowText(Wnd,s);
}break;
/*
case WM_COPY: {
HGLOBAL hMem=GlobalAlloc(GMEM_MOVEABLE,(lstrlen(gAnzeige)+1)*sizeof(TCHAR));
if (!hMem) break;
if (OpenClipboard(Wnd) && EmptyClipboard()) {
lstrcpy((LPTSTR)GlobalLock(hMem),gAnzeige);
GlobalUnlock(hMem);
SetClipboardData(CF_TXT,hMem);
CloseClipboard();
}else GlobalFree(hMem);
}break;
*/
case WM_HSCROLL: switch (LOWORD(wParam)) {
case TB_ENDTRACK: {
feature.g=(short)SendMessage(hGain,TBM_GETPOS,0,0);
feature.o=(short)SendMessage(hOffs,TBM_GETPOS,0,0);
w.post('C'|0x80,&feature,sizeof feature); // senden lassen
}break;
}break;
case WM_COMMAND: // von TranslateAccelerator
case WM_SYSCOMMAND: switch (wParam&0xFFF0) {
case 0x10: SendMessage(Wnd,WM_CLOSE,0,0);
case 0x30: { // Laufende Aktualisierung ein/aus
Config.flags^=0x80;
CheckMenuItem(GetMenu(Wnd),(UINT)wParam,Config.flags&0x80?MF_CHECKED:0);
}break;
case 0x40: if (DialogBox(ghInstance,MAKEINTRESOURCE(100),Wnd,HardwareDlgProc)==IDOK) {
w.start(Wnd);
}break;
case 0x50: if (hSweepDlg) SetFocus(hSweepDlg); else hSweepDlg=CreateDialog(ghInstance,MAKEINTRESOURCE(101),Wnd,SweepDlgProc); break;
case 0x60: {
if (!sweep.backup) sweep.backup=(SDATA**)LocalAlloc(LPTR,sizeof(SDATA*));
else sweep.backup=(SDATA**)LocalReAlloc(sweep.backup,sizeof(SDATA*)*(sweep.nbackup+1),LMEM_MOVEABLE);
sweep.backup[sweep.nbackup]=new SDATA[sweep.width];
memcpy(sweep.backup[sweep.nbackup],sweep.data,sweep.width*3);
sweep.nbackup++;
}break;
case 0x70: {
for (;sweep.nbackup;) delete[] sweep.backup[--sweep.nbackup];
if (sweep.backup) sweep.backup=(SDATA**)LocalFree(sweep.backup);
}break;
case 0x80: SaveCSV();
}break;
case WM_CLOSE: {
w.stop();
SendMessage(Wnd,WM_ENDSESSION,1,0); // speichern auslösen!
}break;
case WM_ENDSESSION: if (wParam) SaveConfig(); break;
case WM_DESTROY: {
gdi.done();
PostQuitMessage(0);
}break;
}
return DefWindowProc(Wnd,Msg,wParam,lParam);
}
void UNIT::Init(int pre, PCTSTR n) {
static const TCHAR units3[]=T("yzafpnµm\0kMGTPEZY");
Pre=pre;
Mul=(float)exp(pre*M_LN10);
switch (pre) {
case 1: lstrcpyn(Chr,T("da"),elemof(Chr)); break;
case -2: Chr[0]='c'; goto term;
case -1: Chr[0]='d'; goto term;
case 2: Chr[0]='h'; goto term;
default: Chr[0]=units3[pre/3+8];
term: Chr[1]=0;
}
if (n) lstrcpyn(Name,n,elemof(Name));
_sntprintf(Text,elemof(Text),T("%s%s"),Chr,Name);
}
void FEATURE::SetFu(float v) {
float fo=GetFo();
fu=lrint(v/FSCALE);
SetFo(fo);
}
void FEATURE::SetFo(float fo) {
fo/=FSCALE;
if (IsLog()) { // bedingt fu!=0
fa=0;
if (steps>1) {
double x=fo/fu; // Frequenzverhältnis
x=log(x);
x/=steps-1;
x=exp(x)-1;
fm=lrint(x*4294967296);
}else fm=0;
}else{
fa=steps>1?lrint((fo-fu)/(steps-1)):0; // geschlossenes Intervall
fm=0;
}
PostMessage(ghMainWnd,WM_ChangeFeature,0,0);
}
void FEATURE::SetLog(bool l) {
float fo=GetFo();
if (l) {
if (!fu) fu=1;
fm=1;
}else fm=0;
SetFo(fo);
}
void FEATURE::SetSteps(int v) {
float fo=GetFo();
steps=(WORD)v;
SetFo(fo);
}
void FEATURE::SetT(float v) {SetSteps(lrint(v/TSAMPLE));}
void FEATURE::SetHV(float v) {
hv=(WORD)lrint(v/HVSCALE);
w.post('C'|0x80,this,sizeof*this); // senden lassen
}
#ifdef _M_IX86
__forceinline long Mul32x32shr32(long x, long y) {
_asm mov eax,x
_asm mov edx,y
_asm imul edx
_asm xchg edx,eax
}
#else
__forceinline long Mul32x32shr32(long x, long y) {return (__int64)x*y>>32;}
#endif
float FEATURE::GetFu() {return fu*FSCALE;}
float FEATURE::GetFo() {
long fc=fu;
for (int i=1; i<steps; i++) fc+=fa+Mul32x32shr32(fc,fm); // Algorithmus im Mikrocontroller nachvollziehen
return fc*(float)FSCALE;
}
float FEATURE::GetT() {return steps*TSAMPLE;}
float FEATURE::GetHV() {return hv*HVSCALE;}
bool FEATURE::IsLog() {return fu && fm;}
/******************************
* Hauptprogramm (lächerlich) *
******************************/
int _stdcall WinMainCRTStartup(void) {
ghInstance=GetModuleHandle(NULL);
LoadString(0,0,StdMBoxTitle,elemof(StdMBoxTitle)); // Piezomess
WNDCLASSEX wc;
InitStruct(&wc,sizeof(wc));
wc.style=CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc=MainWndProc;
wc.hInstance=ghInstance;
wc.hCursor=LoadCursor(0,IDC_ARROW);
wc.hIcon=LoadIcon(ghInstance,MAKEINTRESOURCE(100));
wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName=MAKEINTRESOURCE(100);
wc.lpszClassName=T("Piezomess");
RegisterClassEx(&wc);
InitCommonControls(); // wichtig für Teletubbieoptik!
adcmean.ref=2048;
FreqUnit.Init(6,T("Hz")); // erstmal MHz
sweep.hMutex=CreateMutex(NULL,FALSE,NULL);
sweep.width =2;
sweep.x.a =NaN;
sweep.x.e =NaN;
sweep.x.tick=NaN;
sweep.x.name=T("Frequenz");
sweep.x.unit=FreqUnit.Text;
sweep.x.nk =1;
sweep.amp.a =-30;
sweep.amp.e =+30;
sweep.amp.tick=10;
sweep.amp.vert=true;
sweep.amp.trace = new Trace(T("Amplitude"),T("dB"),RGB(255,255,0)/*gelb*/,0);
sweep.pha.a =-180;
sweep.pha.e = 0;
sweep.pha.tick=45;
sweep.pha.vert=true;
sweep.pha.mirror=true;
sweep.pha.trace = new Trace(T("Phase"),T("°"),RGB(0,255,255)/*türkis*/,0);
ghMainWnd=CreateWindowEx(WS_EX_ACCEPTFILES|WS_EX_OVERLAPPEDWINDOW,
T("Piezomess"),NULL,WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,0,
CW_USEDEFAULT,0,
0,0,ghInstance,GetCommandLine());
ShowWindow(ghMainWnd,SW_SHOWDEFAULT);
/*
CF_XlTable=RegisterClipboardFormat(T("XlTable")); // Excel-Tabellenformat
DdeInitialize(&gDdeInst,DdeCallback,APPCLASS_STANDARD
|CBF_FAIL_POKES|CBF_FAIL_EXECUTES
|CBF_SKIP_CONNECT_CONFIRMS|CBF_SKIP_REGISTRATIONS
|CBF_SKIP_DISCONNECTS|CBF_SKIP_UNREGISTRATIONS,0);
HSZ hsz=DdeCreateStringHandle(gDdeInst,T("Piezomess"),CP_WINNEUTRAL);
DdeNameService(gDdeInst,hsz,0,DNS_REGISTER|DNS_FILTERON);
DdeFreeStringHandle(gDdeInst,hsz);
*/
MSG Msg;
HACCEL hAccel=LoadAccelerators(ghInstance,MAKEINTRESOURCE(100));
while (GetMessage(&Msg,0,0,0)) {
if (TranslateAccelerator(ghMainWnd,hAccel,&Msg)) continue;
if (IsDialogMessage(ghMainWnd,&Msg)) continue;
if (IsDialogMessage(hSweepDlg,&Msg)) continue;
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
// DdeUninitialize(gDdeInst);
CloseHandle(sweep.hMutex);
delete sweep.pha.trace;
delete sweep.amp.trace;
ExitProcess((UINT)Msg.wParam);
}
| Detected encoding: ANSI (CP1252) | 4
|
|
|