Quelltext /~heha/hs/Funkuhr.zip/src/Funkuhr.h

/************************************************
 * DCF77-Funkuhr-Empfänger über serielles Port	*
 * oder auch Parallelport (via inpout32.dll)	*
 * sowie viele andere Eingabemöglichkeiten	*
 * haftmann#software, Juni 2007 ~ Juni 2013	*
 ************************************************/

#define _WIN32_IE 0x0501	// Tray-Icon mit Ballon-Hilfe
#define _WIN32_WINNT 0x0500	// 0x0501: Problem mit zu neuem SDK und XP: Fehlende ToolTips unter 9x/2k!
#define NOATOM
#define NOCLIPBOARD
#define NOCRYPT
#define NOGDICAPMASKS
#define NOIME		// kein Japanisch <ime.h>
#define NOMCX		// kein Modem-Kram <mcx.h>
#define NOMETAFILE
#define NOOPENFILE
#define NOPROFILER
#define NOSOUND
#define NOSYSCOMMANDS
#define NOTEXTMETRIC
#define NOWH
#define WIN32_LEAN_AND_MEAN	// schneller compilieren
#include <windows.h>
#include <windowsx.h>
#include <shellapi.h>	// notwendig wegen ...
#include <mmsystem.h>	// ... WIN32_LEAN_AND_MEAN
#include <shlwapi.h>
#include <commctrl.h>
#include <setupapi.h>
#include <htmlhelp.h>
#include <hidsdi.h>
#include <hidpi.h>
// meine Standard-Definitionen
#define elemof(x) (sizeof(x)/sizeof((x)[0]))
#define T(x) TEXT(x)
#ifndef __cplusplus
typedef enum {false,true} bool;
#endif//__cplusplus
#define nobreak

#ifdef WIN95
# undef  StrCatBuff
# define StrCatBuff(d,s,l) lstrcat(d,s)
// IE<5.0 shlwapi enhält kein längenbegrenztes wsprintf!
# undef  wvnsprintf
# define wvnsprintf(d,l,t,a) wvsprintf(d,t,a)
# define CancelIo(h)
# define FlashWindowEx(p) FlashWindow((p)->hwnd,(p)->dwFlags);
# define TrackMouseEvent(p)
#endif

#define PI	3.14159265358979323846
#define LN10	2.30258509299404568402
#define LOG2E	1.44269504088896340736
#define PI180	(PI/180)
//#ifndef INT_MIN
//# define INT_MIN	(-2147483647 - 1)
//# define INT_MAX	2147483647
//#endif

typedef struct{
 short left,top,right,bottom;
}RECTS;

typedef union {		// Alles was irgendwie 64 Bits sind
 ULONGLONG ull;
 LONGLONG ll;
 FILETIME ft;
 LARGE_INTEGER li;
 DWORD dw[2];
 WORD w[4];
 BYTE b[8];
 div_t d;
 struct{DWORD Tag,Nacht;};
 struct{DWORD Lo,Hi;};
 struct{int x,y;};
 RECTS rc;
 POINT pt;
 SIZE sz;
}U64;

/*** Funkuhr.c ***/
extern HINSTANCE ghThisInst;	// diese .EXE-Datei
extern HINSTANCE ghInstance;	// ggf. Benutzer-Ressourcen
extern NOTIFYICONDATA nid;
#define MainWnd (nid.hWnd)
extern HWND PropWnd;
extern long (WINAPI*Decrypt)(BYTE*);
extern DWORD Cache24[480];
extern TCHAR sDecimal[2];	// Dezimaltrennzeichen (Punkt oder Komma)
extern TCHAR sTime[2];		// Uhrzeit-Trennzeichen (typ. Doppelpunkt)
extern TCHAR sGrad[4];		// Grad-Zeichen (typ. "°", ASCII "grd")
extern TCHAR HelpName[];	// Hilfe-Dateiname (*.hlp, nicht *.chm)
extern TCHAR CacheName[];	// Cache24-Datei (speichert Wetterdaten parallel zur Registrierung)
extern BYTE CmdLineOpt;
extern bool iMeasure;		// 0 = metrisch, 1 = zöllig
extern bool ChmHelp;		// 0 = keine oder RTF, 1 = CHM aka HTML
extern char TryReOpen;		// 2 nach Neustart und WM_POWER (= 3 Versuche), 0 nach Erfolg
extern DWORD WinVer;		// GetVersion()
bool SystemTimeToString(const SYSTEMTIME*st,UINT DateFormat,UINT TimeFormat,LPTSTR p,int len);
bool FileTimeToString(const FILETIME*pft,LPTSTR p,int len,UINT DateFormat, UINT TimeFormat, bool ToLocalTime);
U64 GetSystemFileTime(bool bLocal);	// aktuelle UTC oder Lokalzeit holen, als 64-Bit-Zeitstempel
void StartWecker(void);
void ComputerUhrStellen(void);
typedef enum {CONFIG=1,CACHE24=2,ALL=3} WHATSAVE;
void SaveConf(HKEY root, WHATSAVE what);
void SaveConfig(WHATSAVE what);
bool AnimYes(void);		// true wenn Icon animiert und/oder Sound ausgegeben werden soll
void AnimateTrayIcon(void);
void ShowProperties(void);	// muss neu erzeugt werden, wenn sich Parent-Zuordnung ändert
void SetTrayTip(void);
void MakeIcons(void);
void TrayIconVisChanged(void);
void PropRespawn(void);
void PropInsDelSheet(int iTemplate, int iPos);	// iTemplate<0 löscht Seite Nr. iPos
void PropAppendSysMenu(void);
void LocateFile(PTSTR buf,PCTSTR name);	// Dateiname an verschiedenen Stellen suchen
HINSTANCE MyLoadLibrary(PCTSTR);	// versucht die DLL im übergeordneten Verzeichnis zu finden
void DefHelpProc(HWND Wnd, UINT Msg, LPARAM lParam, UINT id);
#ifdef _M_AMD64
#define HOUR2FILETIME(x) ((x)*60*60*10000000LL)
#define DAY2FILETIME(x)	 ((x)*24*60*60*10000000LL)
#else
// ohne ULONGLONG-Multiplikation auskommen:
#define HOUR2FILETIME(x) (UInt32x32To64((DWORD)(x),0x10C388D)<<11)
#define DAY2FILETIME(x)	 ((__int64)((DWORD)(x)*0x324A9A7)<<14)	// x max. 4
#endif

