/********************************
* Projekt: Funkuhr DCF77 *
* Eigenschaftsseite „Diagnose“ *
* Anezige der empfangenen Bits *
* und Interpretation; Uhr *
********************************/
#include "Funkuhr.h"
typedef struct{
WORD ZeigRt; // Bits: Anzeigen rot wegen Fehler (IDs 16..31)
WORD ZeigGn; // Bits: Anzeigen grün wenn OK (IDs 16..31)
}DRAWINFO;
static DRAWINFO di;
#define TEXT_RT RGB(255,0,0) // Textfarbe-Rot
#define TEXT_GN RGB(0,128,0) // Textfarbe-Grün
// wine BUG: Workaround: WM_SETTEXT an STATIC-Steuerelement löscht Text bei NULL-Zeiger nicht
#define NOTEXT T("")
static void SetBitsColor(HWND Wnd, BYTE i, BYTE farbe) {
WORD maske=1<<i;
bool Neuzeichnen=false;
switch (farbe) {
case 0: { // schwarz setzen
if ((di.ZeigRt|di.ZeigGn)&maske) Neuzeichnen=true;
di.ZeigRt&=~maske;
di.ZeigGn&=~maske;
}break;
case 1: { // rot setzen
if ((~di.ZeigRt|di.ZeigGn)&maske) Neuzeichnen=true;
di.ZeigRt|=maske;
di.ZeigGn&=~maske;
}break;
case 2: { // grün setzen
if ((di.ZeigRt|~di.ZeigGn)&maske) Neuzeichnen=true;
di.ZeigRt&=~maske;
di.ZeigGn|=maske;
}break;
}
if (Neuzeichnen) {
Wnd=GetDlgItem(Wnd,16+i);
if (Wnd) InvalidateRect(Wnd,NULL,TRUE);
}
}
static void ZeigeSekunde(HWND Wnd) {
TCHAR s[3];
if (Empfang.Luecke) wnsprintf(s,elemof(s),T("%02d"),Empfang.Sek);
else lstrcpy(s,T("--"));
SetEditText(Wnd,11,s);
}
// Prüft <data> und <okay> auf Endekennung in den unteren <bits> Bits.
// Endekennung = gelöschtes Bit sowohl in <data> UND <okay>
// Setzt <true> bei <*nichts> wenn Endekennung vorhanden
// Belässt <true> bei <*nichts> ohne weitere Prüfung (Verkettung)
// <nichts> darf nicht NULL sein!
static void PruefBits(UINT data, UINT okay, BYTE bits, bool*nichts) {
if (*nichts) return; // true bleibt true!
if (~(data|okay)&((1<<bits)-1)) *nichts=true; // Ende erkannt
}
// Wie oben, zusätzlich Ausgabe der Bits in <Wnd>=Dialogelement
static void ZeigeBits(HWND Wnd, UINT data, UINT okay, BYTE bits, bool*nichts) {
TCHAR s[16],*p=s;
if (!*nichts) {
if (GetWindowStyle(Wnd)&ES_MULTILINE) {
lstrcpy(p,T("\r\n\r\n")); p+=4; // etwa die vertikale Mitte
}
do {
if (!((data|okay)&1)) {
*nichts=true;
break; // Ende der Bitkette
}
*p++=okay&1?data&1?'1':'0':'F';
data>>=1;
okay>>=1;
}while (--bits);
}
*p=0;
SetEditText(Wnd,(UINT)-1,s);
}
// PruefXxx-Routinen: liefern TRUE wenn OK, setzen ggf. Kommentar
// Liefern Anzahl zu prüfender Paritätsbits (>1)
// Liefern "unbewertbar" mit Kode 0xFF (nur Wetterdaten)
static BYTE PruefBit0(HWND Wnd, BYTE data) {
return data^1;
}
static BYTE PruefWetter(HWND Wnd, BYTE data) {
BYTE ret=0xFF;
TCHAR s[64];
int alarm;
DWORD sty;
s[0]=0; // Text löschen
alarm=AlarmDek(Config.MinuteZurueck);
if (alarm>=0) {
TCHAR t[64];
LoadString(ghInstance,15,t,elemof(t)); //"Katastrophenwarnung Region %d Kreis %d!"
wnsprintf(s,elemof(s),t,alarm&7,alarm>>3);
ret=1;
}else if (Decrypt) {
BYTE cipher[10];
DWORD idx;
if (BuildCipher(Config.MinuteZurueck,cipher,&idx)) {
long result=Decrypt(cipher);
TCHAR t[64]; // "Region %d %s %d: 0x%X" "Tag" "Nacht"
DWORD d=IndexToRegion(idx%480);
LoadString(ghInstance,14,t,elemof(t));
wnsprintf(s,elemof(s),t,
LOBYTE(HIWORD(d)),GetStr(t,(d&1)+1),HIBYTE(HIWORD(d))+1,result);
ret = result>=0 ? TRUE : FALSE; // bei CRC-Fehler rot machen, sonst grün
}
}
Wnd=GetDlgItem(Wnd,64); // zeigt "früher Reserveantenne" linksbündig
sty=GetWindowStyle(Wnd);
if (s[0]) {
if (!(sty&SS_RIGHT)) SetWindowLong(Wnd,GWL_STYLE,sty|SS_RIGHT); // fortan rechtsbündig
SetWindowText(Wnd,s);
}else if (sty&SS_RIGHT) SetWindowText(Wnd,s); // löschen (Ursprungstext nicht wiederherstellen)
return ret;
}
static BYTE PruefMEZ(HWND Wnd, BYTE data) {
TCHAR s[32],*p=s;
if (!((data^(data>>1))&2)) return FALSE;
if (data&1) {
p+=LoadString(ghInstance,3,p,elemof(s)); // Umstellung
*p++=' ';
}
if (data&2) p+=LoadString(ghInstance,4,p,elemof(s)-(int)(p-s));// Sommerzeit
else p+=LoadString(ghInstance,5,p,elemof(s)-(int)(p-s)); // Normalzeit
SetDlgItemText(Wnd,51,s);
return TRUE;
}
static BYTE PruefStartbit(HWND Wnd, BYTE data) {
return data;
}
static BYTE PruefMinute(HWND Wnd, BYTE data) {
BYTE m=GetBCD(data,0,59);
TCHAR s[4];
if (m==0xFF) return FALSE;
wnsprintf(s,elemof(s),T("%02u"),m);
return (BYTE)SetDlgItemText(Wnd,54,s);
}
static BYTE PruefMinutePar(HWND Wnd, BYTE data) {
return 8;
}
static BYTE PruefStunde(HWND Wnd, BYTE data) {
BYTE m=GetBCD(data,0,23);
if (m==0xFF) return FALSE;
return (BYTE)SetDlgItemInt(Wnd,56,m,FALSE);
}
static BYTE PruefStundePar(HWND Wnd, BYTE data) {
return 7;
}
static TCHAR TagFormat[4]; // "%u.", aber nicht alle Sprachen verwenden den Punkt
static BYTE PruefTag(HWND Wnd, BYTE data) {
BYTE m=GetBCD(data,1,31);
if (m==0xFF) return FALSE;
return (BYTE)wndSetText(GetDlgItem(Wnd,58),TagFormat,m);
}
static BYTE PruefWochentag(HWND Wnd, BYTE data) {
BYTE m=GetBCD(data,1,7);
TCHAR s[32];
SYSTEMTIME t;
if (m==0xFF) return FALSE;
t.wDay=m; // 1 = "Montag" usw.
t.wMonth=5; // Mai 2006 beginnt am Montag: Bingo!
t.wYear=2006;
t.wDayOfWeek=0;// Wurst! Hauptsache gültig.
GetDateFormat(LOCALE_USER_DEFAULT,0,&t,T("dddd"),s,elemof(s));
return (BYTE)SetDlgItemText(Wnd,59,s);
}
static BYTE PruefMonat(HWND Wnd, BYTE data) {
BYTE m=GetBCD(data,1,12);
TCHAR s[32];
SYSTEMTIME t;
if (m==0xFF) return FALSE;
t.wDay=1;
t.wMonth=m;
t.wYear=2006; // Wurst!
t.wDayOfWeek=0;// Wurst!
GetDateFormat(LOCALE_USER_DEFAULT,0,&t,T("MMMM"),s,elemof(s));
return (BYTE)SetDlgItemText(Wnd,60,s);
}
static BYTE PruefJahr(HWND Wnd, BYTE data) {
BYTE m=GetBCD(data,0,99);
if (m==0xFF) return FALSE;
SetDlgItemInt(Wnd,61,2000+m,FALSE); // Der Jahr-2100-Bug lauert :-)
return TRUE; // (erlebe ich nicht, und ob's da noch DCF77 und Windows gibt?)
}
static BYTE PruefDatumPar(HWND Wnd, BYTE data) {
return 23;
}
#define NUMWND 15 // Anzahl Anzeigefenster
// Uhr-Daten als Binärkette und deren Interpretation ausgeben
#pragma warning(disable:4700) // <bitsbefore> ohne Initialisierung ist OK
static void ZeigeUhrData(HWND Wnd, bool Alles) {
static const BYTE BitsPerWnd[NUMWND]={1,14,1,3,1,1,7,1,6,1,6,3,5,8,1};
static BYTE(*const PruefPerWnd[NUMWND])(HWND,BYTE)={
PruefBit0, PruefWetter, NULL, PruefMEZ,
NULL, PruefStartbit, PruefMinute, PruefMinutePar,
PruefStunde, PruefStundePar, PruefTag, PruefWochentag,
PruefMonat, PruefJahr, PruefDatumPar};
BYTE i,BitsAvail,Anzahl;
bool nichts; // Merker: Keine gültigen Bits
ULONGLONG data,okay; // Schiebe-Datenregister
DWORD bitsbefore; // Bitspeicher für Paritätsprüfung
if (Config.MinuteZurueck && !Alles) return;
// Empfangsdaten lesen
// EnterCritSec
i=Empfang.Index-Config.MinuteZurueck;
if (i>=MINU) i+=MINU; // Index auf zurückliegendes Telegramm
data=Empfang.Data[i];
okay=Empfang.Okay[i];
BitsAvail=Empfang.Sek+1;// nur wichtig wenn MinuteZurueck==0
Anzahl=Empfang.Anzahl;
// LeaveCritSec
if (Config.MinuteZurueck) BitsAvail=59;
// Bits und Interpretation ausgeben
nichts=false;
if (Config.MinuteZurueck>Anzahl) nichts=true; // Anzeigen löschen lassen
for (i=0; i<elemof(BitsPerWnd); i++) {
BYTE bits=BitsPerWnd[i];
BYTE m=(BYTE)((1<<min(bits,BitsAvail))-1); // Maske
BYTE d,f; // Wetter-Daten (14bit) ohne Prüfung, BYTE reicht
d=(BYTE)data&m; // Daten-Byte
f=~(BYTE)okay&m; // Fehler-Byte
bitsbefore<<=bits;
bitsbefore|=d; // Reihenfolge für Parität unerheblich!
if (Alles || BitsAvail<=bits) {
BYTE ok=FALSE;
ZeigeBits(GetDlgItem(Wnd,16+i),(UINT)data,(UINT)okay,bits,&nichts);
if (BitsAvail>=bits // Bits vollständig für's Fenster?
&& PruefPerWnd[i]) { // Prüfroutine vorhanden?
if (!f) {
ok=PruefPerWnd[i](Wnd,d); // <d> prüfen
if (ok==0xFF) goto unk; // schwarz lassen / setzen
if (ok>1 // hier: Anzahl Paritätsbits
&& CountLsbBits(bitsbefore,ok)&1) ok=FALSE; // muss gerade sein
}
SetBitsColor(Wnd,i,(BYTE)(ok?2:1)); // grün (OK) oder rot (Fehler)
}else unk: SetBitsColor(Wnd,i,(BYTE)(f?1:0));// schwarz (k.A.) oder rot (Fehlimpuls)
if (i==1) {
HWND w=GetDlgItem(Wnd,64);
if (BitsAvail<bits && GetWindowStyle(w)&SS_RIGHT) SetWindowText(w,NOTEXT);
}else{
if (!ok) SetDlgItemText(Wnd,48+i,NOTEXT); // Beschreibungstext löschen
}
}else{
PruefBits((UINT)data,(UINT)okay,bits,&nichts);
}
if (bits>BitsAvail) BitsAvail=0; else BitsAvail-=bits;
data>>=bits;
okay>>=bits;
}
}
#pragma warning(default:4700)
INT_PTR CALLBACK DiagnoseDlgProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
DefHelpProc(Wnd,Msg,lParam,106);
if (!*TagFormat) GetDlgItemText(Wnd,58,TagFormat,elemof(TagFormat));
switch (Msg) {
case WM_INITDIALOG: {
int i;
AttachUpDown(Wnd,10,12,-MINU,0,-Config.MinuteZurueck);
for (i=16; i<31; i++) {
SendDlgItemMessage(Wnd,i,WM_SETFONT,0,0); // fette Schrift fester Breite
}
// SendMessage(Wnd,0x31A/*WM_THEMECHANGED*/,0,0);
}return TRUE;
case WM_NOTIFY: {
LPPSHNOTIFY psn=(LPPSHNOTIFY)lParam;
switch (psn->hdr.code) {
case PSN_SETACTIVE: {
ZeigeSekunde(Wnd);
ZeigeUhrData(Wnd,true);
}break;
}
}break;
case WM_FUNKRECV: switch ((BYTE)wParam) {
case 0:
case 2: { // Sekundenbeginn: Zähler mitlaufen lassen
ZeigeSekunde(Wnd);
}break;
case 1: { // Impulsende: Bit eintragen
ZeigeUhrData(Wnd,Empfang.Sek?false:true);
}break;
}break;
case WM_COMMAND: switch ((DWORD)wParam) {
case MAKELONG(10,EN_CHANGE): {
int i;
if (GetUpDownInt(Wnd,12,&i)) {
Config.MinuteZurueck=(BYTE)-i; // i ist negativ
ZeigeUhrData(Wnd,true);
}
}
}break;
case WM_CTLCOLORSTATIC: {
int id=GetDlgCtrlID((HWND)lParam)-16;
if ((unsigned)id<16) {
WORD maske=1<<id;
LRESULT br=DefWindowProc(Wnd,Msg,wParam,lParam);
if ((di.ZeigRt|di.ZeigGn)&maske) { // Farbänderung
SetTextColor((HDC)wParam,di.ZeigRt&maske?TEXT_RT:TEXT_GN);
} // IMMER Hintergrund setzen (für konsistente Teletubbie-Optik)
SetBkMode((HDC)wParam,TRANSPARENT);
//SetBkColor((HDC)wParam,GetSysColor(COLOR_3DFACE)); // unter W2K erf.
return (BOOL)br;
}
}break;
}
return FALSE;
}
Vorgefundene Kodierung: UTF-8 | 0
|