/****************************************
* Projekt: Funkuhr DCF77 *
* Eigenschaftsseite äDemodulatorô *
* Beobachtung der I/Q-Demodulation *
****************************************/
#include "Funkuhr.h"
// Dialog-Daten, verschwinden mit dem Fokusverlust
#define HISTIQ 32
typedef struct {
int iqidx;
int lastr; // letzter Radius (Vektordiagramm)
int lastv; // letztes Maximum der FFT
POINT lastiq[HISTIQ]; // Vektoren, i = x, q = y (positiv nach oben)
int lasta[HISTIQ]; // Amplituden (erspart hier das Wurzelziehen)
struct {
HFONT fText; // kleine Schrift fⁿr Skalenbeschriftung (?) und Frequenzanzeige
HPEN pVektor[HISTIQ],pKreis,pAchse;
}gdi;
}dlg;
INT_PTR CALLBACK DemodulatorDlgProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
dlg*D=(dlg*)GetWindowLongPtr(Wnd,DWLP_USER);
DefHelpProc(Wnd,Msg,lParam,109);
switch (Msg) {
case WM_INITDIALOG: {
HWND w;
CheckDlgButton(Wnd,18,!DemodIQ.NoAGC); // AGC
ShowDlgItem(Wnd,18,Config.iDemodTrig&2?SW_HIDE:SW_SHOW);
CheckDlgButton(Wnd,16,Config.iDemodTrig&1); // AFC
CheckDlgButton(Wnd,17,Config.iDemodTrig>>1&1);// Phasendemodulation
w=GetDlgItem(Wnd,12); // AGC-Pegel
SendMessage(w,TBM_SETRANGE,FALSE,MAKELONG(0,63));
SendMessage(w,TBM_SETTICFREQ,9,0);
SendMessage(w,TBM_SETPOS,TRUE,Config.iDemodTrig>>2);
EnableWindow(w,DemodIQ.NoAGC);
ShowWindow(w,Config.iDemodTrig&2?SW_HIDE:SW_SHOW);
AttachUpDown(Wnd,32,33,0,0,0); // Frequenz grob
w=GetDlgItem(Wnd,34); // Frequenz fein (AFC)
SendMessage(w,TBM_SETRANGE,FALSE,MAKELONG(-126,126));
SendMessage(w,TBM_SETTICFREQ,18,0);
//SendMessage(w,TBM_SETPOS,TRUE,fein);
EnableWindow(w,!(Config.iDemodTrig&1));
// gelb und ohne Animationseffekte bei Stillstand
SendDlgItemMessage(Wnd,13,WM_USER+16/*PBM_SETSTATE*/,3/*PBST_PAUSED*/,0);
SendDlgItemMessage(Wnd,14,WM_USER+16/*PBM_SETSTATE*/,3/*PBST_PAUSED*/,0);
}return TRUE;
case WM_COMMAND: switch ((DWORD)wParam) {
case MAKELONG(16,BN_CLICKED): {
EnableDlgItem(Wnd,34,Config.iDemodTrig&1);
Config.iDemodTrig^=1;
}break;
case MAKELONG(17,BN_CLICKED): {
int i=Config.iDemodTrig&2?SW_SHOW:SW_HIDE;
Config.iDemodTrig^=2;
ShowDlgItem(Wnd,12,i);
ShowDlgItem(Wnd,18,i);
}break;
case MAKELONG(18,BN_CLICKED): {
DemodIQ.NoAGC=!DemodIQ.NoAGC;
EnableDlgItem(Wnd,12,DemodIQ.NoAGC);
}break;
case MAKELONG(32,EN_CHANGE): {
SetTimer(Wnd,32,100,NULL);
}break;
case MAKELONG(36,BN_CLICKED): {
DemodIQ.DoFFT = DemodIQ.DoFFT ? 0 : 255;
}break;
}break;
case WM_TIMER: switch ((BYTE)wParam) {
case 32: {
int f;
if (GetUpDownInt(Wnd,33,&f)) {
SetFiltFreq(f*100+(int)SendDlgItemMessage(Wnd,34,TBM_GETPOS,0,0));
}
}break;
}break;
case WM_VSCROLL: {
Config.iDemodTrig=(BYTE)(Config.iDemodTrig&3|(63-(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0))<<2);
if (DemodIQ.NoAGC) SetTrig();
}break;
case WM_HSCROLL: {
if ((BYTE)wParam==SB_ENDSCROLL) { // Schieber wieder Richtung Mitte ziehen
int fein=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
int ganz;
if (GetUpDownInt(Wnd,33,&ganz)) {
if (fein<=-100) {fein+=100; ganz--;}
else if (fein>=100) {fein-=100; ganz++;}
else goto skip;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,fein);
SendDlgItemMessage(Wnd,33,UDM_SETPOS32,0,ganz);
KillTimer(Wnd,32);
skip:;
}
}else SendMessage(Wnd,WM_COMMAND,MAKELONG(32,EN_CHANGE),0);
}break;
case WM_DRAWITEM: {
DRAWITEMSTRUCT *dis=(void*)lParam;
HDC dc=CreateCompatibleDC(dis->hDC);
SIZE sz={dis->rcItem.right-dis->rcItem.left,dis->rcItem.bottom-dis->rcItem.top};
HBITMAP bm=CreateCompatibleBitmap(dis->hDC,sz.cx,sz.cy);
HBITMAP obm=SelectBitmap(dc,bm);
SelectBrush(dc,(HBRUSH)SendMessage(Wnd,WM_CTLCOLORDLG,(WPARAM)dc,(LPARAM)Wnd));
PatBlt(dc,0,0,sz.cx,sz.cy,PATCOPY);
if (D) {
WCHAR s[32];
int a,ph;
DemodIQ.lock|=1; // FFT_Data nicht verΣndern oder gar freigeben
if (DemodIQ.FFT_Data) {
int k=2<<DemodIQ.FFT_LenShift;
int i;
int xlast=-1;
int ylast;
int vmax=MulDiv(D->lastv,15,16);
if (vmax<16) vmax=16;
for (i=0; i<k; i+=2) {
int v=hypot_lazy(DemodIQ.FFT_Data[i],DemodIQ.FFT_Data[i+1]);
DemodIQ.FFT_Data[i]=v;
DemodIQ.FFT_Data[i+1]=0;
if (vmax<v) vmax=v;
}
D->lastv=vmax;
// Nicht bspw. 22050 Linien zeichnen, sondern je eine pro Y-Pixel, jeweils das Maximum
for(i=0; i<k; i+=2) {
int x=MulDiv(i,sz.cx,k);
int y=DemodIQ.FFT_Data[i];
if (xlast!=x) {
if (xlast>=0) Line(dc,xlast,sz.cy-ylast,xlast,sz.cy);
xlast=x;
ylast=0;
}
if (ylast<y) ylast=y;
}
Line(dc,xlast,sz.cy-ylast,xlast,sz.cy);
}else{
int i,rad=MulDiv(D->lastr,15,16); // Gleitende Skalierung (beim Vergr÷▀ern)
if (rad<16) rad=16; // Minimalradius!
for(i=0; i<HISTIQ; i++) {
int r=D->lasta[i];
if (rad<r) rad=r;
}
D->lastr=rad;
SaveDC(dc);
SetGraphicsMode(dc,GM_ADVANCED);
SetViewportOrgEx(dc,sz.cx>>1,sz.cy>>1,NULL); // in die Bitmap-Mitte
SetMapMode(dc,MM_ISOTROPIC); // Kreise als Kreise erscheinen lassen
SetWindowExtEx(dc,(rad<<1),(rad<<1),NULL); // 2x Radius als Skalierung
SetViewportExtEx(dc,dis->rcItem.right-dis->rcItem.left-1,dis->rcItem.top-dis->rcItem.bottom+1,NULL);
SelectBrush(dc,GetStockBrush(BLACK_BRUSH));
Ellipse(dc,-rad,-rad,rad,rad);
SelectPen(dc,D->gdi.pAchse);
Line(dc,rad,0,-rad,0);
Line(dc,0,-rad,0,rad);
if (!(Config.iDemodTrig&2)) { // nur bei AM
SelectBrush(dc,GetStockBrush(HOLLOW_BRUSH));
SelectPen(dc,D->gdi.pKreis);
rad=DemodIQ.at;
Ellipse(dc,-rad,-rad,rad,rad);
}
for(i=0; i<HISTIQ; i++) { // mit der dunkelsten Linie beginnen
int k=(i+D->iqidx)&(HISTIQ-1);
SelectPen(dc,D->gdi.pVektor[i]);
Line(dc,D->lastiq[k].x,D->lastiq[k].y,0,0);
if (i==HISTIQ-1) {
ph=lrint(atan2(D->lastiq[k].y,D->lastiq[k].x)*180/PI);
a=D->lasta[k];
}
}
RestoreDC(dc,-1);
}
DemodIQ.lock&=~1;
if (!DemodIQ.FFT_Data) {
int f,r;
SIZE fs; // Schriftgr÷▀e (H÷he)
SaveDC(dc);
SelectFont(dc,D->gdi.fText);
SetBkMode(dc,TRANSPARENT);
SetTextColor(dc,RGB(128,64,0)); // DDS-Frequenz links oben
f=Config.iFiltFreq*200+Config.iAFC;
TextOutW(dc,0,0,s,wnsprintfW(s,elemof(s),L"%d%c%02d",f/100,sDecimal[0],f%100));
GetTextExtentPoint32W(dc,L"Q",1,&fs);
TextOutW(dc,0,fs.cy,L"Hz",2);
SetTextAlign(dc,TA_RIGHT|TA_TOP); // Kreisdurchmesser-Amplitude rechts oben
r=D->lastr;
f=MulDiv(r,100,1<<IQSHIFT);
TextOutW(dc,sz.cx,0,s,wnsprintfW(s,elemof(s),L"%d%c%02d",f/100,sDecimal[0],f%100));
SetTextAlign(dc,TA_LEFT|TA_BOTTOM); // Amplitude (prozentual) links unten
TextOutW(dc,0,sz.cy,s,wnsprintfW(s,elemof(s),L"%d %%",MulDiv(a,100,r)));
SetTextAlign(dc,TA_RIGHT|TA_BOTTOM); // Phasenwinkel rechts unten
TextOutW(dc,sz.cx,sz.cy,s,wnsprintfW(s,elemof(s),L"%d░",ph));
SetTextAlign(dc,TA_RIGHT|TA_TOP);
SetTextColor(dc,RGB(192,192,192));
TextOutW(dc,(sz.cx>>1)-2,fs.cy>>1,L"Q",1);
TextOutW(dc,sz.cx-fs.cx,(sz.cy>>1)+2,L"I",1);
RestoreDC(dc,-1);
}
}
BitBlt(dis->hDC,dis->rcItem.left,dis->rcItem.top,sz.cx,sz.cy,dc,0,0,SRCCOPY);
SelectBitmap(dc,obm);
DeleteBitmap(bm);
DeleteDC(dc);
}break;
case WM_NOTIFY: {
LPPSHNOTIFY psn=(LPPSHNOTIFY)lParam;
switch (psn->hdr.code) {
case PSN_SETACTIVE: {
int fein;
D=LocalAlloc(LPTR,sizeof(dlg));
SetWindowLongPtr(Wnd,DWLP_USER,(LONG_PTR)D);
if (D) {
int i,lpy;
HDC dc=GetDC(0);
lpy=GetDeviceCaps(dc,LOGPIXELSY);
ReleaseDC(0,dc);
D->gdi.fText=CreateFont(-MulDiv(7,lpy,72),0,0,0,700,0,0,0,0,0,
OUT_TT_ONLY_PRECIS,PROOF_QUALITY,VARIABLE_PITCH|FF_SWISS,NULL);
for (i=0; i<HISTIQ; i++) {
BYTE grau=240-(HISTIQ-1)*7+i*7; // i=0: grau=23
COLORREF c=RGB(grau>>1,grau,grau>>1);
if (i==HISTIQ-1) c=RGB(224,255,224); // aktuell: extra hell
D->gdi.pVektor[i]=CreatePen(PS_SOLID,0,c);
}
D->gdi.pKreis=CreatePen(PS_SOLID,0,RGB(192,192,0));
D->gdi.pAchse=CreatePen(PS_SOLID,0,RGB(64,64,64));
}
SendDlgItemMessage(Wnd,33,UDM_SETRANGE32,10,Config.iSampleRate*500);
SendDlgItemMessage(Wnd,33,UDM_SETPOS32,0,FiltFreqHz(&fein));
KillTimer(Wnd,32);
SendDlgItemMessage(Wnd,34,TBM_SETPOS,TRUE,fein);
DemodIQ.hShowDemod=Wnd;
}break;
case PSN_KILLACTIVE: {
if (D) {
int i;
for (i=0; i<sizeof(D->gdi)/sizeof(HGDIOBJ); i++) DeleteObject(((HGDIOBJ*)&D->gdi)[i]);
SetWindowLongPtr(Wnd,DWLP_USER,(LONG_PTR)LocalFree(D));
}
DemodIQ.hShowDemod=0;
}break;
}
}break;
case WM_RECV_IQ: {
if (!DemodIQ.NoAGC) {
UpdateTrig();
SendDlgItemMessage(Wnd,12,TBM_SETPOS,TRUE,63-(Config.iDemodTrig>>2));
}
SendDlgItemMessage(Wnd,13,PBM_SETPOS,Logarithmize(DemodIQ.a>>IQSHIFT,100),0);
SendDlgItemMessage(Wnd,14,PBM_SETPOS,Logarithmize(DemodIQ.n,100),0);
AllocFFTSpace();
if (D) {
int i=D->iqidx;
D->lastiq[i].x=(int)wParam;
D->lastiq[i].y=(int)lParam;
D->lasta[i]=hypoti((int)wParam,(int)lParam);
D->iqidx=(i+1)&(HISTIQ-1);
InvalidateRect(GetDlgItem(Wnd,11),NULL,FALSE);
}
}break;
}
return FALSE;
}
Detected encoding: OEM (CP437) | 1
|
|