// Alles persistente zum Schreiben "in einem Rutsch"
typedef struct {
// Fenster
 POINTS WinPos;
// Hardware
 BYTE Where;		// 0(Seriell), 1(Parallel), 2(Soundkarte), 3(Joystick), 4(UsbPrn), 5(Vorlauf)
 BYTE SerialNo;		// 0..255 für COM1..COM256
 BYTE SerialLineIn;	// 0=..., 4=RxD
 BYTE SerialLineOut;	// 0=..., 2=TxD (Stromversorgung)
 WORD ParallelAddr;	// Basisadresse!
 BYTE ParallelLineIn;	// Bit 0..2: Bitnummer, Bit 3-7: Adress-Additiv
 BYTE ParallelLineOut;	// Bit 0..2: Bitnummer, Bit 3-7: Adress-Additiv
// Empfang
 BYTE Piep;		// 0=aus, 1..10=ein, Lautstärke
 BYTE Minuten;		// History-Tiefe (Anzahl »Ringe«, 1..10 [=MINU])
// Histogramm
 BYTE ZuKurz;		// Unterlauf-Wert [ms] (50 ms)
 BYTE Trenn;		// Entscheider-Zeitwert [ms] (170 ms)
 BYTE ZuLang;		// Überlauf-Wert [2ms] (270 ms)
 BYTE MaxJitter;	// erlaubte Schwankung des Sekundenimpulses (100 ms, nicht benutzt)
// Diagnose
 BYTE MinuteZurueck;	// Anzeige 0=aktuelle bzw. 1..10 = zurückliegende Minute
// Wetter
 char Region;		// Vorhersageregion 0..89 (90 = eigene Position)
// Stellen
 BYTE Checkmarks;	// Bit 0 = Uhr stellen beim Programmstart
			// Bit 1 = alle xx Stunden
			// Bit 2 = wenn Uhr verstellt
			// Bit 3 = Datum stellen
			// Bit 4 = MsgBox bei über xx Sekunden
			// Bit 5 = SYSTEMTIME stellen (sonst LOCALTIME)
			// Bit 6 = frei
			// Bit 7 = Eigenschaftsfenster vor primärer Wetterkarte (Owner)
 BYTE AfterHour;	// Stunden: 24, 0 = ständig stellen
 BYTE MsgAtDiff;	// Sekunden: 2, 0 = immer informieren
 BYTE LastActionCode;	// Text für letzte Aktion (String-ID)
 DWORD LastActionTime;	// Zeit letzte Aktion (als FAT-Zeit)
 DWORD LastSet;		// Uhr zuletzt erfolgreich gestellt
// TrayIcon
 BYTE TrayIconVis;	// Sichtbarkeit Tray-Icon, 0=immer, 1=bei Empfang, 2=nie
 BYTE TrayIconBlink;	// soll's blinken?
 BYTE TrayIconAus;	// Empfänger ausschalten nach Empfang?
			// 0 = ausschalten
			// 1 = erst aus wenn OK
			// 2 = immer ein, aber nicht blinken/piepsen bei „stillem Empfang“
			// 3 = immer ein und immer blinken+piepsen
 BYTE ActivePropSheet;	// Seite im Eigenschaftsfenster (0..9)
// „Geheime“ Einstellungen ohne Dialogelemente
 BYTE ToNoSignal;	// TimeOut-Wert für Meldung „Kein Signal“ in s (Standard: 5)
 BYTE ToRepNoSig;	// TimeOut-Wert für Wiederholungsmeldung „Kein Signal“ in s (Standard: 120)
 BYTE ToBalloon;	// TimeOut-Wert für Meldungen in s (einige werden in Vielfachen angezeigt; Standard: 10)
 BYTE ToSilence;	// TimeOut-Wert für Übergang in stillen Empfangsmodus in min (Standard: 15)
// Wetter
 BYTE cbSort;		// Anzeige- und Sortierkriterium (Low- und High-Nibble, Standard: 0)
			// Bit 0 = Stadt (statt Region)
			// Bit 1 = zusätzlich Nummer
			// Bit 2 = zusätzlich Geokoordinaten
			// Bit 3 = alternative Wettersymbole, TODO
			// Bit 4 = Nach Land vorsortieren
			// Bit 6:5 = nicht(0), alphabetisch(1), W->O(2), N->S(3) sortieren
			// Bit 7 = umgekehrt sortieren
// Karte
 BYTE kShow;		// Sichtbarkeit des Karten-Fensters (Standard: 0x51)
			// Bit 1:0 SW_HIDE(0), SW_NORMAL(1), SW_SHOWMINIMIZED(2), SW_SHOWMAXIMIZED(3)
			// Bit 2 = horizontaler Rollbalken
			// Bit 3 = vertikaler Rollbalken
			// Bit 4 = Menüzeile
			// Bit 5 = Toolbar (** zwingt Karte in Kindfenster wenn Bit 3:2 gesetzt)
			// Bit 6 = Statuszeile (**)
			// Bit 7 = Tooltips
 char kMini;		// Sichtbarkeit und Anordnung des Miniaturfensters (Standard: 0)
			// Bit 1:0 = unsichtbar(0), gleitend(1), außen angedockt(2), innen angedockt(3)
			// Bit 3:2 = LinksOben(0), RechtsOben(1), LinksUnten(2), RechtsUnten(3)
			// Bit 4   = Nur bei Bedarf
			// Bit 7:5 = Relative Verkleinerung zum Bildschirm, etwa logarithmisch gestuft
			//	-4 = 1/4	-3 = 1/6	-2 = 1/8	-1 = 1/12
			//	±0 = 1/16(normal)1 = 1/24	+2 = 1/32	+3 = 1/48
			// FIXME: Größe schließt/öffnet Fenster, Scrollrad irreführend
 BYTE kVis;		// Sichtbare Items der Kartendarstellung (Reihenfolge ist fest, Standard: 0x3F)
			// Bit 0 = Bitmap, von extern geladen
			// Bit 1 = Küstenlinien (TODO)
			// Bit 2 = Ländergrenzen (TODO)
			// Bit 3 = Land eingefärbt (TODO, mit Ländergrenzen verschieden)
			// Bit 4 = Gradnetz
			// Bit 5 = Vorhersage-Polygone
			// Bit 6 = Polygon-Nummern
			// Bit 7 = Städte-Namen
 RECTS kPos;		// Position des Kartenfensters, in Bildschirmkoordinaten (Standard: 0)
 POINTS kScrl;		// Scroll-Position, bezogen auf Maßstab 1:1 (Standard: 0, Routine zieht zu gültigem Wert)
 char kScale;		// Karten-Skalierungs-Exponent (Standard: 0 = 1:1)
			// Bit 3:0 = Feinstufung 2 ^ 1/16 = 1,0442738 (mit Shift-Taste), davon:
			//	     Bit 3:2 = Sub-Index, normale Scrollrad-Operation
			// Bit 7:4 = ganze Binärstufung, 1/256 (2^-8) .. 128 (2^7), eingegrenzt auf 1/16 .. 16
 BYTE kAutoScale;	// Automatische Skalierung (Standard: 0x50)
			// Bit 0 = auf ganze Fensterbreite
			// Bit 1 = auf ganze Fensterlänge (zusammen: Minimum beider)
			// Bit 2 = Fenstergröße automatisch verändern
			// Bit 3 = über Monitorgrenzen hinweg
			// Bit 5:4 = Schriftgröße (6-8-10-12 Punkt)
			// Bit 7:6 = Wettersymbolgröße (24-32-48-64 Pixel)
 BYTE kWetter;		// sichtbare Wetter-Symbole (Standard: 1) (**NW = Niederschlagswahrscheinlichkeit)
			// Bit 3:0 = nichts(0), Tag(1), TagTemp(2), Nacht(3), NachtTemp(4), Wind(5), NW**(6), Gefahren(7)
			// Bit 5:4 = heute(0), morgen(1), übermorgen(2), Tag4(3)
			// Bit 6 = Pieps und blinkender Fenstertitel bei Aktualisierung
			// Bit 7 = Hot-Tracking der 4-Tages-Vorhersage im DlgWetter je nach Region
// Weitere Konfigurationswerte
 char uRegion;		// Benutzer-Region (vor allem falls außerhalb einer der 90 Vorhersageregionen)
			// 0..89 = gefundene oder manuell gesetzte Region
			// -1 wenn kein uPos
 POINTS uPos;		// Benutzer-Position ("Fähnchen") in Mercator-Koordinaten
			// u.a. für die Berechnung von Sonnen- und Mond-Auf- und Untergang
// Hardware II
 char iSoundCard;	// Nummer der Soundkarte, -1 = WAVE_MAPPER
 BYTE iSampleRate;	// Abtastrate (8,11.025,16,22.05,32,44.1,48,96,100,192,200,250)
 WORD iFiltFreq;	// Einstellbare Filterfrequenz in 2 Hz (im NF-Bereich, falls umgesetzt)
 char iAFC;		// AFC-Frequenzkorrektur in 0,01 Hz, -126..+126
 BYTE iDemodTrig;	// Demodulator-Steuerbits
			// Bit 0 = AFC (sonst umlaufender oder umherspringender Zeiger)
			// Bit 1 = Phasendetektor (sonst Amplitudendetektor), erfordert AFC
			// Bit 7:2 = AM-Triggerpegel (zum schnelleren Einpegeln beim Programmstart)
 BYTE iJoystick;	// Nummer des Joysticks
 BYTE iJoyButton;	// Bit 4:0 = Nummer des Joystick-Knopfes
			// Bit 7:5 = Nummer der Achse, die die Zeit in ms liefert, 0 = keine
 BYTE iUsbPrn;		// Nummer des USB-Paralleldrucker-Konverters
 BYTE iUsbInput;	// Verwendeter Eingang (Bitnummer, also 3..5)
 BYTE iUsbHid;		// Nummer des Vorlaufempfängers
 BYTE pedantic;		// steuert Fehlerprüfung beim Auswerten der Alarm- und Wetterinformation
			// Bit 0 = prüfe Empfang.Okay[minute+0], Länge je nach Bit 3
			// Bit 1 = prüfe Empfang.Okay[minute+1], Länge je nach Bit 4
			// Bit 2 = prüfe Empfang.Okay[minute+2], Länge 15 Bits
			// Bit 3 = prüfe volle Empfangslänge bei minute+0, sonst nur 15 Bits
			// Bit 4 = prüfe volle Empfangslänge bei minute+1, sonst 29 Bits (*)
			// Bit 5 = prüfe Uhrzeit bei minute+0
			// Bit 6 = prüfe vollständige Uhrzeit bei minute+1, sonst nur Minutenangabe
			//	   Bit 5 und Bit 6 gemeinsam prüft auf 1-Minute-Differenz
			// Bit 7 = erlaube Fehlerkorrektur
			// (*) Bei Wetter-Dekodierung wird Bit 4 und 6 als gesetzt angenommen
			// Volle Empfangslänge = 59 Bits;
			// 58 Bits genügen wenn Schaltsekunde-Bit gesetzt UND Minute == 0 ist
 POINTS kMiniPos;	// Position des freien Miniaturfensters, in Pixel relativ zu kPos
}TConfig;

