Source file: /~heha/mb-iwp/NA/MSVC.zip/src/Piezomess.cpp

/* 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
Wrong umlauts? - Assume file is ANSI (CP1252) encoded