Quelltext /~heha/hs/Funkuhr.zip/src/DlgDiagnose.c

/********************************
 * 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-80