typedef union{		// Alle Prozessoren haben kürzeren Kode beim Zugriff auf Byte-Werte
 SYSTEMTIME st;
 struct{
  BYTE bYear,rsv0;
  BYTE bMonth,rsv1;
  BYTE bDayOfWeek,rsv2;
  BYTE bDay,rsv3;
  BYTE bHour,rsv4;
  BYTE bMinute,rsv5;
  BYTE bSecond,rsv6;
  WORD wMilliseconds; 
 };
}MYSYSTEMTIME;

#define MINU 10		// Anzahl Minuten in Rückverfolgung
// Alle Lesedaten zusammengefasst
typedef struct{		// R/W/- = Asynchroner UhrThread-Zugriff (dort ist kein Schreibzugriff)
 bool Signal;		// - <true> wenn Trägerabsenkung
 bool Luecke;		// - <true> wenn "fehlendes" Bit detektiert wurde, dann "Sek" gültig
 bool Invers;		// R Invertierung entdeckt
 bool IntrOK;		// R DSR-Wechsel-"Interrupt" klappt (kein 10-ms-Timer)
 bool SelfTimeChange;	// - WM_TIMECHANGE von eigenem Programm, oder von außen?
 BYTE Ein;		// R Thread-Zustand:
			//   0 = Thread AUS
			//   1 = Thread EIN, Empfang TimeOut (> 15 Minuten)
			//   2 = Thread EIN, Empfang nach OK (kein Stellen der Uhr mehr)
			//   3 = Thread EIN, erste 15 Minuten
 bool DauerPiep;	// R <true> bei Dauerpieps (Maus zieht an TrackBar)
 MYSYSTEMTIME Dek;	// - Dekodiertes Datum/Uhrzeit (Icon-Anzeige und Tooltip) - ohne gepatchtes Datum
 BYTE Index;		// - Aktuelles Telegramm "in Füllung"
 BYTE Anzahl;		// - Gefüllte Telegramme (mit "Wrap-Around"), das aktuelle nur bis "Sek"
 BYTE LastOK;		// - Anzahl zusammenhängend OK empfangener Minuten (noch ohne Test der Aufeinanderfolge)
 BYTE Sek;		// - Impuls-Index
 ULONGLONG Data[MINU];	// - regulär 59 Bits, mit Okay=0: Data=0: Ende, Data=1: Fehler
 ULONGLONG Okay[MINU];	// - 0: Ende oder Fehler, 1: Datenbit OK
 WORD Histo[50];	// - Impulslängen in 10-ms-Schritten, letzter Index für >=490 ms
 U64 ZeitAlt;		// - Computer-Uhr VOR dem Stellen
 U64 ZeitNeu;		// - Stell-Zeit für Computer-Uhr (zur Differenz-Ausgabe) - ggf. mit gepatchtem Datum
}TEmpfang;

