DCF77: Add weather info decoding and coding
parent
5ae64a2712
commit
616a5e2820
2
README
2
README
|
@ -28,7 +28,7 @@ Additionally the following communication services are implemented:
|
|||
* German classic 'Zeitansage' (talking clock)
|
||||
* POCSAG transmitter / receiver
|
||||
* Golay/GSC transmitter / receiver
|
||||
* DCF77 time signal transmitter and receiver
|
||||
* DCF77 time signal transmitter and receiver with weather info
|
||||
* C-Netz SIM emulator
|
||||
* C-Netz magnetic card emulator
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ Additional features:
|
|||
<li>POCSAG (paging system)</li>
|
||||
<li>Golay / GSC (paging system)</li>
|
||||
<li>5-Ton-Ruf (firefighter's pagers and siren control)</li>
|
||||
<li>DCF77 The German longwave time signal transmitter/receiver</li>
|
||||
</ul>
|
||||
</td></tr></table></center>
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ bin_PROGRAMS = \
|
|||
|
||||
dcf77_SOURCES = \
|
||||
dcf77.c \
|
||||
weather.c \
|
||||
cities.c \
|
||||
image.c \
|
||||
main.c
|
||||
dcf77_LDADD = \
|
||||
$(COMMON_LA) \
|
||||
|
|
|
@ -0,0 +1,633 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "cities.h"
|
||||
|
||||
static struct city_list {
|
||||
int region;
|
||||
const char *name;
|
||||
} city_list[] = {
|
||||
{ 0, "AGEN" },
|
||||
{ 0, "AUCH" },
|
||||
{ 0, "BORDEAUX" },
|
||||
{ 0, "BRIVE LA GAILLARDE" },
|
||||
{ 0, "CAHORS" },
|
||||
{ 0, "MONTAUBAN" },
|
||||
{ 0, "MONT MARSAN" },
|
||||
{ 0, "PAU" },
|
||||
{ 0, "PERIGUEUX" },
|
||||
{ 0, "TARBES" },
|
||||
{ 0, "TOULOUSE" },
|
||||
{ 1, "ANGOULEME" },
|
||||
{ 1, "LA ROCHELL" },
|
||||
{ 1, "LA ROCHE S" },
|
||||
{ 1, "LIMOGES" },
|
||||
{ 1, "NIORT" },
|
||||
{ 1, "POITIERS" },
|
||||
{ 2, "ALENCON" },
|
||||
{ 2, "AUXERRE" },
|
||||
{ 2, "BAR LE DUC" },
|
||||
{ 2, "BLOIS" },
|
||||
{ 2, "BOBIGNY" },
|
||||
{ 2, "BOURGES" },
|
||||
{ 2, "CERGY PONT" },
|
||||
{ 2, "CHARTRES" },
|
||||
{ 2, "CRETEIL" },
|
||||
{ 2, "EVRY" },
|
||||
{ 2, "LE MANS" },
|
||||
{ 2, "MELUN" },
|
||||
{ 2, "NANTERRE" },
|
||||
{ 2, "NEVERS" },
|
||||
{ 2, "ORLEANS" },
|
||||
{ 2, "PARIS" },
|
||||
{ 2, "REIMS" },
|
||||
{ 2, "TOURS" },
|
||||
{ 2, "TROYES" },
|
||||
{ 2, "VERSAILLES" },
|
||||
{ 3, "ANGERS" },
|
||||
{ 3, "BREST" },
|
||||
{ 3, "CHERBOURG" },
|
||||
{ 3, "JERSEY" },
|
||||
{ 3, "LAVAL" },
|
||||
{ 3, "LORIENT" },
|
||||
{ 3, "NANTES" },
|
||||
{ 3, "RENNES" },
|
||||
{ 3, "ST BRIEUC" },
|
||||
{ 4, "AURILLAC" },
|
||||
{ 4, "CLERMON FERRAND" },
|
||||
{ 4, "FLORAC" },
|
||||
{ 4, "GUERET" },
|
||||
{ 4, "MENDE" },
|
||||
{ 4, "MILLAU" },
|
||||
{ 4, "MONTLUCON" },
|
||||
{ 4, "PUY VELAY" },
|
||||
{ 4, "RODEZ" },
|
||||
{ 4, "ST-ETIENNE" },
|
||||
{ 4, "ST FLOUR" },
|
||||
{ 5, "ALBI" },
|
||||
{ 5, "BEZIERS" },
|
||||
{ 5, "CARCASSONN" },
|
||||
{ 5, "FOIX" },
|
||||
{ 5, "MONTPELLIER" },
|
||||
{ 5, "PERPIGNAN" },
|
||||
{ 6, "AALST" },
|
||||
{ 6, "ANTWERPEN" },
|
||||
{ 6, "BOULOGNE" },
|
||||
{ 6, "BRUGGE" },
|
||||
{ 6, "BRUSSEL" },
|
||||
{ 6, "CHARLEROI" },
|
||||
{ 6, "GENK" },
|
||||
{ 6, "GENT" },
|
||||
{ 6, "HALLE" },
|
||||
{ 6, "HASSELT" },
|
||||
{ 6, "IXELLES" },
|
||||
{ 6, "KNOKKE-HEIST" },
|
||||
{ 6, "KORTRIJK" },
|
||||
{ 6, "LEUVEN" },
|
||||
{ 6, "LIEGE" },
|
||||
{ 6, "LILLE" },
|
||||
{ 6, "LOKEREN" },
|
||||
{ 6, "MAASTRICHT" },
|
||||
{ 6, "MECHELEN" },
|
||||
{ 6, "MIDDELBURG" },
|
||||
{ 6, "MONS" },
|
||||
{ 6, "MOUSCRON" },
|
||||
{ 6, "NAMUR" },
|
||||
{ 6, "OOSTENDE" },
|
||||
{ 6, "ROESELARE" },
|
||||
{ 6, "SCHAERBEEK" },
|
||||
{ 6, "TERNEUZEN" },
|
||||
{ 6, "TOURNAI" },
|
||||
{ 7, "CHAUMONT" },
|
||||
{ 7, "DIJON" },
|
||||
{ 7, "EPINAL" },
|
||||
{ 7, "LONS LE S" },
|
||||
{ 7, "METZ" },
|
||||
{ 7, "NANCY" },
|
||||
{ 7, "VESOUL" },
|
||||
{ 8, "ALES" },
|
||||
{ 8, "AVIGNON" },
|
||||
{ 8, "MARSEILLE" },
|
||||
{ 8, "MONTELIMAR" },
|
||||
{ 8, "NIMES" },
|
||||
{ 8, "PRIVAS" },
|
||||
{ 8, "ST TROPEZ" },
|
||||
{ 8, "TOULON" },
|
||||
{ 9, "BOURG EN B" },
|
||||
{ 9, "LYON" },
|
||||
{ 9, "MACON" },
|
||||
{ 9, "VALENCE" },
|
||||
{ 10, "BRIANCON" },
|
||||
{ 10, "CHAMBERY" },
|
||||
{ 10, "DIGNE" },
|
||||
{ 10, "GAP" },
|
||||
{ 10, "GRENOBLE" },
|
||||
{ 11, "ANNECY" },
|
||||
{ 11, "BESANCON" },
|
||||
{ 11, "DELEMONT" },
|
||||
{ 11, "LA CHAUX-DE-FONDS" },
|
||||
{ 12, "ASCHAFFENBURG" },
|
||||
{ 12, "BAD HOMBURG" },
|
||||
{ 12, "BAD KREUZNACH" },
|
||||
{ 12, "DARMSTADT" },
|
||||
{ 12, "FRANKFURT AM MAIN" },
|
||||
{ 12, "HEIDELBERG" },
|
||||
{ 12, "KAISERSLAUTERN" },
|
||||
{ 12, "KARLSRUHE" },
|
||||
{ 12, "LANDAU IN DER PFALZ" },
|
||||
{ 12, "LUDWIGSHAFEN" },
|
||||
{ 12, "MAINZ" },
|
||||
{ 12, "MANNHEIM" },
|
||||
{ 12, "PIRMASENS" },
|
||||
{ 12, "WORMS" },
|
||||
{ 13, "BITBURG" },
|
||||
{ 13, "HAGEN" },
|
||||
{ 13, "ISERLOHN" },
|
||||
{ 13, "KOBLENZ" },
|
||||
{ 13, "LUEDENSCHEID" },
|
||||
{ 13, "LUXEMBOURG" },
|
||||
{ 13, "NEUWIED" },
|
||||
{ 13, "SAARBRUECKEN" },
|
||||
{ 13, "SEDAN" },
|
||||
{ 13, "SIEGEN" },
|
||||
{ 13, "TRIER" },
|
||||
{ 13, "VERVIERS" },
|
||||
{ 13, "WIESBADEN" },
|
||||
{ 14, "AACHEN" },
|
||||
{ 14, "BIELEFELD" },
|
||||
{ 14, "BOCHUM" },
|
||||
{ 14, "BONN" },
|
||||
{ 14, "DORTMUND" },
|
||||
{ 14, "DUEREN" },
|
||||
{ 14, "DUESSELDORF" },
|
||||
{ 14, "DUISBURG" },
|
||||
{ 14, "ESSEN" },
|
||||
{ 14, "GELSENKIRCHEN" },
|
||||
{ 14, "GUETERSLOH" },
|
||||
{ 14, "KOELN" },
|
||||
{ 14, "LINGEN" },
|
||||
{ 14, "LIPPSTADT" },
|
||||
{ 14, "MOENCHENGLADBACH" },
|
||||
{ 14, "MUELHEIM AN DER RUHR" },
|
||||
{ 14, "MUENSTER" },
|
||||
{ 14, "NORDHORN" },
|
||||
{ 14, "OBERHAUSEN" },
|
||||
{ 14, "OSNABRUECK" },
|
||||
{ 14, "RECKLINGHAUSEN" },
|
||||
{ 14, "RHEINE" },
|
||||
{ 14, "SOLINGEN" },
|
||||
{ 14, "WESEL" },
|
||||
{ 14, "WUPPERTAL" },
|
||||
{ 15, "BRISTOL" },
|
||||
{ 15, "CARDIFF" },
|
||||
{ 15, "EXETER" },
|
||||
{ 15, "HOLYHEAD" },
|
||||
{ 15, "PLYMOUTH" },
|
||||
{ 15, "ST DAVIDS" },
|
||||
{ 15, "SWANSEA" },
|
||||
{ 16, "BIRMINGHAM" },
|
||||
{ 16, "BLACKPOOL" },
|
||||
{ 16, "LEEDS" },
|
||||
{ 16, "LEICESTER" },
|
||||
{ 16, "LIVERPOOL" },
|
||||
{ 16, "MANCHESTER" },
|
||||
{ 16, "MIDDLESBROUGH" },
|
||||
{ 16, "NEWCASTLE" },
|
||||
{ 16, "NOTTINGHAM" },
|
||||
{ 16, "SHEFFIELD" },
|
||||
{ 17, "AMIENS" },
|
||||
{ 17, "BEAUVAIS" },
|
||||
{ 17, "CAEN" },
|
||||
{ 17, "EVREUX" },
|
||||
{ 17, "LAON" },
|
||||
{ 17, "LE HAVRE" },
|
||||
{ 17, "ROUEN" },
|
||||
{ 18, "BOURNEMOUT" },
|
||||
{ 18, "BRIGHTON" },
|
||||
{ 18, "CAMBRIDGE" },
|
||||
{ 18, "DOVER" },
|
||||
{ 18, "IPSWICH" },
|
||||
{ 18, "KINGSTON" },
|
||||
{ 18, "LONDON" },
|
||||
{ 18, "NORTHAMPTON" },
|
||||
{ 18, "NORWICH" },
|
||||
{ 18, "OXFORD" },
|
||||
{ 18, "PORTSMOUTH" },
|
||||
{ 18, "READING" },
|
||||
{ 18, "SOUTHAMPTON" },
|
||||
{ 19, "BORKUM" },
|
||||
{ 19, "BREMERHAVEN" },
|
||||
{ 19, "CUXHAVEN" },
|
||||
{ 19, "DEN HELDER" },
|
||||
{ 19, "ELMSHORN" },
|
||||
{ 19, "EMDEN" },
|
||||
{ 19, "GRONINGEN" },
|
||||
{ 19, "HAMBURG" },
|
||||
{ 19, "LEEUWARDEN" },
|
||||
{ 19, "NORDERTSTEDT" },
|
||||
{ 19, "SPIEKEROOG" },
|
||||
{ 19, "ST PETER ORDING" },
|
||||
{ 19, "SYLT" },
|
||||
{ 19, "TEXEL" },
|
||||
{ 19, "WILHELMSHAVEN" },
|
||||
{ 20, "ALBORG" },
|
||||
{ 20, "ESBJERG" },
|
||||
{ 20, "FREDERIKSHAVN" },
|
||||
{ 20, "HERNING" },
|
||||
{ 20, "HOLSTERBRO" },
|
||||
{ 20, "SKAGEN" },
|
||||
{ 20, "THISTED" },
|
||||
{ 20, "THYBOROEN" },
|
||||
{ 20, "VIBORG" },
|
||||
{ 21, "ARHUS" },
|
||||
{ 21, "FREDERICIA" },
|
||||
{ 21, "HORSENS" },
|
||||
{ 21, "KOLDING" },
|
||||
{ 21, "ODENSE" },
|
||||
{ 21, "RANDERS" },
|
||||
{ 21, "SILKEBORG" },
|
||||
{ 21, "VEJLE" },
|
||||
{ 22, "BRAUNSCHWEIG" },
|
||||
{ 22, "BREMEN" },
|
||||
{ 22, "CELLE" },
|
||||
{ 22, "GOSLAR" },
|
||||
{ 22, "HAMELN" },
|
||||
{ 22, "HANNOVER" },
|
||||
{ 22, "HERFORD" },
|
||||
{ 22, "HILDESHEIM" },
|
||||
{ 22, "LUENEBURG" },
|
||||
{ 22, "MAGDEBURG" },
|
||||
{ 22, "MINDEN" },
|
||||
{ 22, "OLDENBURG" },
|
||||
{ 22, "WOLFSBURG" },
|
||||
{ 23, "HELSINGOER" },
|
||||
{ 23, "KALUNDBORG" },
|
||||
{ 23, "KOEBENHAVN" },
|
||||
{ 23, "MALMOE" },
|
||||
{ 23, "NAESTVED" },
|
||||
{ 23, "ROSKILDE" },
|
||||
{ 23, "SLAGELSE" },
|
||||
{ 24, "FEHMARN" },
|
||||
{ 24, "FLENSBURG" },
|
||||
{ 24, "GREIFSWALD" },
|
||||
{ 24, "KIEL" },
|
||||
{ 24, "LUEBECK" },
|
||||
{ 24, "ROSTOCK" },
|
||||
{ 24, "RUEGEN" },
|
||||
{ 24, "SCHWERIN" },
|
||||
{ 24, "STRALSUND" },
|
||||
{ 24, "SZCZECIN" },
|
||||
{ 24, "WISMAR" },
|
||||
{ 25, "AUGSBURG" },
|
||||
{ 25, "DEGGENDORF" },
|
||||
{ 25, "INGOLSTADT" },
|
||||
{ 25, "LANDSHUT" },
|
||||
{ 25, "PASSAU" },
|
||||
{ 25, "REGENSBURG" },
|
||||
{ 25, "ULM" },
|
||||
{ 26, "BURGHAUSEN" },
|
||||
{ 26, "FRIEDRICHSHAFEN" },
|
||||
{ 26, "KEMPTEN" },
|
||||
{ 26, "LINZ" },
|
||||
{ 26, "MUENCHEN" },
|
||||
{ 26, "ROSENHEIM" },
|
||||
{ 26, "SIGMARINGEN" },
|
||||
{ 26, "WELS" },
|
||||
{ 27, "BOLZANO" },
|
||||
{ 27, "MERANO" },
|
||||
{ 27, "TRENTO" },
|
||||
{ 28, "ANSBACH" },
|
||||
{ 28, "BAMBERG" },
|
||||
{ 28, "BAYREUTH" },
|
||||
{ 28, "ERLANGEN" },
|
||||
{ 28, "FUERTH" },
|
||||
{ 28, "NUERNBERG" },
|
||||
{ 28, "SCHWEINFURT" },
|
||||
{ 28, "WEIDEN" },
|
||||
{ 28, "WERTHEIM" },
|
||||
{ 28, "WUERZBURG" },
|
||||
{ 29, "ALTENBURG" },
|
||||
{ 29, "BAUTZEN" },
|
||||
{ 29, "CHEMNITZ" },
|
||||
{ 29, "COTTBUS" },
|
||||
{ 29, "DESSAU" },
|
||||
{ 29, "DRESDEN" },
|
||||
{ 29, "EISENHUETTENSTADT" },
|
||||
{ 29, "GOERLITZ" },
|
||||
{ 29, "HALLE" },
|
||||
{ 29, "HOYERSWERDA" },
|
||||
{ 29, "LEIPZIG" },
|
||||
{ 29, "WITTENBERG" },
|
||||
{ 29, "WROCLAW" },
|
||||
{ 30, "EISENACH" },
|
||||
{ 30, "ERFURT" },
|
||||
{ 30, "GOTHA" },
|
||||
{ 30, "HOF" },
|
||||
{ 30, "JENA" },
|
||||
{ 30, "NORDHAUSEN" },
|
||||
{ 30, "PLAUEN" },
|
||||
{ 30, "SUHL" },
|
||||
{ 30, "WEIMAR" },
|
||||
{ 30, "ZWICKAU" },
|
||||
{ 31, "EVIAN" },
|
||||
{ 31, "FRIBOURG" },
|
||||
{ 31, "GENEVE" },
|
||||
{ 31, "LAUSANNE" },
|
||||
{ 31, "MONTREUX" },
|
||||
{ 31, "NEUCHATEL" },
|
||||
{ 32, "AARAU" },
|
||||
{ 32, "BERN" },
|
||||
{ 32, "BIENNE" },
|
||||
{ 32, "FRAUENFELD" },
|
||||
{ 32, "KONSTANZ" },
|
||||
{ 32, "LUZERN" },
|
||||
{ 32, "SCHAFFHAUSEN" },
|
||||
{ 32, "SOLOTHURN" },
|
||||
{ 32, "ZUERICH" },
|
||||
{ 32, "ZUG" },
|
||||
{ 33, "ADELBODEN" },
|
||||
{ 33, "GRINDELWALD" },
|
||||
{ 33, "INTERLAKEN" },
|
||||
{ 34, "BRIG" },
|
||||
{ 34, "MARTIGNY" },
|
||||
{ 34, "SION" },
|
||||
{ 35, "ALTDORF" },
|
||||
{ 35, "GLARUS" },
|
||||
{ 35, "SARNEN" },
|
||||
{ 35, "SCHWYZ" },
|
||||
{ 35, "STANS" },
|
||||
{ 35, "ST.GALLEN" },
|
||||
{ 36, "CHUR" },
|
||||
{ 36, "DAVOS" },
|
||||
{ 37, "FULDA" },
|
||||
{ 37, "GIESSEN" },
|
||||
{ 37, "GOETTINGEN" },
|
||||
{ 37, "KASSEL" },
|
||||
{ 37, "MARBURG" },
|
||||
{ 38, "BELLINZONA" },
|
||||
{ 38, "EDOLO" },
|
||||
{ 38, "LOCARNO" },
|
||||
{ 38, "LUGANO" },
|
||||
{ 39, "AOSTA" },
|
||||
{ 39, "SESTRIERE" },
|
||||
{ 40, "ALESSANDRIA" },
|
||||
{ 40, "BERGAMO" },
|
||||
{ 40, "BRESCIA" },
|
||||
{ 40, "MILANO" },
|
||||
{ 40, "PARMA" },
|
||||
{ 40, "PIACENZA" },
|
||||
{ 40, "TORINO" },
|
||||
{ 40, "VERONA" },
|
||||
{ 41, "FIRENZE" },
|
||||
{ 41, "PERUGIA" },
|
||||
{ 41, "PISA" },
|
||||
{ 41, "ROMA" },
|
||||
{ 41, "SIENA" },
|
||||
{ 41, "VATICANO" },
|
||||
{ 42, "AMSTERDAM" },
|
||||
{ 42, "ARNHEM" },
|
||||
{ 42, "ASSEN" },
|
||||
{ 42, "DEN HAAG" },
|
||||
{ 42, "EINDHOVEN" },
|
||||
{ 42, "HAARLEM" },
|
||||
{ 42, "LELYSTAD" },
|
||||
{ 42, "ROTTERDAM" },
|
||||
{ 42, "S.HERTOGENBOSCH" },
|
||||
{ 42, "UTRECHT" },
|
||||
{ 42, "ZWOLLE" },
|
||||
{ 43, "CANNES" },
|
||||
{ 43, "GENOVA" },
|
||||
{ 43, "LA SPEZIA" },
|
||||
{ 43, "MONACO" },
|
||||
{ 43, "NICE" },
|
||||
{ 43, "SAN REMO" },
|
||||
{ 44, "BOLOGNA" },
|
||||
{ 44, "NOVA GORIC" },
|
||||
{ 44, "RIJEKA" },
|
||||
{ 44, "RIMINI" },
|
||||
{ 44, "TRIESTE" },
|
||||
{ 44, "UDINE" },
|
||||
{ 44, "VENEZIA" },
|
||||
{ 45, "BASEL" },
|
||||
{ 45, "BELFORT" },
|
||||
{ 45, "COLMAR" },
|
||||
{ 45, "FREIBURG" },
|
||||
{ 45, "LIESTAL" },
|
||||
{ 45, "LOERRACH" },
|
||||
{ 45, "MULHOUSE" },
|
||||
{ 45, "OFFENBURG" },
|
||||
{ 45, "STRASBOURG" },
|
||||
{ 46, "GRAZ" },
|
||||
{ 46, "KLAGENFURT" },
|
||||
{ 46, "LIENZ" },
|
||||
{ 46, "LJUBLJANA" },
|
||||
{ 46, "MARIBOR" },
|
||||
{ 46, "SEMMERING" },
|
||||
{ 46, "VILLACH" },
|
||||
{ 46, "ZELTWEG" },
|
||||
{ 47, "BAD GASTEIN" },
|
||||
{ 47, "INNSBRUCK" },
|
||||
{ 47, "ISCHGL" },
|
||||
{ 47, "LANDECK" },
|
||||
{ 47, "SOELDEN" },
|
||||
{ 47, "TUXERTAL" },
|
||||
{ 48, "BAD TOELZ" },
|
||||
{ 48, "BERCHTESGADEN" },
|
||||
{ 48, "BISCHOFSHOFEN" },
|
||||
{ 48, "BREGENZ" },
|
||||
{ 48, "GARMISCH PARTENKIRCHEN" },
|
||||
{ 48, "KITZBUEHEL" },
|
||||
{ 48, "LINDAU" },
|
||||
{ 48, "SALZBURG" },
|
||||
{ 48, "SCHLADMING" },
|
||||
{ 48, "STEYR" },
|
||||
{ 48, "VADUZ" },
|
||||
{ 49, "BRATISLAVA" },
|
||||
{ 49, "EISENSTADT" },
|
||||
{ 49, "GYOER" },
|
||||
{ 49, "KLOSTERNEUBURG" },
|
||||
{ 49, "SOPRON" },
|
||||
{ 49, "SZOMBATHELY" },
|
||||
{ 49, "TRENCIN" },
|
||||
{ 49, "WIEN" },
|
||||
{ 49, "WIENER NEUSTADT" },
|
||||
{ 49, "ZALAEGERSZEG" },
|
||||
{ 50, "BRNO" },
|
||||
{ 50, "BUDEJOVICE" },
|
||||
{ 50, "CHEB" },
|
||||
{ 50, "HAVLICKAV BROD" },
|
||||
{ 50, "HRADEC/KRA" },
|
||||
{ 50, "JIHLAVA" },
|
||||
{ 50, "KARLOVY VARY" },
|
||||
{ 50, "KLADNO" },
|
||||
{ 50, "MOST" },
|
||||
{ 50, "OLOMOUC" },
|
||||
{ 50, "OSTRAVA" },
|
||||
{ 50, "PARDUBICE" },
|
||||
{ 50, "PLZEN" },
|
||||
{ 50, "PRAHA" },
|
||||
{ 50, "PREROV" },
|
||||
{ 50, "PROSTEJOV" },
|
||||
{ 50, "ST POELTEN" },
|
||||
{ 50, "ZWETTL" },
|
||||
{ 51, "CHOMUTOV" },
|
||||
{ 51, "DECIN" },
|
||||
{ 51, "LIBEREC" },
|
||||
{ 51, "OPAVA" },
|
||||
{ 51, "PIRNA" },
|
||||
{ 51, "SNIEZKA" },
|
||||
{ 51, "TEPLICE" },
|
||||
{ 51, "USTI NAD LABEM" },
|
||||
{ 51, "WALBRZYCH" },
|
||||
{ 52, "BERLIN" },
|
||||
{ 52, "BRANDENBURG" },
|
||||
{ 52, "FINOW" },
|
||||
{ 52, "FRANKFURT AN DER ODER" },
|
||||
{ 52, "GORZOW" },
|
||||
{ 52, "NEUBRANDENBURG" },
|
||||
{ 52, "POTSDAM" },
|
||||
{ 52, "POZNAN" },
|
||||
{ 52, "STENDAL" },
|
||||
{ 53, "GOETEBORG" },
|
||||
{ 53, "HALMSTAD" },
|
||||
{ 54, "GAEVLE" },
|
||||
{ 54, "NYKOPING" },
|
||||
{ 54, "STOCKHOLM" },
|
||||
{ 54, "UPPSALA" },
|
||||
{ 54, "VAESTERAS" },
|
||||
{ 55, "BORGHOLM" },
|
||||
{ 55, "BORNHOLM" },
|
||||
{ 55, "KALMAR" },
|
||||
{ 55, "LINKOEPING" },
|
||||
{ 55, "RONNE" },
|
||||
{ 55, "VISBY" },
|
||||
{ 56, "BORAS" },
|
||||
{ 56, "JOENKOEPING" },
|
||||
{ 56, "KARLSTAD" },
|
||||
{ 56, "OEREBRO" },
|
||||
{ 57, "BADEN-BADEN" },
|
||||
{ 57, "DONAUESCHINGEN" },
|
||||
{ 57, "FREUDENSTADT" },
|
||||
{ 57, "VILLINGEN-SCHWENNINGEN" },
|
||||
{ 58, "DRAMMEN" },
|
||||
{ 58, "FREDRIKSTADEN" },
|
||||
{ 58, "OSLO" },
|
||||
{ 58, "TOENSBERG" },
|
||||
{ 59, "AALEN" },
|
||||
{ 59, "GOEPPINGEN" },
|
||||
{ 59, "HEILBRONN" },
|
||||
{ 59, "PFORZHEIM" },
|
||||
{ 59, "REUTLINGEN" },
|
||||
{ 59, "SCHWAEBISCH GMUEND" },
|
||||
{ 59, "STUTTGART" },
|
||||
{ 59, "TUEBINGEN" },
|
||||
{ 60, "NAPOLI" },
|
||||
{ 61, "ANCONA" },
|
||||
{ 61, "PESCARA" },
|
||||
{ 61, "SAN MARINO" },
|
||||
{ 62, "BARI" },
|
||||
{ 62, "FOGGIA" },
|
||||
{ 62, "LECCE" },
|
||||
{ 63, "BEKESCSABA" },
|
||||
{ 63, "BRANSKA" },
|
||||
{ 63, "BUDAPEST" },
|
||||
{ 63, "DEBRECEN" },
|
||||
{ 63, "DUNAIJVAROS" },
|
||||
{ 63, "EGER" },
|
||||
{ 63, "ERD" },
|
||||
{ 63, "HODMEZOVASARHELY" },
|
||||
{ 63, "KAPOSVAR" },
|
||||
{ 63, "KECSKEMET" },
|
||||
{ 63, "KOSICE" },
|
||||
{ 63, "MISKOLC" },
|
||||
{ 63, "NAGYKANIZSA" },
|
||||
{ 63, "NYIREGYHAZA" },
|
||||
{ 63, "OZD" },
|
||||
{ 63, "PECS" },
|
||||
{ 63, "SALGOTARJAN" },
|
||||
{ 63, "SIOFOK" },
|
||||
{ 63, "SZEGED" },
|
||||
{ 63, "SZEKESFEEVAR" },
|
||||
{ 63, "SZOLNOK" },
|
||||
{ 63, "TATABANYA" },
|
||||
{ 63, "VESZPREM" },
|
||||
{ 64, "MADRID" },
|
||||
{ 65, "BILBAO" },
|
||||
{ 66, "CATANIA" },
|
||||
{ 66, "COSENZA" },
|
||||
{ 66, "MESSINA" },
|
||||
{ 66, "PALERMO" },
|
||||
{ 66, "REGGIO CALABRIA" },
|
||||
{ 67, "IBIZA" },
|
||||
{ 67, "MAHON" },
|
||||
{ 67, "PALMA DE MALLORCA" },
|
||||
{ 68, "VALENCIA" },
|
||||
{ 69, "BARCELONA" },
|
||||
{ 69, "FIGUERES" },
|
||||
{ 69, "GIRONA" },
|
||||
{ 69, "LLORET DE MAR" },
|
||||
{ 70, "ANDORRA LA VELLA" },
|
||||
{ 71, "SEVILLA" },
|
||||
{ 72, "LISBOA" },
|
||||
{ 73, "AJACCIO" },
|
||||
{ 73, "BASTIA" },
|
||||
{ 73, "CAGLIARI" },
|
||||
{ 73, "SASSARI" },
|
||||
{ 74, "GIJON" },
|
||||
{ 75, "CORK" },
|
||||
{ 75, "GALWAY" },
|
||||
{ 75, "LIMERICK" },
|
||||
{ 76, "BELFAST" },
|
||||
{ 76, "DUBLIN" },
|
||||
{ 77, "ABERDEEN" },
|
||||
{ 77, "EDINBURGH" },
|
||||
{ 77, "GLASGOW" },
|
||||
{ 77, "ISLE OF MAN" },
|
||||
{ 78, "BERGEN" },
|
||||
{ 78, "STAVANGER" },
|
||||
{ 79, "TRONDHEIM" },
|
||||
{ 80, "SUNDSVALL" },
|
||||
{ 81, "GDANSK" },
|
||||
{ 81, "OLSZTYN" },
|
||||
{ 81, "SLUPSK" },
|
||||
{ 82, "BIALYSTOK" },
|
||||
{ 82, "BYDGOSZCZ" },
|
||||
{ 82, "LODZ" },
|
||||
{ 82, "LUBLIN" },
|
||||
{ 82, "TORUN" },
|
||||
{ 82, "WARSZAWA" },
|
||||
{ 83, "BIELSKO" },
|
||||
{ 83, "KATOWICE" },
|
||||
{ 83, "KIELCE" },
|
||||
{ 83, "KRAKOW" },
|
||||
{ 83, "OPOLE" },
|
||||
{ 83, "RZESZOW" },
|
||||
{ 83, "ZAKOPANE" },
|
||||
{ 84, "UMEA" },
|
||||
{ 85, "FALUN" },
|
||||
{ 85, "OESTERSUND" },
|
||||
{ 86, "SAMEDAN" },
|
||||
{ 87, "OSIJEK" },
|
||||
{ 87, "ZAGREB" },
|
||||
{ 88, "ZERMATT" },
|
||||
{ 89, "SPLIT" },
|
||||
{ 24, "Doerphof" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
void display_city(const char *search)
|
||||
{
|
||||
int i;
|
||||
int found = 0;
|
||||
|
||||
for (i = 0; city_list[i].name; i++) {
|
||||
if (strcasestr(city_list[i].name, search)) {
|
||||
found++;
|
||||
printf("City %s is located in region %d.\n", city_list[i].name, city_list[i].region);
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
printf("No city found for '%s', try larger city.\n", search);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
void display_city(const char *search);
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
/* implementation of DCF77 transmitter and receiver
|
||||
/* implementation of DCF77 transmitter and receiver, including weather
|
||||
*
|
||||
* (C) 2022 by Andreas Eversberg <jolly@eversberg.eu>
|
||||
* All Rights Reserved
|
||||
|
@ -28,6 +28,7 @@
|
|||
#include <math.h>
|
||||
#include "../libdebug/debug.h"
|
||||
#include "dcf77.h"
|
||||
#include "weather.h"
|
||||
|
||||
double get_time(void);
|
||||
|
||||
|
@ -35,7 +36,6 @@ double get_time(void);
|
|||
#define TEST_FREQUENCY 1000
|
||||
#define CARRIER_BANDWIDTH 10.0
|
||||
#define SAMPLE_CLOCK 1000
|
||||
#define CLOCK_1S 1.0
|
||||
#define CLOCK_BANDWIDTH 0.1
|
||||
#define REDUCTION_FACTOR 0.15
|
||||
#define REDUCTION_TH 0.575
|
||||
|
@ -43,6 +43,9 @@ double get_time(void);
|
|||
|
||||
#define level2db(level) (20 * log10(level))
|
||||
|
||||
/* uncomment to speed up transmission by factor 10 and feed the data to the receiver */
|
||||
//#define DEBUG_LOOP
|
||||
|
||||
static int fast_math = 0;
|
||||
static float *sin_tab = NULL, *cos_tab = NULL;
|
||||
|
||||
|
@ -50,6 +53,292 @@ const char *time_zone[4] = { "???", "CEST", "CET", "???" };
|
|||
const char *week_day[8] = { "???", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
|
||||
const char *month_name[13] = { "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
|
||||
const char *datasets_0_59[8] = {
|
||||
"Maximum values 1st day (today)",
|
||||
"Minimum values 1st day (today)",
|
||||
"Maximum values 2nd day (tomorrow)",
|
||||
"Minimum values 2nd day (tomorrow)",
|
||||
"Maximum values 3rd day (in two days)",
|
||||
"Minimum values 3rd day (in two days)",
|
||||
"Maximum values 4th day (in three days)",
|
||||
"Wind and weather anomaly 4th day (in three days)",
|
||||
};
|
||||
|
||||
const char *datasets_60_89[2] = {
|
||||
"Maximum values 1st day (following day)",
|
||||
"Maximum values 2nd day (2nd following day)",
|
||||
};
|
||||
|
||||
const char *region[90] = {
|
||||
"F - Bordeaux, Aquitaine (Suedwestfrankreich)",
|
||||
"F - La Rochelle, Poitou-Charentes (Westkueste Frankreichs)",
|
||||
"F - Paris, Ile-de-France (Pariser Becken)",
|
||||
"F - Brest, Bretagne",
|
||||
"F - Clermont-Ferrand (Massif Central), Auvergne (Zentralmassiv)",
|
||||
"F - Beziers, Languedoc-Roussillon",
|
||||
"B - Bruxelles, Brussel (Benelux)",
|
||||
"F - Dijon (Bourgogne), Bourgogne (Ostfrankreich / Burgund)",
|
||||
"F - Marseille, Provence-Alpes-Côte d'Azur",
|
||||
"F - Lyon (Rhone-Alpes), Rhone-Alpes (Rhonetal)",
|
||||
"F - Grenoble (Savoie), Rhone-Alpes (Franz. Alpen)",
|
||||
"CH - La Chaux de Fond, Jura",
|
||||
"D - Frankfurt am Main, Hessen (Unterer Rheingraben)",
|
||||
"D - Trier, Westliches Mittelgebirge",
|
||||
"D - Duisburg, Nordrhein-Westfalen",
|
||||
"GB - Swansea, Wales (Westl. England / Wales)",
|
||||
"GB - Manchester, England (Noerdliches England)",
|
||||
"F - le Havre, Haute-Normandie (Normandie)",
|
||||
"GB - London, England (Suedostengland / London)",
|
||||
"D - Bremerhaven, Bremen (Nordseekueste)",
|
||||
"DK - Herning, Ringkobing (Nordwestliches Juetland)",
|
||||
"DK - Arhus, Arhus (Oestliches Juetland)",
|
||||
"D - Hannover, Niedersachsen (Norddeutschland)",
|
||||
"DK - Kobenhavn, Staden Kobenhaven (Seeland)",
|
||||
"D - Rostock, Mecklenburg-Vorpommern (Ostseekueste)",
|
||||
"D - Ingolstadt, Bayern (Donautal)",
|
||||
"D - Muenchen, Bayern (Suedbayern)",
|
||||
"I - Bolzano, Trentino-Alto Adige (Suedtirol)",
|
||||
"D - Nuernberg, Bayern (Nordbayern)",
|
||||
"D - Leipzig, Sachsen",
|
||||
"D - Erfurt, Thueringen",
|
||||
"CH - Lausanne, Genferseeregion (Westl. Schweizer Mitteland)",
|
||||
"CH - Zuerich (Oestl. Schweizer Mittelland)",
|
||||
"CH - Adelboden (Westl. Schweizer Alpennordhang)",
|
||||
"CH - Sion, Wallis",
|
||||
"CH - Glarus, Oestlicher Schweizer Alpennordhang",
|
||||
"CH - Davos, Graubuenden",
|
||||
"D - Kassel, Hessen (Mittelgebirge Ost)",
|
||||
"CH - Locarno, Tessin",
|
||||
"I - Sestriere, Piemont. Alpen",
|
||||
"I - Milano, Lombardia (Poebene)",
|
||||
"I - Roma, Lazio (Toskana)",
|
||||
"NL - Amsterdam, Noord-Holland (Holland)",
|
||||
"I - Genova, Liguria (Golf von Genua)",
|
||||
"I - Venezia, Veneto (Pomuendung)",
|
||||
"F - Strasbourg, Alsace (Oberer Rheingraben)",
|
||||
"A - Klagenfurt, Kaernten (Oesterreich. Alpensuedhang)",
|
||||
"A - Innsbruck, Tirol (Inneralpine Gebiete Oesterreichs)",
|
||||
"A - Salzburg, Bayr. / Oesterreich. Alpennordhang",
|
||||
"SK (Oesterreich / Slovakia) - Wien / Bratislava",
|
||||
"CZ - Praha, Prag (Tschechisches Becken)",
|
||||
"CZ - Decin, Severocesky (Erzgebirge)",
|
||||
"D - Berlin, Ostdeutschland",
|
||||
"S - Goeteborg, Goeteborgs och Bohus Laen (Westkueste Schweden)",
|
||||
"S - Stockholm, Stockholms Laen (Stockholm)",
|
||||
"S - Kalmar, Kalmar Laen (Schwedische Ostseekueste)",
|
||||
"S - Joenkoeping, Joenkoepings Laen (Suedschweden)",
|
||||
"D - Donaueschingen, Baden-Wuerttemberg (Schwarzwald / Schwaebische Alb)",
|
||||
"N - Oslo",
|
||||
"D - Stuttgart, Baden-Wuerttemberg (Noerdl. Baden Wuerttemberg)",
|
||||
"I - Napoli",
|
||||
"I - Ancona",
|
||||
"I - Bari",
|
||||
"HU - Budapest",
|
||||
"E - Madrid",
|
||||
"E - Bilbao",
|
||||
"I - Palermo",
|
||||
"E - Palma de Mallorca",
|
||||
"E - Valencia",
|
||||
"E - Barcelona",
|
||||
"AND - Andorra",
|
||||
"E - Sevilla",
|
||||
"P - Lissabon",
|
||||
"I - Sassari, (Sardinien / Korsika)",
|
||||
"E - Gijon",
|
||||
"IRL - Galway",
|
||||
"IRL - Dublin",
|
||||
"GB - Glasgow",
|
||||
"N - Stavanger",
|
||||
"N - Trondheim",
|
||||
"S - Sundsvall",
|
||||
"PL - Gdansk",
|
||||
"PL - Warszawa",
|
||||
"PL - Krakow",
|
||||
"S - Umea",
|
||||
"S - Oestersund",
|
||||
"CH - Samedan",
|
||||
"CR - Zagreb",
|
||||
"CH - Zermatt",
|
||||
"CR - Split",
|
||||
};
|
||||
|
||||
const char *weathers_day[16] = {
|
||||
"Reserved",
|
||||
"Sunny",
|
||||
"Partly clouded",
|
||||
"Mostly clouded",
|
||||
"Overcast",
|
||||
"Heat storms",
|
||||
"Heavy Rain",
|
||||
"Snow",
|
||||
"Fog",
|
||||
"Sleet",
|
||||
"Rain shower",
|
||||
"Light rain",
|
||||
"Snow showers",
|
||||
"Frontal storms",
|
||||
"Stratus cloud",
|
||||
"Sleet storms",
|
||||
};
|
||||
|
||||
const char *weathers_night[16] = {
|
||||
"Reserved",
|
||||
"Clear",
|
||||
"Partly clouded",
|
||||
"Mostly clouded",
|
||||
"Overcast",
|
||||
"Heat storms",
|
||||
"Heavy Rain",
|
||||
"Snow",
|
||||
"Fog",
|
||||
"Sleet",
|
||||
"Rain shower",
|
||||
"Light rain",
|
||||
"Snow showers",
|
||||
"Frontal storms",
|
||||
"Stratus cloud",
|
||||
"Sleet storms",
|
||||
};
|
||||
|
||||
const char *extremeweathers[16] = {
|
||||
"None",
|
||||
"Heavy Weather 24 hrs.",
|
||||
"Heavy weather Day",
|
||||
"Heavy weather Night",
|
||||
"Storm 24hrs.",
|
||||
"Storm Day",
|
||||
"Storm Night",
|
||||
"Wind gusts Day",
|
||||
"Wind gusts Night",
|
||||
"Icy rain morning",
|
||||
"Icy rain evening",
|
||||
"Icy rain night",
|
||||
"Fine dust",
|
||||
"Ozon",
|
||||
"Radiation",
|
||||
"High water",
|
||||
};
|
||||
|
||||
const char *probabilities[8] = {
|
||||
"0 %",
|
||||
"15 %",
|
||||
"30 %",
|
||||
"45 %",
|
||||
"60 %",
|
||||
"75 %",
|
||||
"90 %",
|
||||
"100 %",
|
||||
};
|
||||
|
||||
const char *winddirections[16] = {
|
||||
"North",
|
||||
"Northeast",
|
||||
"East",
|
||||
"Southeast",
|
||||
"South",
|
||||
"Southwest",
|
||||
"West",
|
||||
"Northwest",
|
||||
"Changeable",
|
||||
"Foen",
|
||||
"Biese N/O",
|
||||
"Mistral N",
|
||||
"Scirocco S",
|
||||
"Tramont W",
|
||||
"reserved",
|
||||
"reserved",
|
||||
};
|
||||
|
||||
const char *windstrengths[8] = {
|
||||
"0",
|
||||
"0-2",
|
||||
"3-4",
|
||||
"5-6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
">=10",
|
||||
};
|
||||
|
||||
const char *yesno[2] = {
|
||||
"No",
|
||||
"Yes",
|
||||
};
|
||||
const char *anomaly1[4] = {
|
||||
"Same Weather",
|
||||
"Jump 1",
|
||||
"Jump 2",
|
||||
"Jump 3",
|
||||
};
|
||||
const char *anomaly2[4] = {
|
||||
"0-2 hrs",
|
||||
"2-4 hrs",
|
||||
"5-6 hrs",
|
||||
"7-8 hrs",
|
||||
};
|
||||
|
||||
/* show a list of weather data values */
|
||||
void list_weather(void)
|
||||
{
|
||||
time_t timestamp, t;
|
||||
struct tm *tm;
|
||||
int i, j;
|
||||
|
||||
/* get time stamp of this day, but at 22:00 UTC */
|
||||
timestamp = floor(get_time());
|
||||
timestamp -= timestamp % 86400;
|
||||
timestamp += 79200;
|
||||
|
||||
printf("\n");
|
||||
printf("List of all regions\n");
|
||||
printf("-------------------\n");
|
||||
for (i = 0; i < 90; i++) {
|
||||
printf("Region: %2d = %s\n", i, region[i]);
|
||||
for (j = 0; j < 8; j++) {
|
||||
/* get local time where transmission starts */
|
||||
if (i < 60) {
|
||||
t = timestamp + 180 * i + 10800 * j;
|
||||
tm = localtime(&t);
|
||||
printf(" -> Transmission at %02d:%02d of %s\n", tm->tm_hour, tm->tm_min, datasets_0_59[j]);
|
||||
} else if (j < 2) {
|
||||
t = timestamp + 180 * (i - 60) + 10800 * 7 + 5400 * j;
|
||||
tm = localtime(&t);
|
||||
printf(" -> Transmission at %02d:%02d of %s\n", tm->tm_hour, tm->tm_min, datasets_60_89[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("List of all weathers\n");
|
||||
printf("--------------------\n");
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (i == 1)
|
||||
printf("Weather: %2d = %s (day) %s (night)\n", i, weathers_day[i], weathers_night[i]);
|
||||
else
|
||||
printf("Weather: %2d = %s (day and night)\n", i, weathers_day[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("List of all extreme weathers\n");
|
||||
printf("----------------------------\n");
|
||||
for (i = 1; i < 16; i++) {
|
||||
printf("Extreme: %2d = %s\n", i, extremeweathers[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static const char *show_bits(uint64_t value, int bits)
|
||||
{
|
||||
static char bit[128];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bits; i++)
|
||||
bit[i] = '0' + ((value >> i) & 1);
|
||||
sprintf(bit + i, "(%" PRIu64 ")", value);
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
/* global init */
|
||||
int dcf77_init(int _fast_math)
|
||||
{
|
||||
|
@ -82,6 +371,7 @@ void dcf77_exit(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* instance creation */
|
||||
dcf77_t *dcf77_create(int samplerate, int use_tx, int use_rx, int test_tone)
|
||||
{
|
||||
dcf77_t *dcf77 = NULL;
|
||||
|
@ -150,6 +440,7 @@ dcf77_t *dcf77_create(int samplerate, int use_tx, int use_rx, int test_tone)
|
|||
dcf77->dmp_input_level = display_measurements_add(&dcf77->dispmeas, "Input Level", "%.0f dB", DISPLAY_MEAS_AVG, DISPLAY_MEAS_LEFT, -100.0, 0.0, -INFINITY);
|
||||
dcf77->dmp_signal_level = display_measurements_add(&dcf77->dispmeas, "Signal Level", "%.0f dB", DISPLAY_MEAS_AVG, DISPLAY_MEAS_LEFT, -100.0, 0.0, -INFINITY);
|
||||
dcf77->dmp_signal_quality = display_measurements_add(&dcf77->dispmeas, "Signal Qualtiy", "%.0f %%", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 100.0, -INFINITY);
|
||||
dcf77->dmp_current_second = display_measurements_add(&dcf77->dispmeas, "Current Second", "%.0f", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 59.0, -INFINITY);
|
||||
}
|
||||
|
||||
if (tx->enable)
|
||||
|
@ -157,9 +448,17 @@ dcf77_t *dcf77_create(int samplerate, int use_tx, int use_rx, int test_tone)
|
|||
if (rx->enable)
|
||||
PDEBUG(DDCF77, DEBUG_INFO, "DCF77 receiver has been created.\n");
|
||||
|
||||
#if 0
|
||||
void rx_frame_test(dcf77_t *dcf77, const char *string);
|
||||
rx_frame_test(dcf77, "00001000011111100100101101001010000110000110011100001010000");
|
||||
rx_frame_test(dcf77, "00101010111111000100111101000010000110000110011100001010000");
|
||||
rx_frame_test(dcf77, "00011000101111000100100011000010000110000110011100001010000");
|
||||
#endif
|
||||
|
||||
return dcf77;
|
||||
}
|
||||
|
||||
/* instance destruction */
|
||||
void dcf77_destroy(dcf77_t *dcf77)
|
||||
{
|
||||
if (dcf77) {
|
||||
|
@ -171,33 +470,264 @@ void dcf77_destroy(dcf77_t *dcf77)
|
|||
PDEBUG(DDCF77, DEBUG_INFO, "DCF77 has been destroyed.\n");
|
||||
}
|
||||
|
||||
/* set inital time stamp at the moment the stream starts */
|
||||
void dcf77_tx_start(dcf77_t *dcf77, time_t timestamp)
|
||||
static void display_weather_temperature(const char *desc, uint32_t weather)
|
||||
{
|
||||
int value;
|
||||
|
||||
value = (weather >> 16) & 0x3f;
|
||||
switch (value) {
|
||||
case 0:
|
||||
printf("%s%s = < -21 degrees C\n", desc, show_bits(value, 6));
|
||||
break;
|
||||
case 63:
|
||||
printf("%s%s = > 40 degrees C\n", desc, show_bits(value, 6));
|
||||
break;
|
||||
default:
|
||||
printf("%s%s = %d degrees C\n", desc, show_bits(value, 6), value - 22);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TX part
|
||||
*/
|
||||
|
||||
/* Adjust given time stamp to the time stamp when the weather of the given
|
||||
* region istransmitted. An offset is used to start several minutes before
|
||||
* the transmission of the region starts, so the receiver has time to sync
|
||||
* to the signal first, so it will not miss that weather info.
|
||||
*
|
||||
* Note that this will only set the start of transmitting weather of the
|
||||
* current day (and day temperature).
|
||||
*/
|
||||
time_t dcf77_start_weather(time_t timestamp, int region, int offset)
|
||||
{
|
||||
int hour, min;
|
||||
|
||||
/* hour+min at UTC */
|
||||
if (region < 60) {
|
||||
/* first dataset starts at 22:00 UTC */
|
||||
hour = (22 + region / 20) % 24;
|
||||
} else {
|
||||
/* seventh dataset starts at 19:00 UTC */
|
||||
hour = (19 + (region - 60) / 20) % 24;
|
||||
}
|
||||
min = (region % 20) * 3;
|
||||
PDEBUG(DDCF77, DEBUG_INFO, "Setting UTC time for region %d to %02d:%02d minutes.\n", region, hour, min);
|
||||
|
||||
/* reset to 0:00 UTC at same day */
|
||||
timestamp -= (timestamp % 86400);
|
||||
|
||||
/* add time to start */
|
||||
timestamp += hour * 3600 + min * 60;
|
||||
|
||||
/* substract offset */
|
||||
PDEBUG(DDCF77, DEBUG_INFO, "Setting timestamp offset to %d minutes.\n", offset);
|
||||
timestamp -= 60 * offset;
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/* set weather to transmit on all regions */
|
||||
void dcf77_set_weather(dcf77_t *dcf77, int weather_day, int weather_night, int extreme, int rain, int wind_dir, int wind_bft, int temperature_day, int temperature_night)
|
||||
{
|
||||
dcf77_tx_t *tx = &dcf77->tx;
|
||||
double now;
|
||||
time_t t;
|
||||
|
||||
/* get time stamp */
|
||||
if (timestamp < 0)
|
||||
now = get_time();
|
||||
tx->weather = 1;
|
||||
tx->weather_day = weather_day;
|
||||
tx->weather_night = weather_night;
|
||||
tx->rain = rain;
|
||||
tx->extreme = extreme;
|
||||
tx->wind_dir = wind_dir;
|
||||
tx->wind_bft = wind_bft;
|
||||
tx->temperature_day = temperature_day;
|
||||
tx->temperature_night = temperature_night;
|
||||
}
|
||||
|
||||
/* generate weather frame from weather data */
|
||||
static uint64_t generate_weather(time_t timestamp, int minute, int utc_hour, int weather_day, int weather_night, int extreme, int rain, int wind_dir, int wind_bft, int temperature_day, int temperature_night)
|
||||
{
|
||||
int dataset = ((utc_hour + 2) % 24) * 20 + (minute / 3); /* data sets since 22:00 UTC */
|
||||
struct tm *tm;
|
||||
uint64_t key;
|
||||
uint32_t weather;
|
||||
int value, temperature;
|
||||
int i;
|
||||
int best, diff;
|
||||
|
||||
/* generate key from time stamp of next minute */
|
||||
timestamp += 60;
|
||||
tm = localtime(×tamp);
|
||||
key = 0;
|
||||
key |= (uint64_t)(tm->tm_min % 10) << 0;
|
||||
key |= (uint64_t)(tm->tm_min / 10) << 4;
|
||||
key |= (uint64_t)(tm->tm_hour % 10) << 8;
|
||||
key |= (uint64_t)(tm->tm_hour / 10) << 12;
|
||||
key |= (uint64_t)(tm->tm_mday % 10) << 16;
|
||||
key |= (uint64_t)(tm->tm_mday / 10) << 20;
|
||||
key |= (uint64_t)((tm->tm_mon + 1) % 10) << 24;
|
||||
key |= (uint64_t)((tm->tm_mon + 1) / 10) << 28;
|
||||
if (tm->tm_wday > 0)
|
||||
key |= (uint64_t)(tm->tm_wday) << 29;
|
||||
else
|
||||
now = timestamp;
|
||||
t = floor(now);
|
||||
key |= (uint64_t)(7) << 29;
|
||||
key |= (uint64_t)(tm->tm_year % 10) << 32;
|
||||
key |= (uint64_t)((tm->tm_year / 10) % 10) << 36;
|
||||
|
||||
/* generate weather data */
|
||||
timestamp -= 120;
|
||||
weather = 0;
|
||||
PDEBUG(DFRAME, DEBUG_INFO, "Encoding weather for dataset %d/480\n", dataset);
|
||||
printf("Peparing Weather INFO\n");
|
||||
printf("---------------------\n");
|
||||
printf("Time (UTC): %02d:%02d\n", (int)(timestamp / 3600) % 24, (int)(timestamp / 60) % 60);
|
||||
/* dataset and region for 0..59 */
|
||||
printf("Dataset: %s\n", datasets_0_59[dataset / 60]);
|
||||
value = dataset % 60;
|
||||
printf("Region: %d = %s\n", value, region[value]);
|
||||
/* calc. weather of region */
|
||||
if (weather_day < 0 || weather_day > 15)
|
||||
weather_day = 1;
|
||||
weather |= weather_day << 0;
|
||||
if (weather_night < 0 || weather_night > 15)
|
||||
weather_night = 1;
|
||||
weather |= weather_night << 4;
|
||||
/* calc. temperature of region 0..59 (day/night) or region 60..89 (day) */
|
||||
if (((dataset / 60) & 1) == 0 || (dataset / 60) == 7)
|
||||
temperature = temperature_day + 22;
|
||||
else
|
||||
temperature = temperature_night + 22;
|
||||
if (temperature < 0)
|
||||
temperature = 0;
|
||||
if (temperature > 63)
|
||||
value = 63;
|
||||
weather |= temperature << 16;
|
||||
/* show weather of region 0..59 */
|
||||
if ((dataset / 60) < 7) {
|
||||
printf("Weather (day): %s = %s\n", show_bits(weather_day, 4), weathers_day[weather_day]);
|
||||
printf("Weather (night): %s = %s\n", show_bits(weather_night, 4), weathers_night[weather_night]);
|
||||
}
|
||||
/* show extreme/wind/rain of region 0..59 */
|
||||
if (((dataset / 60) & 1) == 0) {
|
||||
/* even datasets, this is 'Day' data */
|
||||
if (extreme < 0 || extreme > 15)
|
||||
value = 0;
|
||||
else
|
||||
value = extreme;
|
||||
printf("Extreme weather: %s = %s\n", show_bits(value, 4), extremeweathers[value]);
|
||||
weather |= value << 8;
|
||||
best = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
diff = abs(atoi(probabilities[i]) - rain);
|
||||
if (i == 0 || diff < best) {
|
||||
best = diff;
|
||||
value = i;
|
||||
}
|
||||
}
|
||||
printf("Rain Probability: %s = %s (best match for %d)\n", show_bits(value, 3), probabilities[value], rain);
|
||||
weather |= value << 12;
|
||||
value = 0;
|
||||
printf("Anomaly: %s = %s\n", show_bits(value, 1), yesno[value]);
|
||||
weather |= value << 15;
|
||||
display_weather_temperature("Temperature (day): ", weather);
|
||||
} else {
|
||||
/* odd datasets, this is 'Night' data */
|
||||
if (wind_dir < 0 || wind_dir > 15)
|
||||
value = 8;
|
||||
else
|
||||
value = wind_dir;
|
||||
printf("Wind direction: %s = %s\n", show_bits(value, 4), winddirections[value]);
|
||||
weather |= value << 8;
|
||||
if (wind_bft < 1)
|
||||
value = 0;
|
||||
else
|
||||
if (wind_bft < 7)
|
||||
value = (wind_bft + 1) / 2;
|
||||
else
|
||||
if (wind_bft < 10)
|
||||
value = wind_bft - 3;
|
||||
else
|
||||
value = 7;
|
||||
printf("Wind strength: %s = %s (best match for %d)\n", show_bits(value, 3), windstrengths[value], wind_bft);
|
||||
weather |= value << 12;
|
||||
value = 0;
|
||||
printf("Anomaly: %s = %s\n", show_bits(value, 1), yesno[value]);
|
||||
weather |= value << 15;
|
||||
value = temperature_night + 22;
|
||||
if (value < 0)
|
||||
value = 0;
|
||||
if (value > 63)
|
||||
value = 63;
|
||||
weather |= value << 16;
|
||||
if ((dataset / 60) < 7)
|
||||
display_weather_temperature("Temperature (night): ", weather);
|
||||
}
|
||||
/* show weather and temperature of of region 60..89 */
|
||||
if ((dataset / 60) == 7) {
|
||||
printf("Dataset: %s\n", 60 + datasets_60_89[(dataset % 60) / 30]);
|
||||
value = 60 + (dataset % 30);
|
||||
printf("Region: %d = %s\n", value, region[value]);
|
||||
printf("Weather (day): %s = %s\n", show_bits(weather_day, 4), weathers_day[weather_day]);
|
||||
printf("Weather (night): %s = %s\n", show_bits(weather_night, 4), weathers_night[weather_night]);
|
||||
display_weather_temperature("Temperature: ", weather);
|
||||
}
|
||||
|
||||
/* the magic '10' bit string */
|
||||
weather |= 0x1 << 22;
|
||||
|
||||
/* encode */
|
||||
return weather_encode(weather, key);
|
||||
}
|
||||
|
||||
/* transmit chunk of weather data for each minute */
|
||||
static uint16_t tx_weather(dcf77_tx_t *tx, time_t timestamp, int minute, int hour, int zone)
|
||||
{
|
||||
int index = (minute + 2) % 3;
|
||||
int utc_hour;
|
||||
uint16_t chunk;
|
||||
|
||||
if (index == 0) {
|
||||
/* convert hour to UTC */
|
||||
utc_hour = hour - 1;
|
||||
if (zone & 1)
|
||||
utc_hour--;
|
||||
if (utc_hour < 0)
|
||||
utc_hour += 24;
|
||||
/* in index 0 we transmit minute + 1 (next minute), so we substract 1 */
|
||||
tx->weather_cipher = generate_weather(timestamp, (minute + 59) % 60, utc_hour, tx->weather_day, tx->weather_night, tx->extreme, tx->rain, tx->wind_dir, tx->wind_bft, tx->temperature_day, tx->temperature_night);
|
||||
PDEBUG(DFRAME, DEBUG_INFO, "Transmitting first chunk of weather info.\n");
|
||||
chunk = (tx->weather_cipher & 0x3f) << 1; /* bit 2-7 */
|
||||
chunk |= (tx->weather_cipher & 0x0fc0) << 2; /* bit 9-14 */
|
||||
tx->weather_cipher >>= 12;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
PDEBUG(DFRAME, DEBUG_INFO, "Transmitting %s chunk of weather info.\n", (index == 1) ? "second" : "third");
|
||||
chunk = tx->weather_cipher & 0x3fff;
|
||||
tx->weather_cipher >>= 14;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/* set inital time stamp at the moment the stream starts */
|
||||
void dcf77_tx_start(dcf77_t *dcf77, time_t timestamp, double sub_sec)
|
||||
{
|
||||
dcf77_tx_t *tx = &dcf77->tx;
|
||||
|
||||
/* current second within minute */
|
||||
tx->second = t % 60;
|
||||
tx->second = timestamp % 60;
|
||||
/* time stamp of next minute */
|
||||
tx->timestamp = t - tx->second + 60;
|
||||
tx->timestamp = timestamp - tx->second + 60;
|
||||
/* wave within current second */
|
||||
tx->wave = floor(fmod(now, 1.0) * (double)tx->waves_sec);
|
||||
tx->wave = sub_sec * (double)tx->waves_sec;
|
||||
/* silence until next second begins */
|
||||
tx->symbol = 'm'; tx->level = 0;
|
||||
}
|
||||
|
||||
/* transmit one symbol = one second */
|
||||
static char tx_symbol(dcf77_t *dcf77, time_t timestamp, int second)
|
||||
{
|
||||
dcf77_tx_t *tx = &dcf77->tx;
|
||||
char symbol;
|
||||
int i, j;
|
||||
|
||||
/* generate frame */
|
||||
if (second == 0 || !tx->data_frame) {
|
||||
|
@ -205,18 +735,19 @@ static char tx_symbol(dcf77_t *dcf77, time_t timestamp, int second)
|
|||
int isdst_next_hour, wday, zone;
|
||||
uint64_t frame = 0, p;
|
||||
|
||||
/* get DST next hour */
|
||||
timestamp += 3600;
|
||||
tm = localtime(×tamp);
|
||||
timestamp -= 3600;
|
||||
if (!tm) {
|
||||
error_tm:
|
||||
PDEBUG(DDCF77, DEBUG_ERROR, "Failed to get local time of time stamp!\n");
|
||||
return 'm';
|
||||
}
|
||||
isdst_next_hour = tm->tm_isdst;
|
||||
tm = localtime(×tamp);
|
||||
if (!tm)
|
||||
goto error_tm;
|
||||
|
||||
/* get weather data */
|
||||
if (tx->weather) {
|
||||
frame |= tx_weather(tx, timestamp, tm->tm_min, tm->tm_hour, (tm->tm_isdst > 0) ? 1 : 2) << 1;
|
||||
/* calling tx_weather() destroys tm, because it is a pointer to a global variable. now we fix it */
|
||||
tm = localtime(×tamp);
|
||||
}
|
||||
|
||||
if (tm->tm_wday > 0)
|
||||
wday = tm->tm_wday;
|
||||
|
@ -228,7 +759,7 @@ error_tm:
|
|||
else
|
||||
zone = 2;
|
||||
|
||||
PDEBUG(DDCF77, DEBUG_NOTICE, "The time transmitting: %s %s %d %02d:%02d:00 %s %02d\n", week_day[wday], month_name[tm->tm_mon + 1], tm->tm_mday, tm->tm_hour, tm->tm_min, time_zone[zone], tm->tm_year + 1900);
|
||||
PDEBUG(DDCF77, DEBUG_NOTICE, "The time transmitting: %s %s %d %02d:%02d:%02d %s %02d\n", week_day[wday], month_name[tm->tm_mon + 1], tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, time_zone[zone], tm->tm_year + 1900);
|
||||
|
||||
if ((tm->tm_isdst > 0) != (isdst_next_hour > 0))
|
||||
frame |= (uint64_t)1 << 16;
|
||||
|
@ -270,19 +801,40 @@ error_tm:
|
|||
frame |= (uint64_t)(p & 1) << 58;
|
||||
|
||||
tx->data_frame = frame;
|
||||
|
||||
for (i = 0, j = 0; i < 59; i++) {
|
||||
if (i == 1 || i == 15 || i == 21 || i == 29 || i == 36 || i == 42 || i == 45 || i == 50)
|
||||
tx->data_string[j++] = ' ';
|
||||
tx->data_string[j++] = '0' + ((frame >> i) & 1);
|
||||
}
|
||||
tx->data_string[j] = '\0';
|
||||
PDEBUG(DDSP, DEBUG_INFO, "Start transmission of frame:\n");
|
||||
PDEBUG(DDSP, DEBUG_INFO, "0 Wetterdaten Info 1 Minute P StundeP Tag WoT Monat Jahr P\n");
|
||||
PDEBUG(DDSP, DEBUG_INFO, "%s\n", tx->data_string);
|
||||
}
|
||||
|
||||
if (second == 59)
|
||||
symbol = 'm';
|
||||
else symbol = ((tx->data_frame >> second) & 1) + '0';
|
||||
else
|
||||
symbol = ((tx->data_frame >> second) & 1) + '0';
|
||||
|
||||
PDEBUG(DDSP, DEBUG_DEBUG, "Trasmitting symbol '%c' (Bit %d)\n", symbol, second);
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
static void rx_symbol(dcf77_t *dcf77, char symbol);
|
||||
|
||||
/* encode one minute */
|
||||
void dcf77_encode(dcf77_t *dcf77, sample_t *samples, int length)
|
||||
{
|
||||
#ifdef DEBUG_LOOP
|
||||
/* mute and speed up by factor 20 */
|
||||
memset(samples, 0, sizeof(*samples) * length);
|
||||
sample_t test_sample[length * 20];
|
||||
samples = test_sample;
|
||||
|