typedef struct{		// in (mehreren) Eigenschaftsseiten verwendete GDI-Objekte
 HBRUSH brKurz;		// Kurzer Impuls: dunkelgelb
 HBRUSH brLang;		// Langer Impuls: hellgelb
 HBRUSH brFehl;		// Fehlerhafter Impuls: rot
 HPEN   peDivi;		// Teilerstrich (im Histogramm): blau, gepunktet
 HPEN   peXor;		// Stift für R2_XORPEN-Operationen (schwarz auf grau)
 HFONT  fnQuer;		// große Schrift (Diagramm-Hinterlegung)
 HFONT	fnKursiv;	// Kursivschrift (für Erläuterungen im Hardware-Dialog)
 HFONT  fnFett;		// Fettschrift (für farbliche Hervorhebungen)
 HPEN	peZgr[2];	// Stift für Zeiger im Icon (3 Pixel dick) (Index 1 für hellen Hintergrund)
 HPEN	peBlau[2];	// blauer Stift Breite 0 (1 Pixel)
 HBRUSH	brBlau[2];	// blauer Pinsel (für Dreieck = »Sendemast«)
}TGdiObj;		// alles - außer die Wetterdarstellung

extern TConfig Config;
extern TEmpfang Empfang;
extern TGdiObj GdiObj;

#define WM_FUNKRECV	(WM_USER+201)
	// wParam=0: Impuls-Start
	// wParam=1: Impuls-Ende, lParam=Index der Histogramm-Einfügung (0xFF=Signalinversion)
	// wParam=2: Simulation 59. Sekunde (konzeptionell komplett fragwürdig!)
	// wParam=10:Computer-Uhr gestellt
	// wParam=11:Weckzeit geändert
	// wParam=12:Empfangszustand (Config.Ein) geändert, lParam=alter Zustand
	// wParam=13:LastActionCode geändert
	// wParam=14:Veränderliche HID-Daten: Akkuspannung und Chiptemperatur verfügbar, lParam=report (Gefahr!?)
	// wParam=16:Neue entschlüsselte Wetterdaten, lParam = Cache24-Index
	// wParam=17:Tageswechsel (Lokalzeit)
	// wParam=18:Wechsel von Config.Region (Aktualisierung der Karten-Polygone auslösen), lParam=altes Config.Region
	// wParam=19:Wechsel von Config.uPos und/oder Config.uRegion, je nach lParam
	//		0: Setzen von Config.uPos und Config.uRegion (>=0)
	//		1: Setzen von Config.uRegion (>=0)
	//		2: Löschen der User-Position, also Config.uRegion=-1
#define WM_SetActivity	(WM_USER+204)	// wParam=0..3 für neue Aktivität
#define WM_MyPosStaat	(WM_USER+205)	// wParam=0, lParam=0, Ergebnis=-1..NUMSTAAT-1; nur an Kartenfenster zu senden!

/*** DCF77.c ***/
#define WM_RECV_IQ	(WM_USER+202)	// wParam=I, lParam=Q
#define WM_TryReOpen	(WM_USER+203)	// Worker-Thread bittet um seinen Neustart
#define IQSHIFT		14
typedef short fft_t;	// Datentyp für FFT: <short> oder <int> (ausprobieren!)
typedef struct {
 HWND hShowDemod;	// Ziel für PostMessage()
 DWORD nBlocks;		// Blockzähler (Annahme: dwBufferLength==dwBytesRecorded)
 bool NoAGC;		// Automatische Schaltschwellenanpassung deaktivieren (wird nicht gespeichert)
 BYTE lock;
 BYTE DoFFT;		// FFT durchführen (statt I/Q-Demodulation anzeigen), mit Countdown-Funktion
 BYTE FFT_LenShift;	// Anzahl der Spektrallinien
 fft_t*FFT_Data;	// I/Q-Spektrum (lineare Frequenzachse)
 int f;			// Frequenz des DDS-Generators, in 1/100 Hz
 int at;		// Triggerschwelle bei Amplitudendemodulation (positiv, gleitend, Tau ca. 5 s)
 int i,q,a,n;		// I/Q-Signalstärken, Amplitude (=hypoti(i,q)), Gesamtsignal(Rauschen)
			// i,q,a = um IQSHIFT linksgeschoben
}TDemodIQ;
extern TDemodIQ DemodIQ;
extern const GUID GUID_DEVINTERFACE_USBPRINT;
typedef struct{
 HANDLE hDev;		// Gerätetreiber-Kanal
 PHIDP_PREPARSED_DATA pd;//HID-...
 HIDP_CAPS caps;	// HID-...
}THid;
extern THid gHid;	// HID-Thread-Info
void FillHidRep4(HWND Wnd, const THid*Hid, PUCHAR report);
BYTE GetBCD(BYTE data, BYTE min, BYTE max);	// liefert 0xFF bei Fehler
BYTE CountLsbBits(ULONG l, BYTE bits);		// liefert Anzahl 1-Bits
bool DecodeTime(ULONGLONG ll, MYSYSTEMTIME*st);
void ClearHisto(void);
void OnTimerPulsAuswertung(void);
void OnTimerSek59(void);
void OnSignalChange(bool Signal, DWORD Timestamp);
void SetFiltFreq(int f);	// Sinustabelle des I/Q-Demodulators neu berechnen
int Logarithmize(int t, int max);// result = ln(t)*max/LN32K
int hypoti(int x, int y);	// Hypotenuse berechnen, Integer-Version
int hypot_lazy(int x, int y);	// Faule Hypotenusenabschätzung
void SetTrig(void);	// Config.iDemodTrig -> DemodIQ.at, AM-Schaltschwelle von Hand einstellen
void UpdateTrig(void);	// DemodIQ.at -> Config.iDemodTrig, AM-Schaltschwelle anzeigen
void zeroOverlapped(OVERLAPPED*o);	// Dateiposition ind Internal nullsetzen (alles außer hEvent)
int GetMaxReport(const HIDP_CAPS*caps);	// Maximale Reportpuffergröße erfragen
bool GetInputReport(HANDLE hDev, void*buf, int len, OVERLAPPED*o);
void AllocFFTSpace(void);
int FiltFreqHz(int*frac);	// Ganze Filterfrequenz sowie Feinverstellung (-50..+50)
bool StartEmpfang(void);
bool RestartEmpfang(void);
void EndeEmpfang(void);
void InfoPropSheet(WPARAM wParam, LPARAM lParam);
bool HidOpen(THid*);
void HidClose(THid*);

/*** Sprechblase.c ***/
BOOL RegisterSprechblase(void);
void Sprechblase(void);

/*** wutils.c ***/
extern TCHAR MBoxTitle[64];
void _fastcall InitStruct(LPVOID p, UINT len);
int vMBox(HWND Wnd, UINT id, UINT style, va_list arglist);
int MBox(HWND Wnd, UINT id, UINT style,...);
PTSTR GetStr(PTSTR start, int n);		// n-ten nullterminierten String liefern
#ifdef UNICODE
# define GetStrW GetStr
#else
PWSTR GetStrW(PWSTR start, int n);
#endif
BOOL wndSetText(HWND w, PCTSTR t, ...);		// Formatierten Fenstertext setzen
int StripAmpersand(PTSTR s);			// &-Zeichen entfernen, liefert String-Länge
int GenerateUniqueHotkey(HMENU hSubMenu, PTSTR buf, int len);	// etwas eindeutiges generieren
DWORD ClientToScreenS(HWND w, DWORD pos);	// ClientToScreen() mit short-Koordinaten
UINT GetCheckboxGroup(HWND Wnd, UINT u, UINT o);
void SetCheckboxGroup(HWND Wnd, UINT u, UINT o, UINT v);
void EnableDlgItem(HWND Wnd, UINT id, BOOL state);
void ShowDlgItem(HWND Wnd, UINT id, int state);
BOOL CheckMenuRadio(HMENU m, UINT id);
void SetCheckMenuGroup(HMENU m, UINT u, UINT o, UINT v);
UINT GetCheckMenuGroup(HMENU m, UINT u, UINT o);
void EnableMenuGroup(HMENU m, UINT u, UINT o, UINT state);
void SetEditText(HWND Wnd, UINT id, LPTSTR s);	// dabei Markierung beibehalten
HWND AttachUpDown(HWND Wnd, UINT id, UINT udid, int min, int max, int cur);
bool GetUpDownInt(HWND Wnd, UINT id, int *val);
bool GetUpDownByte(HWND Wnd, UINT id, BYTE *val);
div_t _fastcall mydiv(int,__int64);
#define udiv(z,n) mydiv(n,z)	// n muss positiv sein; liefert stets positiven Rest
#ifdef _M_IX86
__forceinline __int64 llrint(double f) {
 __int64 i;
 _asm	fld	f
 _asm	fistp	i
 return i;
}
#if _MSC_VER < 1400	// Visual C++ 6
__forceinline char _BitScanForward(DWORD*Index, DWORD v) {
 _asm	bsf	eax,v
 _asm	mov	ecx,Index	// ohne ECX einzusauen geht es hier nicht
 _asm	mov	[ecx],eax
 _asm	setnz	al
}
__forceinline char _BitScanReverse(DWORD*Index, DWORD v) {
 _asm	bsr	eax,v
 _asm	mov	ecx,Index
 _asm	mov	[ecx],eax
 _asm	setnz	al
}
__forceinline char _bittest(const void*p, DWORD bitnum) {
 _asm	mov	ecx,p
 _asm	mov	eax,bitnum
 _asm	bt	dword ptr [ecx],eax
 _asm	setc	al
}
__forceinline char _bittestandset(void*p, DWORD bitnum) {
 _asm	mov	ecx,p
 _asm	mov	eax,bitnum
 _asm	bts	dword ptr [ecx],eax
 _asm	setc	al
}
__forceinline char _bittestandclear(void*p, DWORD bitnum) {
 _asm	mov	ecx,p
 _asm	mov	eax,bitnum
 _asm	btr	dword ptr [ecx],eax
 _asm	setc	al
}
__forceinline char _bittestandcomplement(void*p, DWORD bitnum) {
 _asm	mov	ecx,p
 _asm	mov	eax,bitnum
 _asm	btc	dword ptr [ecx],eax
 _asm	setc	al
}
__forceinline void __stosd(DWORD*p, DWORD val, DWORD count) {
 _asm	mov	edi,p
 _asm	mov	eax,val
 _asm	mov	ecx,count
 _asm	rep stosd
}
__forceinline void __movsw(WORD*d, const WORD*s, DWORD count) {
 _asm	mov	edi,d
 _asm	mov	esi,s
 _asm	mov	ecx,count
 _asm	rep movsw
}
__forceinline void __movsd(DWORD*d, const DWORD*s, DWORD count) {
 _asm	mov	edi,d
 _asm	mov	esi,s
 _asm	mov	ecx,count
 _asm	rep movsd
}
#endif
#else
__int64 llrint(double f);
#endif
#define lrint(x) (int)llrint(x)
float hypotf(float,float);
POINT _fastcall sincos(int radius, int deg10);
int sinus(int radius, int sec);	// Lookuptabellen-Sinus (unnötig)
BOOL _stdcall Line(HDC dc, int x1, int y1, int x2, int y2);
void InitCritSec(void);
void InitBeep(BYTE negvol);
void StartBeep(void);
void StopBeep(void);
void DoneBeep(void);
typedef struct{
 HINSTANCE hLib;	// Libname = erster String
 FARPROC proc[];	// dynamisches Array aus Funktionszeigern; die Länge ergibt sich aus der Anzahl der
}dynaprocs;		// …nullterminierten Strings (doppel-null-terminiert)
bool _fastcall dynaload(dynaprocs*,const char*);	// liefert false wenn ein Einsprungpunkt nicht vorhanden
bool IsUserAdmin(void);	// wie es der Name sagt
void _fastcall bloat(int*dst, const char*src, int len);	// Byte-Array zu Integer-Array (typischerweise Punkte)
#ifdef UNICODE
#define MyLoadStringW(id,buf,len) LoadString(ghInstance,id,buf,len)
#else
int MyLoadStringW(UINT id, PWSTR buf, int len);
#endif
__int64 CalcArea(const POINT *p, int n, POINT *c);

#ifdef _DEBUG
void _cdecl dprintf(const char *s,...);
#define DbgPrintf(x) dprintf x
#define assert(x) if (!(x)) dprintf("%s:%d: assert failed: %s\n",__FILE__,__LINE__,#x)
#else
#define DbgPrintf(x)
#define assert(x) x
#endif

/*** mtDekoder ***/
int AlarmDek(BYTE MinuteZurueck);
// MJD480 = Modifiziertes Julianisches Datum = Tage seit 1.1.1601 00:00 * 480 (3 Minuten)
bool BuildCipher(BYTE MinuteZurueck, BYTE cipher[10], DWORD* MJD480);
int GetT3M(int index, int*j3m);
int GetAge(int index, int*j3m);
void SetCache24Entry(DWORD saveindex, DWORD result);
// Berechnet aus <idx> (0..479):
// LOBYTE(LOWORD(result)) = Tag(0) / Nacht(1)
// HIBYTE(LOWORD(result)) = Zeitraum (2 oder 4)
// LOBYTE(HIWORD(result)) = Vorhersageregion 0..89
// HIBYTE(HIWORD(result)) = Gültigkeitsbereich (0..3)
DWORD IndexToRegion(int idx);
int GetHeuteMJD(bool bLocalTime);	// sonst MESZ; Tage seit 1601-1-1-00:00
int Cache24Merge(const DWORD other[480]);

/*** allgemein ***/
#ifdef _M_AMD64
# define DWL_MSGRESULT DWLP_MSGRESULT
# define INPOUTDLL T("inpoutx64.dll")
#else
#undef UInt32x32To64
ULONGLONG _fastcall UInt32x32To64(DWORD x,DWORD y);
# define INPOUTDLL T("inpout32.dll")
#endif

/*** Karte.c ***/
#define NUMSTAAT 47		// Europäische Länder inklusive Zwergstaaten, ohne Kanalinseln
#define WM_FocusRegion	(WM_USER+202)	// (int)wParam = Region
extern const TCHAR KARTECLASSNAME[];
extern HWND hFirst;
void RegisterKarte(void);	// Fensterklasse registrieren
HWND Karte(void);		// Fenster zeigen (Knopfdruck)
// - wertet UMSCH aus, um ein weiteres Fenster zu öffnen
// - wertet STRG aus, um die JPG-Datei (statt GIF-Datei) zu laden
// Pixelkoordinaten steigen von West nach Ost und von Nord nach Süd
int GetCityX(BYTE index);	// Google-Maps-Karten-Pixel-Koordinaten
int GetCityY(BYTE index);	// (als Sortierkriterium ausreichend)
typedef struct{
 float X,Y;
}PointF;		// wie GDIplus
// Länge und Breite steigt von West nach Ost sowie von Süd nach Nord
PointF GetCityKoord(BYTE index);	// in Längen- und Breitengrad
// Gleitkommazahl in String — ohne sprintf() o.ä.
int FloatToStr(float v, int nk, PTSTR s, int len);

/*** DlgWetter.c ***/
extern const BYTE Flaggen[90];
extern const WORD Kennzeichen[NUMSTAAT];
extern const char Vierfarben[NUMSTAAT];
void bloatsym(POINT*d, const char*s, int l);

void SetCurRegion(HWND Wnd, int region); // Hot-Tracking-Region setzen
void CreateSymbGdiHandles(void);
void DeleteSymbGdiHandles(void);
void CalcMondalter(void);
int TagesName(int TagNr, TCHAR *buf, int len, HMENU hSubMenu);	// Tag = 0..3
void SetRectC(RECT*r,int cx,int cy,int ex,int ey);
void Measure(HDC dc, U64 v, BYTE typ, RECT*rc);		// Größe bestimmen
int GetForecast(int,U64[4]);
int SchwerwetterText(PTSTR s, int slen, bool nacht, U64 v, bool statusbar);
int MkTempStringW(DWORD v, PCWSTR fmt, PWSTR buf, int len);
void ptSymbolTag(HDC,U64);
void ptTempTag(HDC,U64);
void ptSymbolNacht(HDC,U64,int TagNr);
void ptTempNacht(HDC,U64);
void ptNSW(HDC,U64);
void ptWind(HDC,U64);
bool TagNachtWarnung(U64);
void ptWarnung(HDC,U64);

/*** Mondalter.c ***/
PointF geoloc;		// für Auf- und Untergangszeit, in Grad
int geotz;		// Zeitzone zur Berechnung von Auf- und Untergangszeiten, in Minuten, östlich = negativ
TIME_ZONE_INFORMATION geotzi;	// mit entsprechend umgerechneten Umschalt-Tagen
double Mondalter(double JDE);
bool AufUntergang(bool bSonne, double MJD, TCHAR*Auf, TCHAR*Unter);	// Zeiten in der Form "xx:xx\0"
// bSonne=false: Mond, true=Sonne, 2=bürgerliche Dämmerung, 3=nautische Dämmerung
BOOL GetTimezoneChangeDate(MYSYSTEMTIME *st);	// siehe GetTimeZoneInformation()
void InitTZ(void);

/*** pngload.c ***/		// Funktionen, die nur mit Anwesenheit von Gdiplus funktionieren
HBITMAP pngload(PCTSTR);	// lädt PNG-Datei (auch .GIF usw.)

/*** DlgXxx.c ***/
INT_PTR CALLBACK HardwareDlgProc(HWND,UINT,WPARAM,LPARAM);
INT_PTR CALLBACK DiagnoseDlgProc(HWND,UINT,WPARAM,LPARAM);
INT_PTR CALLBACK EmpfangDlgProc(HWND,UINT,WPARAM,LPARAM);
INT_PTR CALLBACK StellenDlgProc(HWND,UINT,WPARAM,LPARAM);
INT_PTR CALLBACK HistogrammDlgProc(HWND,UINT,WPARAM,LPARAM);
INT_PTR CALLBACK TrayIconDlgProc(HWND,UINT,WPARAM,LPARAM);
INT_PTR CALLBACK UeberDlgProc(HWND,UINT,WPARAM,LPARAM);
INT_PTR CALLBACK WetterDlgProc(HWND,UINT,WPARAM,LPARAM);
INT_PTR CALLBACK DemodulatorDlgProc(HWND,UINT,WPARAM,LPARAM);
Vorgefundene Kodierung: UTF-80