DCF77: Add weather info decoding and coding
This commit is contained in:
parent
5ae64a2712
commit
616a5e2820
2
README
2
README
|
@ -28,7 +28,7 @@ Additionally the following communication services are implemented:
|
||||||
* German classic 'Zeitansage' (talking clock)
|
* German classic 'Zeitansage' (talking clock)
|
||||||
* POCSAG transmitter / receiver
|
* POCSAG transmitter / receiver
|
||||||
* Golay/GSC 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 SIM emulator
|
||||||
* C-Netz magnetic card emulator
|
* C-Netz magnetic card emulator
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,7 @@ Additional features:
|
||||||
<li>POCSAG (paging system)</li>
|
<li>POCSAG (paging system)</li>
|
||||||
<li>Golay / GSC (paging system)</li>
|
<li>Golay / GSC (paging system)</li>
|
||||||
<li>5-Ton-Ruf (firefighter's pagers and siren control)</li>
|
<li>5-Ton-Ruf (firefighter's pagers and siren control)</li>
|
||||||
|
<li>DCF77 The German longwave time signal transmitter/receiver</li>
|
||||||
</ul>
|
</ul>
|
||||||
</td></tr></table></center>
|
</td></tr></table></center>
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ bin_PROGRAMS = \
|
||||||
|
|
||||||
dcf77_SOURCES = \
|
dcf77_SOURCES = \
|
||||||
dcf77.c \
|
dcf77.c \
|
||||||
|
weather.c \
|
||||||
|
cities.c \
|
||||||
|
image.c \
|
||||||
main.c
|
main.c
|
||||||
dcf77_LDADD = \
|
dcf77_LDADD = \
|
||||||
$(COMMON_LA) \
|
$(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>
|
* (C) 2022 by Andreas Eversberg <jolly@eversberg.eu>
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "../libdebug/debug.h"
|
#include "../libdebug/debug.h"
|
||||||
#include "dcf77.h"
|
#include "dcf77.h"
|
||||||
|
#include "weather.h"
|
||||||
|
|
||||||
double get_time(void);
|
double get_time(void);
|
||||||
|
|
||||||
|
@ -35,7 +36,6 @@ double get_time(void);
|
||||||
#define TEST_FREQUENCY 1000
|
#define TEST_FREQUENCY 1000
|
||||||
#define CARRIER_BANDWIDTH 10.0
|
#define CARRIER_BANDWIDTH 10.0
|
||||||
#define SAMPLE_CLOCK 1000
|
#define SAMPLE_CLOCK 1000
|
||||||
#define CLOCK_1S 1.0
|
|
||||||
#define CLOCK_BANDWIDTH 0.1
|
#define CLOCK_BANDWIDTH 0.1
|
||||||
#define REDUCTION_FACTOR 0.15
|
#define REDUCTION_FACTOR 0.15
|
||||||
#define REDUCTION_TH 0.575
|
#define REDUCTION_TH 0.575
|
||||||
|
@ -43,6 +43,9 @@ double get_time(void);
|
||||||
|
|
||||||
#define level2db(level) (20 * log10(level))
|
#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 int fast_math = 0;
|
||||||
static float *sin_tab = NULL, *cos_tab = NULL;
|
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 *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 *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 */
|
/* global init */
|
||||||
int dcf77_init(int _fast_math)
|
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_create(int samplerate, int use_tx, int use_rx, int test_tone)
|
||||||
{
|
{
|
||||||
dcf77_t *dcf77 = NULL;
|
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_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_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_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)
|
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)
|
if (rx->enable)
|
||||||
PDEBUG(DDCF77, DEBUG_INFO, "DCF77 receiver has been created.\n");
|
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;
|
return dcf77;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* instance destruction */
|
||||||
void dcf77_destroy(dcf77_t *dcf77)
|
void dcf77_destroy(dcf77_t *dcf77)
|
||||||
{
|
{
|
||||||
if (dcf77) {
|
if (dcf77) {
|
||||||
|
@ -171,33 +470,264 @@ void dcf77_destroy(dcf77_t *dcf77)
|
||||||
PDEBUG(DDCF77, DEBUG_INFO, "DCF77 has been destroyed.\n");
|
PDEBUG(DDCF77, DEBUG_INFO, "DCF77 has been destroyed.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set inital time stamp at the moment the stream starts */
|
static void display_weather_temperature(const char *desc, uint32_t weather)
|
||||||
void dcf77_tx_start(dcf77_t *dcf77, time_t timestamp)
|
{
|
||||||
|
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;
|
dcf77_tx_t *tx = &dcf77->tx;
|
||||||
double now;
|
|
||||||
time_t t;
|
|
||||||
|
|
||||||
/* get time stamp */
|
tx->weather = 1;
|
||||||
if (timestamp < 0)
|
tx->weather_day = weather_day;
|
||||||
now = get_time();
|
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
|
else
|
||||||
now = timestamp;
|
key |= (uint64_t)(7) << 29;
|
||||||
t = floor(now);
|
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 */
|
/* current second within minute */
|
||||||
tx->second = t % 60;
|
tx->second = timestamp % 60;
|
||||||
/* time stamp of next minute */
|
/* time stamp of next minute */
|
||||||
tx->timestamp = t - tx->second + 60;
|
tx->timestamp = timestamp - tx->second + 60;
|
||||||
/* wave within current second */
|
/* 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 */
|
/* silence until next second begins */
|
||||||
tx->symbol = 'm'; tx->level = 0;
|
tx->symbol = 'm'; tx->level = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* transmit one symbol = one second */
|
||||||
static char tx_symbol(dcf77_t *dcf77, time_t timestamp, int second)
|
static char tx_symbol(dcf77_t *dcf77, time_t timestamp, int second)
|
||||||
{
|
{
|
||||||
dcf77_tx_t *tx = &dcf77->tx;
|
dcf77_tx_t *tx = &dcf77->tx;
|
||||||
char symbol;
|
char symbol;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
/* generate frame */
|
/* generate frame */
|
||||||
if (second == 0 || !tx->data_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;
|
int isdst_next_hour, wday, zone;
|
||||||
uint64_t frame = 0, p;
|
uint64_t frame = 0, p;
|
||||||
|
|
||||||
|
/* get DST next hour */
|
||||||
timestamp += 3600;
|
timestamp += 3600;
|
||||||
tm = localtime(×tamp);
|
tm = localtime(×tamp);
|
||||||
timestamp -= 3600;
|
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;
|
isdst_next_hour = tm->tm_isdst;
|
||||||
tm = localtime(×tamp);
|
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)
|
if (tm->tm_wday > 0)
|
||||||
wday = tm->tm_wday;
|
wday = tm->tm_wday;
|
||||||
|
@ -228,7 +759,7 @@ error_tm:
|
||||||
else
|
else
|
||||||
zone = 2;
|
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))
|
if ((tm->tm_isdst > 0) != (isdst_next_hour > 0))
|
||||||
frame |= (uint64_t)1 << 16;
|
frame |= (uint64_t)1 << 16;
|
||||||
|
@ -270,19 +801,40 @@ error_tm:
|
||||||
frame |= (uint64_t)(p & 1) << 58;
|
frame |= (uint64_t)(p & 1) << 58;
|
||||||
|
|
||||||
tx->data_frame = frame;
|
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)
|
if (second == 59)
|
||||||
symbol = 'm';
|
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);
|
PDEBUG(DDSP, DEBUG_DEBUG, "Trasmitting symbol '%c' (Bit %d)\n", symbol, second);
|
||||||
|
|
||||||
return symbol;
|
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)
|
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;
|
||||||
|
length *= 20;
|
||||||
|
#endif
|
||||||
dcf77_tx_t *tx = &dcf77->tx;
|
dcf77_tx_t *tx = &dcf77->tx;
|
||||||
double carrier_phase, test_phase;
|
double carrier_phase, test_phase;
|
||||||
int i;
|
int i;
|
||||||
|
@ -310,6 +862,9 @@ void dcf77_encode(dcf77_t *dcf77, sample_t *samples, int length)
|
||||||
tx->timestamp += 60;
|
tx->timestamp += 60;
|
||||||
}
|
}
|
||||||
tx->symbol = tx_symbol(dcf77, tx->timestamp, tx->second);
|
tx->symbol = tx_symbol(dcf77, tx->timestamp, tx->second);
|
||||||
|
#ifdef DEBUG_LOOP
|
||||||
|
rx_symbol(dcf77, tx->symbol);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
switch (tx->symbol) {
|
switch (tx->symbol) {
|
||||||
case '0':
|
case '0':
|
||||||
|
@ -345,7 +900,146 @@ void dcf77_encode(dcf77_t *dcf77, sample_t *samples, int length)
|
||||||
tx->test_phase = test_phase;
|
tx->test_phase = test_phase;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rx_frame(uint64_t frame)
|
/*
|
||||||
|
* RX part
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* display weather data from weather frame */
|
||||||
|
static void display_weather(uint32_t weather, int minute, int utc_hour)
|
||||||
|
{
|
||||||
|
int dataset = ((utc_hour + 2) % 24) * 20 + (minute / 3); /* data sets since 22:00 UTC */
|
||||||
|
int value;
|
||||||
|
|
||||||
|
PDEBUG(DFRAME, DEBUG_INFO, "Decoding weather for dataset %d/480\n", dataset);
|
||||||
|
printf("Received Weather INFO\n");
|
||||||
|
printf("---------------------\n");
|
||||||
|
printf("Time (UTC): %02d:%02d\n", utc_hour, minute);
|
||||||
|
printf("Dataset: %s\n", datasets_0_59[dataset / 60]);
|
||||||
|
value = dataset % 60;
|
||||||
|
printf("Region: %d = %s\n", value, region[value]);
|
||||||
|
if ((dataset / 60) < 7) {
|
||||||
|
value = (weather >> 0) & 0xf;
|
||||||
|
printf("Weather (day): %s = %s\n", show_bits(value, 4), weathers_day[value]);
|
||||||
|
value = (weather >> 4) & 0xf;
|
||||||
|
printf("Weather (night): %s = %s\n", show_bits(value, 4), weathers_night[value]);
|
||||||
|
}
|
||||||
|
if (((dataset / 60) & 1) == 0) {
|
||||||
|
/* even datasets, this is 'Day' data */
|
||||||
|
if (((weather >> 15) & 1) == 0) {
|
||||||
|
value = (weather >> 8) & 0xf;
|
||||||
|
printf("Extreme weather: %s = %s\n", show_bits(value, 4), extremeweathers[value]);
|
||||||
|
} else {
|
||||||
|
value = (weather >> 8) & 0x3;
|
||||||
|
printf("Relative weather: %s = %s\n", show_bits(value, 2), anomaly1[value]);
|
||||||
|
value = (weather >> 10) & 0x3;
|
||||||
|
printf("Sunshine: %s = %s\n", show_bits(value, 2), anomaly1[value]);
|
||||||
|
}
|
||||||
|
value = (weather >> 12) & 0x7;
|
||||||
|
printf("Rain Probability: %s = %s\n", show_bits(value, 3), probabilities[value]);
|
||||||
|
value = (weather >> 15) & 0x1;
|
||||||
|
printf("Anomaly: %s = %s\n", show_bits(value, 1), yesno[value]);
|
||||||
|
display_weather_temperature("Temperature (day): ", weather);
|
||||||
|
} else {
|
||||||
|
/* odd datasets, this is 'Night' data */
|
||||||
|
if (((weather >> 15) & 1) == 0) {
|
||||||
|
value = (weather >> 8) & 0xf;
|
||||||
|
printf("Wind direction: %s = %s\n", show_bits(value, 4), winddirections[value]);
|
||||||
|
} else {
|
||||||
|
value = (weather >> 8) & 0x3;
|
||||||
|
printf("Relative weather: %s = %s\n", show_bits(value, 2), anomaly1[value]);
|
||||||
|
value = (weather >> 10) & 0x3;
|
||||||
|
printf("Sunshine: %s = %s\n", show_bits(value, 2), anomaly1[value]);
|
||||||
|
}
|
||||||
|
value = (weather >> 12) & 0x7;
|
||||||
|
printf("Wind strength: %s = %s\n", show_bits(value, 3), windstrengths[value]);
|
||||||
|
value = (weather >> 15) & 0x1;
|
||||||
|
printf("Anomaly: %s = %s\n", show_bits(value, 1), yesno[value]);
|
||||||
|
if ((dataset / 60) < 7)
|
||||||
|
display_weather_temperature("Temperature (night): ", weather);
|
||||||
|
}
|
||||||
|
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]);
|
||||||
|
value = (weather >> 0) & 0xf;
|
||||||
|
printf("Weather (day): %s = %s\n", show_bits(value, 4), weathers_day[value]);
|
||||||
|
value = (weather >> 4) & 0xf;
|
||||||
|
printf("Weather (night): %s = %s\n", show_bits(value, 4), weathers_night[value]);
|
||||||
|
display_weather_temperature("Temperature: ", weather);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset weather frame */
|
||||||
|
static void rx_weather_reset(dcf77_rx_t *rx)
|
||||||
|
{
|
||||||
|
rx->weather_index = 0;
|
||||||
|
rx->weather_cipher = 0;
|
||||||
|
rx->weather_key = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* receive weather chunk */
|
||||||
|
static void rx_weather(dcf77_rx_t *rx, int minute, int hour, int zone, uint64_t frame)
|
||||||
|
{
|
||||||
|
int index = (minute + 2) % 3;
|
||||||
|
int utc_hour;
|
||||||
|
int32_t weather;
|
||||||
|
|
||||||
|
if (rx->weather_index == 0 && index != 0) {
|
||||||
|
PDEBUG(DFRAME, DEBUG_INFO, "Skipping weather info chunk, waiting for new start of weather info.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
rx_weather_reset(rx);
|
||||||
|
rx->weather_cipher |= (frame >> 2) & 0x3f; /* bit 2-7 */
|
||||||
|
rx->weather_cipher |= (frame >> 3) & 0x0fc0; /* bit 9-14 */
|
||||||
|
rx->weather_index++;
|
||||||
|
if (((frame & 0x0002)) || ((frame & 0x0100)) || !rx->weather_cipher) {
|
||||||
|
PDEBUG(DFRAME, DEBUG_INFO, "There is no weather info in this received minute.\n");
|
||||||
|
rx_weather_reset(rx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PDEBUG(DFRAME, DEBUG_INFO, "Got first chunk of weather info.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rx->weather_index == 1 && index == 1) {
|
||||||
|
PDEBUG(DFRAME, DEBUG_INFO, "Got second chunk of weather info.\n");
|
||||||
|
rx->weather_cipher |= (frame << 11) & 0x3fff000; /* bit 1-14 */
|
||||||
|
rx->weather_key |= (frame >> 21) & 0x7f;
|
||||||
|
rx->weather_key |= ((frame >> 29) & 0x3f) << 8;
|
||||||
|
rx->weather_key |= ((frame >> 36) & 0x3f) << 16;
|
||||||
|
rx->weather_key |= ((frame >> 45) & 0x1f) << 24;
|
||||||
|
rx->weather_key |= ((frame >> 42) & 0x07) << 29;
|
||||||
|
rx->weather_key |= ((frame >> 50) & 0xff) << 32;
|
||||||
|
rx->weather_index++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rx->weather_index == 2 && index == 2) {
|
||||||
|
PDEBUG(DFRAME, DEBUG_INFO, "Got third chunk of weather info.\n");
|
||||||
|
rx->weather_cipher |= (frame << 25) & 0xfffc000000; /* bit 1-14 */
|
||||||
|
weather = weather_decode(rx->weather_cipher, rx->weather_key);
|
||||||
|
if (weather < 0)
|
||||||
|
PDEBUG(DFRAME, DEBUG_NOTICE, "Failed to decrypt weather info, checksum error.\n");
|
||||||
|
else {
|
||||||
|
/* convert hour to UTC */
|
||||||
|
utc_hour = hour - 1;
|
||||||
|
if (zone & 1)
|
||||||
|
utc_hour--;
|
||||||
|
if (utc_hour < 0)
|
||||||
|
utc_hour += 24;
|
||||||
|
/* in index 2 we transmit minute + 3 (next minute), so we substract 3 */
|
||||||
|
display_weather(weather, (minute + 57) % 60, utc_hour);
|
||||||
|
}
|
||||||
|
rx_weather_reset(rx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_weather_reset(rx);
|
||||||
|
PDEBUG(DFRAME, DEBUG_INFO, "Got weather info chunk out of order, waiting for new start of weather info.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode time from received data */
|
||||||
|
static void rx_frame(dcf77_rx_t *rx, uint64_t frame)
|
||||||
{
|
{
|
||||||
int zone;
|
int zone;
|
||||||
int minute_one, minute_ten, minute = -1;
|
int minute_one, minute_ten, minute = -1;
|
||||||
|
@ -428,15 +1122,34 @@ static void rx_frame(uint64_t frame)
|
||||||
PDEBUG(DFRAME, DEBUG_INFO, "Year : %02d\n", year);
|
PDEBUG(DFRAME, DEBUG_INFO, "Year : %02d\n", year);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minute >= 0 && hour >= 0 && day >= 0 && wday >= 0 && month >= 0 && year >= 0)
|
if (minute >= 0 && hour >= 0 && day >= 0 && wday >= 0 && month >= 0 && year >= 0) {
|
||||||
PDEBUG(DDCF77, DEBUG_NOTICE, "The received time is: %s %s %d %02d:%02d:00 %s 20%02d\n", week_day[wday], month_name[month], day, hour, minute, time_zone[zone], year);
|
PDEBUG(DDCF77, DEBUG_NOTICE, "The received time is: %s %s %d %02d:%02d:00 %s 20%02d\n", week_day[wday], month_name[month], day, hour, minute, time_zone[zone], year);
|
||||||
else
|
rx_weather(rx, minute, hour, zone, frame);
|
||||||
|
} else {
|
||||||
PDEBUG(DDCF77, DEBUG_NOTICE, "The received time is invalid!\n");
|
PDEBUG(DDCF77, DEBUG_NOTICE, "The received time is invalid!\n");
|
||||||
|
rx_weather_reset(rx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* test routing for test data */
|
||||||
|
void rx_frame_test(dcf77_t *dcf77, const char *string)
|
||||||
|
{
|
||||||
|
uint64_t frame = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
puts(string);
|
||||||
|
for (i = 0; i < 59; i++) {
|
||||||
|
frame |= (uint64_t)(string[i] & 1) << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_frame(&dcf77->rx, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* receive one symbol = one second */
|
||||||
static void rx_symbol(dcf77_t *dcf77, char symbol)
|
static void rx_symbol(dcf77_t *dcf77, char symbol)
|
||||||
{
|
{
|
||||||
dcf77_rx_t *rx = &dcf77->rx;
|
dcf77_rx_t *rx = &dcf77->rx;
|
||||||
|
double second = -NAN;
|
||||||
|
|
||||||
PDEBUG(DDSP, DEBUG_DEBUG, "Received symbol '%c'\n", symbol);
|
PDEBUG(DDSP, DEBUG_DEBUG, "Received symbol '%c'\n", symbol);
|
||||||
|
|
||||||
|
@ -445,33 +1158,48 @@ static void rx_symbol(dcf77_t *dcf77, char symbol)
|
||||||
PDEBUG(DDSP, DEBUG_INFO, "Reception of frame has started\n");
|
PDEBUG(DDSP, DEBUG_INFO, "Reception of frame has started\n");
|
||||||
rx->data_receive = 1;
|
rx->data_receive = 1;
|
||||||
rx->data_index = 0;
|
rx->data_index = 0;
|
||||||
|
rx->string_index = 0;
|
||||||
|
second = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (symbol == 'm') {
|
if (symbol == 'm') {
|
||||||
if (rx->data_index == 59) {
|
if (rx->data_index == 59) {
|
||||||
rx->data_string[rx->data_index] = '\0';
|
rx->data_string[rx->string_index] = '\0';
|
||||||
rx->data_index = 0;
|
rx->data_index = 0;
|
||||||
PDEBUG(DDSP, DEBUG_INFO, "Received complete frame: %s (0x%016" PRIx64 ")\n", rx->data_string, rx->data_frame);
|
rx->string_index = 0;
|
||||||
rx_frame(rx->data_frame);
|
PDEBUG(DDSP, DEBUG_INFO, "Received complete 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", rx->data_string);
|
||||||
|
rx_frame(rx, rx->data_frame);
|
||||||
|
second = 0;
|
||||||
} else {
|
} else {
|
||||||
PDEBUG(DDSP, DEBUG_INFO, "Short read, frame too short\n");
|
PDEBUG(DDSP, DEBUG_INFO, "Short read, frame too short\n");
|
||||||
rx->data_index = 0;
|
rx->data_index = 0;
|
||||||
|
rx->string_index = 0;
|
||||||
|
rx_weather_reset(rx);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (rx->data_index == 59) {
|
if (rx->data_index == 59) {
|
||||||
PDEBUG(DDSP, DEBUG_INFO, "Long read, frame too long\n");
|
PDEBUG(DDSP, DEBUG_INFO, "Long read, frame too long\n");
|
||||||
rx->data_receive = 0;
|
rx->data_receive = 0;
|
||||||
|
rx_weather_reset(rx);
|
||||||
} else {
|
} else {
|
||||||
rx->data_string[rx->data_index++] = symbol;
|
if (rx->data_index == 1 || rx->data_index == 15 || rx->data_index == 21 || rx->data_index == 29 || rx->data_index == 36 || rx->data_index == 42 || rx->data_index == 45 || rx->data_index == 50)
|
||||||
|
rx->data_string[rx->string_index++] = ' ';
|
||||||
|
rx->data_string[rx->string_index++] = symbol;
|
||||||
|
rx->data_index++;
|
||||||
rx->data_frame >>= 1;
|
rx->data_frame >>= 1;
|
||||||
rx->data_frame |= (uint64_t)(symbol & 1) << 58;
|
rx->data_frame |= (uint64_t)(symbol & 1) << 58;
|
||||||
|
second = rx->data_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
display_measurements_update(dcf77->dmp_current_second, second, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#define DEBUG_SAMPLE
|
//#define DEBUG_SAMPLE
|
||||||
|
|
||||||
|
/* decode radio wave and extract each bit / second */
|
||||||
void dcf77_decode(dcf77_t *dcf77, sample_t *samples, int length)
|
void dcf77_decode(dcf77_t *dcf77, sample_t *samples, int length)
|
||||||
{
|
{
|
||||||
dcf77_rx_t *rx = &dcf77->rx;
|
dcf77_rx_t *rx = &dcf77->rx;
|
||||||
|
@ -481,6 +1209,9 @@ void dcf77_decode(dcf77_t *dcf77, sample_t *samples, int length)
|
||||||
|
|
||||||
display_wave(&dcf77->dispwav, samples, length, 1.0);
|
display_wave(&dcf77->dispwav, samples, length, 1.0);
|
||||||
|
|
||||||
|
#ifdef DEBUG_LOOP
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
if (!rx->enable)
|
if (!rx->enable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,18 @@ typedef struct dcf77_tx {
|
||||||
int second;
|
int second;
|
||||||
char symbol;
|
char symbol;
|
||||||
uint64_t data_frame;
|
uint64_t data_frame;
|
||||||
|
char data_string[100]; /* 60 digits + spaces + '\0' */
|
||||||
int test_tone;
|
int test_tone;
|
||||||
|
int weather;
|
||||||
|
int weather_day;
|
||||||
|
int weather_night;
|
||||||
|
int extreme;
|
||||||
|
int rain;
|
||||||
|
int wind_dir;
|
||||||
|
int wind_bft;
|
||||||
|
int temperature_day;
|
||||||
|
int temperature_night;
|
||||||
|
uint64_t weather_cipher;
|
||||||
} dcf77_tx_t;
|
} dcf77_tx_t;
|
||||||
|
|
||||||
typedef struct dcf77_rx {
|
typedef struct dcf77_rx {
|
||||||
|
@ -29,9 +40,12 @@ typedef struct dcf77_rx {
|
||||||
int clock_count;
|
int clock_count;
|
||||||
double value_level, value_short, value_long; /* measured values */
|
double value_level, value_short, value_long; /* measured values */
|
||||||
int data_receive, data_index;
|
int data_receive, data_index;
|
||||||
char data_string[60]; /* 59 digits + '\0' */
|
char data_string[100]; /* 60 digits + spaces + '\0' */
|
||||||
|
int string_index;
|
||||||
uint64_t data_frame;
|
uint64_t data_frame;
|
||||||
iir_filter_t clock_lp[2]; /* filters received carrier signal */
|
int weather_index;
|
||||||
|
uint64_t weather_cipher;
|
||||||
|
uint64_t weather_key;
|
||||||
} dcf77_rx_t;
|
} dcf77_rx_t;
|
||||||
|
|
||||||
typedef struct dcf77 {
|
typedef struct dcf77 {
|
||||||
|
@ -43,6 +57,7 @@ typedef struct dcf77 {
|
||||||
dispmeasparam_t *dmp_input_level;
|
dispmeasparam_t *dmp_input_level;
|
||||||
dispmeasparam_t *dmp_signal_level;
|
dispmeasparam_t *dmp_signal_level;
|
||||||
dispmeasparam_t *dmp_signal_quality;
|
dispmeasparam_t *dmp_signal_quality;
|
||||||
|
dispmeasparam_t *dmp_current_second;
|
||||||
|
|
||||||
/* wave */
|
/* wave */
|
||||||
dispwav_t dispwav; /* display wave form */
|
dispwav_t dispwav; /* display wave form */
|
||||||
|
@ -52,6 +67,10 @@ int dcf77_init(int _fast_math);
|
||||||
void dcf77_exit(void);
|
void dcf77_exit(void);
|
||||||
dcf77_t *dcf77_create(int samplerate, int use_tx, int use_rx, int test_tone);
|
dcf77_t *dcf77_create(int samplerate, int use_tx, int use_rx, int test_tone);
|
||||||
void dcf77_destroy(dcf77_t *dcf77);
|
void dcf77_destroy(dcf77_t *dcf77);
|
||||||
void dcf77_tx_start(dcf77_t *dcf77, time_t timestamp);
|
void dcf77_tx_start(dcf77_t *dcf77, time_t timestamp, double sub_sec);
|
||||||
void dcf77_encode(dcf77_t *dcf77, sample_t *samples, int length);
|
void dcf77_encode(dcf77_t *dcf77, sample_t *samples, int length);
|
||||||
void dcf77_decode(dcf77_t *dcf77, sample_t *samples, int length);
|
void dcf77_decode(dcf77_t *dcf77, sample_t *samples, int length);
|
||||||
|
|
||||||
|
void list_weather(void);
|
||||||
|
time_t dcf77_start_weather(time_t timestamp, int region, int offset);
|
||||||
|
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);
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
const char *aaimage[] = {
|
||||||
|
"",
|
||||||
|
"@W * DCF77 with weather info *",
|
||||||
|
"",
|
||||||
|
" @Y\\__/",
|
||||||
|
" @w_______@Y/ \\__",
|
||||||
|
" @w/ ____\\_@Y/@w_",
|
||||||
|
" \\___/@r10:08:33@w\\",
|
||||||
|
" @B/ @w\\________/",
|
||||||
|
" @B/ @W*@B/ @W*@B/ @W*@B/ @W*@B/",
|
||||||
|
" @W*@B/ @W*@B/ @W*@B/ @W*@B/",
|
||||||
|
"",
|
||||||
|
NULL
|
||||||
|
};
|
153
src/dcf77/main.c
153
src/dcf77/main.c
|
@ -27,11 +27,14 @@
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <math.h>
|
||||||
#include "../libdebug/debug.h"
|
#include "../libdebug/debug.h"
|
||||||
#include "../liboptions/options.h"
|
#include "../liboptions/options.h"
|
||||||
#include "../libsample/sample.h"
|
#include "../libsample/sample.h"
|
||||||
#include "../libsound/sound.h"
|
#include "../libsound/sound.h"
|
||||||
|
#include "../libaaimage/aaimage.h"
|
||||||
#include "dcf77.h"
|
#include "dcf77.h"
|
||||||
|
#include "cities.h"
|
||||||
|
|
||||||
int num_kanal = 1;
|
int num_kanal = 1;
|
||||||
dcf77_t *dcf77 = NULL;
|
dcf77_t *dcf77 = NULL;
|
||||||
|
@ -40,7 +43,17 @@ static const char *dsp_device = "";
|
||||||
static int dsp_samplerate = 192000;
|
static int dsp_samplerate = 192000;
|
||||||
static int dsp_buffer = 50;
|
static int dsp_buffer = 50;
|
||||||
static int rx = 0, tx = 0;
|
static int rx = 0, tx = 0;
|
||||||
static time_t timestamp = -1;
|
static double timestamp = -1;
|
||||||
|
static int weather = 0;
|
||||||
|
static int weather_day;
|
||||||
|
static int weather_night;
|
||||||
|
static int extreme;
|
||||||
|
static int rain;
|
||||||
|
static int wind_dir;
|
||||||
|
static int wind_bft;
|
||||||
|
static int temperature_day;
|
||||||
|
static int temperature_night;
|
||||||
|
static int region = -1, region_advance;
|
||||||
static int double_amplitude = 0;
|
static int double_amplitude = 0;
|
||||||
static int test_tone = 0;
|
static int test_tone = 0;
|
||||||
static int dsp_interval = 1; /* ms */
|
static int dsp_interval = 1; /* ms */
|
||||||
|
@ -110,8 +123,6 @@ static time_t feierabend_time()
|
||||||
|
|
||||||
t = get_time();
|
t = get_time();
|
||||||
tm = localtime(&t);
|
tm = localtime(&t);
|
||||||
if (!tm)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
tm->tm_hour = 17;
|
tm->tm_hour = 17;
|
||||||
tm->tm_min = 0;
|
tm->tm_min = 0;
|
||||||
|
@ -148,7 +159,7 @@ void print_help(void)
|
||||||
printf(" -R --rx\n");
|
printf(" -R --rx\n");
|
||||||
printf(" Receive time signal\n");
|
printf(" Receive time signal\n");
|
||||||
printf(" -F --fake\n");
|
printf(" -F --fake\n");
|
||||||
printf(" Use given time stamp: <year> <month> <day> <hour> <min< <sec>.\n");
|
printf(" Use given time stamp: <year> <month> <day> <hour> <min> <sec>.\n");
|
||||||
printf(" All values have to be numerical. The year must have 4 digits.\n");
|
printf(" All values have to be numerical. The year must have 4 digits.\n");
|
||||||
printf(" --feierabend\n");
|
printf(" --feierabend\n");
|
||||||
printf(" --end-of-working-day\n");
|
printf(" --end-of-working-day\n");
|
||||||
|
@ -156,6 +167,29 @@ void print_help(void)
|
||||||
printf(" --geburtstag\n");
|
printf(" --geburtstag\n");
|
||||||
printf(" --birthday\n");
|
printf(" --birthday\n");
|
||||||
printf(" Use fake time stamp that equals birth of the author.\n");
|
printf(" Use fake time stamp that equals birth of the author.\n");
|
||||||
|
printf(" -W --weather <weather> <extreme> <rain> <wind dir> <wind bft> <temperature>\n");
|
||||||
|
printf(" Send these weather info for all regions / all days.\n");
|
||||||
|
printf(" See -L for infos on values.\n");
|
||||||
|
printf(" weather = 1..15 for common day and night weather.\n");
|
||||||
|
printf(" weather = 1..15,1..15 for specific day and night weather.\n");
|
||||||
|
printf(" extreme = 0..15 for extreme weather conditions.\n");
|
||||||
|
printf(" rain = 0..100 for rain/show probability. (closest is used)\n");
|
||||||
|
printf(" wind dir = N | NE | E | SE | S | SW | W | NW | 0 for wind direction.\n");
|
||||||
|
printf(" wind bft = <bft> for wind speed in bft. (closest is used)\n");
|
||||||
|
printf(" temerature = <celsius> for common min and max temperature.\n");
|
||||||
|
printf(" temerature = <celsius>,<celsius> for specific min and max temperature.\n");
|
||||||
|
printf(" --beach-party\n");
|
||||||
|
printf(" Beach weather, equivalent to -W 1 0 0 0 2 35,20\n");
|
||||||
|
printf(" --santa-claus\n");
|
||||||
|
printf(" --muenster-2005\n");
|
||||||
|
printf(" Deep snow, equivalent to -W 7 1 100 E 3 1,-1\n");
|
||||||
|
printf(" -A --at-region <region> <advance minutes>\n");
|
||||||
|
printf(" Alter time, so that the weather of the given region is transmitted.\n");
|
||||||
|
printf(" To allow the receiver to sync, give time to advance in minutes.\n");
|
||||||
|
printf(" -L --list\n");
|
||||||
|
printf(" List all regions / weather values.\n");
|
||||||
|
printf(" -C --city <name fragment>\n");
|
||||||
|
printf(" Search for city (case insensitive) and display its region code.\n");
|
||||||
printf(" -D --double-amplitude\n");
|
printf(" -D --double-amplitude\n");
|
||||||
printf(" Transmit with double amplitude by using differential stereo output.\n");
|
printf(" Transmit with double amplitude by using differential stereo output.\n");
|
||||||
printf(" --test-tone\n");
|
printf(" --test-tone\n");
|
||||||
|
@ -173,8 +207,11 @@ void print_help(void)
|
||||||
#define OPT_F2 1002
|
#define OPT_F2 1002
|
||||||
#define OPT_G1 1003
|
#define OPT_G1 1003
|
||||||
#define OPT_G2 1004
|
#define OPT_G2 1004
|
||||||
#define OPT_TEST_TONE 1005
|
#define OPT_BEACH 1005
|
||||||
#define OPT_FAST_MATH 1006
|
#define OPT_SANTA 1006
|
||||||
|
#define OPT_MUENSTER 1007
|
||||||
|
#define OPT_TEST_TONE 1008
|
||||||
|
#define OPT_FAST_MATH 1009
|
||||||
|
|
||||||
static void add_options(void)
|
static void add_options(void)
|
||||||
{
|
{
|
||||||
|
@ -190,15 +227,25 @@ static void add_options(void)
|
||||||
option_add(OPT_F2, "end-of-working-day", 0);
|
option_add(OPT_F2, "end-of-working-day", 0);
|
||||||
option_add(OPT_G1, "geburtstag", 0);
|
option_add(OPT_G1, "geburtstag", 0);
|
||||||
option_add(OPT_G2, "birthday", 0);
|
option_add(OPT_G2, "birthday", 0);
|
||||||
option_add(OPT_TEST_TONE, "test-tone", 0);
|
option_add('W', "weather", 6);
|
||||||
|
option_add(OPT_BEACH, "beach-party", 0);
|
||||||
|
option_add(OPT_SANTA, "santa-claus", 0);
|
||||||
|
option_add(OPT_MUENSTER, "muenster-2005", 0);
|
||||||
|
option_add('A', "at-region", 2);
|
||||||
|
option_add('L', "list", 0);
|
||||||
|
option_add('C', "city", 1);
|
||||||
option_add('D', "double-amplitude", 0);
|
option_add('D', "double-amplitude", 0);
|
||||||
|
option_add(OPT_TEST_TONE, "test-tone", 0);
|
||||||
option_add('r', "realtime", 1);
|
option_add('r', "realtime", 1);
|
||||||
option_add(OPT_FAST_MATH, "fast-math", 0);
|
option_add(OPT_FAST_MATH, "fast-math", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *wind_dirs[8] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW" };
|
||||||
|
|
||||||
static int handle_options(int short_option, int argi, char **argv)
|
static int handle_options(int short_option, int argi, char **argv)
|
||||||
{
|
{
|
||||||
int rc;
|
char *string, *string1;
|
||||||
|
int rc, i;
|
||||||
|
|
||||||
switch (short_option) {
|
switch (short_option) {
|
||||||
case 'h':
|
case 'h':
|
||||||
|
@ -233,7 +280,6 @@ static int handle_options(int short_option, int argi, char **argv)
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
timestamp = parse_time(argv + argi);
|
timestamp = parse_time(argv + argi);
|
||||||
printf("%ld\n",timestamp);
|
|
||||||
if (timestamp < 0) {
|
if (timestamp < 0) {
|
||||||
fprintf(stderr, "Given time stamp is invalid, please use -h for help.\n");
|
fprintf(stderr, "Given time stamp is invalid, please use -h for help.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -247,6 +293,79 @@ static int handle_options(int short_option, int argi, char **argv)
|
||||||
case OPT_G2:
|
case OPT_G2:
|
||||||
timestamp = 115099200 - 70;
|
timestamp = 115099200 - 70;
|
||||||
break;
|
break;
|
||||||
|
case 'W':
|
||||||
|
if (weather) {
|
||||||
|
no_multiple_weathers:
|
||||||
|
fprintf(stderr, "You cannot define more than one weather situation.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
weather = 1;
|
||||||
|
string = options_strdup(argv[argi++]);
|
||||||
|
string1 = strsep(&string, ",");
|
||||||
|
weather_day = atoi(string1);
|
||||||
|
if (string)
|
||||||
|
weather_night = atoi(string);
|
||||||
|
else
|
||||||
|
weather_night = weather_day;
|
||||||
|
extreme = atoi(argv[argi++]);
|
||||||
|
rain = atoi(argv[argi++]);
|
||||||
|
/* if wind is not found, wind 8 (changable) is selected */
|
||||||
|
string = options_strdup(argv[argi++]);
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
if (!strcasecmp(string, wind_dirs[i]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wind_dir = i;
|
||||||
|
wind_bft = atoi(argv[argi++]);
|
||||||
|
string = options_strdup(argv[argi++]);
|
||||||
|
string1 = strsep(&string, ",");
|
||||||
|
temperature_day = atoi(string1);
|
||||||
|
if (string)
|
||||||
|
temperature_night = atoi(string);
|
||||||
|
else
|
||||||
|
temperature_night = temperature_day;
|
||||||
|
break;
|
||||||
|
case OPT_BEACH:
|
||||||
|
if (weather)
|
||||||
|
goto no_multiple_weathers;
|
||||||
|
weather = 1;
|
||||||
|
weather_day = 1;
|
||||||
|
weather_night = 1;
|
||||||
|
extreme = 0;
|
||||||
|
rain = 0;
|
||||||
|
wind_dir = 8;
|
||||||
|
wind_bft = 2;
|
||||||
|
temperature_day = 35;
|
||||||
|
temperature_night = 20; /* tropical night >= 20 */
|
||||||
|
break;
|
||||||
|
case OPT_SANTA:
|
||||||
|
case OPT_MUENSTER:
|
||||||
|
if (weather)
|
||||||
|
goto no_multiple_weathers;
|
||||||
|
weather = 1;
|
||||||
|
weather_day = 7;
|
||||||
|
weather_night = 7;
|
||||||
|
extreme = 0;
|
||||||
|
rain = 100;
|
||||||
|
wind_dir = 6;
|
||||||
|
wind_bft = 3;
|
||||||
|
temperature_day = 1;
|
||||||
|
temperature_night = -1; /* freezing a little */
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
region = atoi(argv[argi++]);
|
||||||
|
if (region < 0 || region > 89) {
|
||||||
|
fprintf(stderr, "Given region number is is invalid, please use -L for list of valid regions.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
region_advance = atoi(argv[argi++]);
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
list_weather();
|
||||||
|
return 0;
|
||||||
|
case 'C':
|
||||||
|
display_city(argv[argi++]);
|
||||||
|
return 0;
|
||||||
case OPT_TEST_TONE:
|
case OPT_TEST_TONE:
|
||||||
test_tone = 1;
|
test_tone = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -407,8 +526,20 @@ int main(int argc, char *argv[])
|
||||||
fprintf(stderr, "Failed to create \"DCF77\" instance. Quitting!\n");
|
fprintf(stderr, "Failed to create \"DCF77\" instance. Quitting!\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if (weather)
|
||||||
|
dcf77_set_weather(dcf77, weather_day, weather_night, extreme, rain, wind_dir, wind_bft, temperature_day, temperature_night);
|
||||||
|
|
||||||
printf("\n");
|
/* no time stamp given, so we use our clock */
|
||||||
|
if (tx) {
|
||||||
|
if (timestamp < 0 && region < 0)
|
||||||
|
printf("No alternative time given, so you might not notice the difference between our transmission and the real DCF77 transmission.\n");
|
||||||
|
if (timestamp < 0)
|
||||||
|
timestamp = get_time();
|
||||||
|
if (region >= 0 && weather)
|
||||||
|
timestamp = dcf77_start_weather((time_t)timestamp, region, region_advance);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_aaimage();
|
||||||
printf("DCF77 ready.\n");
|
printf("DCF77 ready.\n");
|
||||||
|
|
||||||
/* prepare terminal */
|
/* prepare terminal */
|
||||||
|
@ -437,7 +568,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
soundif_start();
|
soundif_start();
|
||||||
if (tx)
|
if (tx)
|
||||||
dcf77_tx_start(dcf77, timestamp);
|
dcf77_tx_start(dcf77, (time_t)timestamp, fmod(timestamp, 1.0));
|
||||||
|
|
||||||
while (!quit) {
|
while (!quit) {
|
||||||
int w;
|
int w;
|
||||||
|
|
|
@ -0,0 +1,582 @@
|
||||||
|
|
||||||
|
/* based on code found at:
|
||||||
|
https://github.com/FroggySoft/AlarmClock/blob/master/dcf77.cpp
|
||||||
|
https://github.com/tobozo/esp32-dcf77-weatherman/blob/master/dcf77.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <endian.h>
|
||||||
|
#include "../libdebug/debug.h"
|
||||||
|
#include "weather.h"
|
||||||
|
|
||||||
|
/// Container zum Konvertieren zwischen 4 Bytes und Uint.
|
||||||
|
union ByteUInt {
|
||||||
|
struct {
|
||||||
|
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
uint8_t Byte0;
|
||||||
|
uint8_t Byte1;
|
||||||
|
uint8_t Byte2;
|
||||||
|
uint8_t Byte3;
|
||||||
|
# elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
uint8_t Byte3;
|
||||||
|
uint8_t Byte2;
|
||||||
|
uint8_t Byte1;
|
||||||
|
uint8_t Byte0;
|
||||||
|
# else
|
||||||
|
#error unsupported bitorder, please fix
|
||||||
|
# endif
|
||||||
|
} s;
|
||||||
|
uint32_t FullUint;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// bit pattern for 0D,0E from 0B-0D
|
||||||
|
static const uint32_t mUintArrBitPattern12[12] = {
|
||||||
|
0x80000, //0b10000000000000000000 / 0D.3
|
||||||
|
0x00010, //0b00000000000000010000 / 0B.4
|
||||||
|
0x00008, //0b00000000000000001000 / 0B.3
|
||||||
|
0x00100, //0b00000000000100000000 / 0C.0
|
||||||
|
0x00080, //0b00000000000010000000 / 0B.7
|
||||||
|
0x01000, //0b00000001000000000000 / 0C.4
|
||||||
|
0x00800, //0b00000000100000000000 / 0C.3
|
||||||
|
0x10000, //0b00010000000000000000 / 0D.0
|
||||||
|
0x08000, //0b00001000000000000000 / 0C.7
|
||||||
|
0x00001, //0b00000000000000000001 / 0B.0
|
||||||
|
0x00000, //0b00000000000000000000 / xxxx
|
||||||
|
0x00000 //0b00000000000000000000 / xxxx
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 12-15 from 16-19 (time)
|
||||||
|
static const uint32_t mUintArrBitPattern30_1[30] = {
|
||||||
|
0x00000200, //0b00000000000000000000001000000000 / 17.1
|
||||||
|
0x00000020, //0b00000000000000000000000000100000 / 16.5
|
||||||
|
0x02000000, //0b00000010000000000000000000000000 / 19.1
|
||||||
|
0x00000000, //0b00000000000000000000000000000000 / 1A.3
|
||||||
|
0x00000000, //0b00000000000000000000000000000000 / 1A.5
|
||||||
|
0x00000080, //0b00000000000000000000000010000000 / 16.7
|
||||||
|
0x40000000, //0b01000000000000000000000000000000 / 19.6
|
||||||
|
0x01000000, //0b00000001000000000000000000000000 / 19.0
|
||||||
|
|
||||||
|
0x04000000, //0b00000100000000000000000000000000 / 19.2
|
||||||
|
0x00000000, //0b00000000000000000000000000000000 / 1A.4
|
||||||
|
0x00010000, //0b00000000000000010000000000000000 / 18.0
|
||||||
|
0x00000000, //0b00000000000000000000000000000000 / 1A.2
|
||||||
|
0x00400000, //0b00000000010000000000000000000000 / 18.6
|
||||||
|
0x00000010, //0b00000000000000000000000000010000 / 16.4
|
||||||
|
0x00200000, //0b00000000001000000000000000000000 / 18.5
|
||||||
|
0x00080000, //0b00000000000010000000000000000000 / 18.3
|
||||||
|
|
||||||
|
0x00004000, //0b00000000000000000100000000000000 / 17.6
|
||||||
|
0x00000000, //0b00000000000000000000000000000000 / 1A.6
|
||||||
|
0x00020000, //0b00000000000000100000000000000000 / 18.1
|
||||||
|
0x00100000, //0b00000000000100000000000000000000 / 18.4
|
||||||
|
0x00008000, //0b00000000000000001000000000000000 / 17.7
|
||||||
|
0x00000040, //0b00000000000000000000000001000000 / 16.6
|
||||||
|
0x00001000, //0b00000000000000000001000000000000 / 17.4
|
||||||
|
0x00000400, //0b00000000000000000000010000000000 / 17.2
|
||||||
|
|
||||||
|
0x00000001, //0b00000000000000000000000000000001 / 16.0
|
||||||
|
0x80000000, //0b10000000000000000000000000000000 / 19.7
|
||||||
|
0x00000008, //0b00000000000000000000000000001000 / 16.3
|
||||||
|
0x00000002, //0b00000000000000000000000000000010 / 16.1
|
||||||
|
0x00040000, //0b00000000000001000000000000000000 / 18.2
|
||||||
|
0x10000000 //0b00010000000000000000000000000000 / 19.4
|
||||||
|
};
|
||||||
|
|
||||||
|
/// bit pattern for 12-15 from 1A (time2)
|
||||||
|
static const uint32_t mUintArrBitPattern30_2[30] = {
|
||||||
|
0x00, //0b00000000, /* 17.1
|
||||||
|
0x00, //0b00000000, /* 16.5
|
||||||
|
0x00, //0b00000000, /* 19.1
|
||||||
|
0x08, //0b00001000, /* 1A.3
|
||||||
|
0x20, //0b00100000, /* 1A.5
|
||||||
|
0x00, //0b00000000, /* 16.7
|
||||||
|
0x00, //0b00000000, /* 19.6
|
||||||
|
0x00, //0b00000000, /* 19.0
|
||||||
|
|
||||||
|
0x00, //0b00000000, /* 19.2
|
||||||
|
0x10, //0b00010000, /* 1A.4
|
||||||
|
0x00, //0b00000000, /* 18.0
|
||||||
|
0x04, //0b00000100, /* 1A.2
|
||||||
|
0x00, //0b00000000, /* 18.6
|
||||||
|
0x00, //0b00000000, /* 16.4
|
||||||
|
0x00, //0b00000000, /* 18.5
|
||||||
|
0x00, //0b00000000, /* 18.3
|
||||||
|
|
||||||
|
0x00, //0b00000000, /* 17.6
|
||||||
|
0x40, //0b01000000, /* 1A.6
|
||||||
|
0x00, //0b00000000, /* 18.1
|
||||||
|
0x00, //0b00000000, /* 18.4
|
||||||
|
0x00, //0b00000000, /* 17.7
|
||||||
|
0x00, //0b00000000, /* 16.6
|
||||||
|
0x00, //0b00000000, /* 17.4
|
||||||
|
0x00, //0b00000000, /* 17.2
|
||||||
|
|
||||||
|
0x00, //0b00000000, /* 16.0
|
||||||
|
0x00, //0b00000000, /* 19.7
|
||||||
|
0x00, //0b00000000, /* 16.3
|
||||||
|
0x00, //0b00000000, /* 16.1
|
||||||
|
0x00, //0b00000000, /* 18.2
|
||||||
|
0x00 //0b00000000, /* 19.4
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 12-14 from 1C-1E (result from F)
|
||||||
|
static const uint32_t mUintArrBitPattern20[20] = {
|
||||||
|
0x000004, //0b000000000000000000000100 / 1C.2
|
||||||
|
0x002000, //0b000000000010000000000000 / 1E.5
|
||||||
|
0x008000, //0b000000001000000000000000 / 1E.7
|
||||||
|
0x400000, //0b010000000000000000000000 / 1D.6
|
||||||
|
0x000100, //0b000000000000000100000000 / 1E.0
|
||||||
|
0x100000, //0b000100000000000000000000 / 1D.4
|
||||||
|
0x000400, //0b000000000000010000000000 / 1E.2
|
||||||
|
0x800000, //0b100000000000000000000000 / 1D.7
|
||||||
|
|
||||||
|
0x040000, //0b000001000000000000000000 / 1D.2
|
||||||
|
0x020000, //0b000000100000000000000000 / 1D.1
|
||||||
|
0x000008, //0b000000000000000000001000 / 1C.3
|
||||||
|
0x000200, //0b000000000000001000000000 / 1E.1
|
||||||
|
0x004000, //0b000000000100000000000000 / 1E.6
|
||||||
|
0x000002, //0b000000000000000000000010 / 1C.1
|
||||||
|
0x001000, //0b000000000001000000000000 / 1E.4
|
||||||
|
0x080000, //0b000010000000000000000000 / 1D.3
|
||||||
|
|
||||||
|
0x000800, //0b000000000000100000000000 / 1E.3
|
||||||
|
0x200000, //0b001000000000000000000000 / 1D.5
|
||||||
|
0x010000, //0b000000010000000000000000 / 1D.0
|
||||||
|
0x000001 //0b000000000000000000000001 / 1C.0
|
||||||
|
};
|
||||||
|
|
||||||
|
/// bit pattern for 12-15 from 16-19 (1/3)
|
||||||
|
static const uint64_t mByteArrLookupTable1C_1[8] = {
|
||||||
|
0xBB0E22C573DFF76D, 0x90E9A1381C844A56,
|
||||||
|
0x648D280BD1BA9352, 0x1CC5A7F0E97F364E,
|
||||||
|
0xC1773DB3AAE00C6F, 0x1488F62BD2995E45,
|
||||||
|
0x1F7096D3B30BFCEE, 0x8142CA34A5582967
|
||||||
|
};
|
||||||
|
|
||||||
|
/// bit pattern for 12-15 from 16-19 (2/3)
|
||||||
|
static const uint64_t mByteArrLookupTable1C_2[8] = {
|
||||||
|
0xAB3DFC7465E60E4F, 0x9711D85983C2BA20,
|
||||||
|
0xC51BD2584937017D, 0x93FAE02F66B4AC8E,
|
||||||
|
0xB7CC43FF5866EB35, 0x822A99DD007114AE,
|
||||||
|
0x4EB1F7701852AA9F, 0xD56BCC3D0483E926
|
||||||
|
};
|
||||||
|
|
||||||
|
/// bit pattern for 12-15 from 16-19 (3/3)
|
||||||
|
static const uint64_t mByteArrLookupTable1C_3[8] = {
|
||||||
|
0x0A02000F06070D08, 0x030C0B050901040E,
|
||||||
|
0x0209050D0C0E0F08, 0x06070B01000A0403,
|
||||||
|
0x08000D0F010C0306, 0x0B0409050A07020E,
|
||||||
|
0x030D000C09060F0B, 0x010E080A02070405
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Container, which contains all former global vars
|
||||||
|
typedef struct DataContainer {
|
||||||
|
/// Registers R12 to R15
|
||||||
|
union ByteUInt mByteUint1;
|
||||||
|
/// Registers R08 to R0A
|
||||||
|
union ByteUInt mByteUint2;
|
||||||
|
/// Registers R0B to R0E
|
||||||
|
union ByteUInt mByteUint3;
|
||||||
|
/// Registers R1C to R1E
|
||||||
|
union ByteUInt mByteUint4;
|
||||||
|
|
||||||
|
uint8_t mByteUpperTime2;//, mByteR1B;
|
||||||
|
uint32_t mUintLowerTime;
|
||||||
|
} DataContainer_t;
|
||||||
|
|
||||||
|
static int32_t GetWeatherFromPlain(uint8_t *PlainBytes)
|
||||||
|
{
|
||||||
|
uint32_t result;
|
||||||
|
uint32_t checkSum;
|
||||||
|
|
||||||
|
checkSum = PlainBytes[2] & 0x0f;
|
||||||
|
checkSum <<= 8;
|
||||||
|
checkSum |= PlainBytes[1];
|
||||||
|
checkSum <<= 4;
|
||||||
|
checkSum |= PlainBytes[0] >> 4;
|
||||||
|
if (checkSum != 0x2501)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
result = PlainBytes[0] & 0x0f;
|
||||||
|
result <<= 8;
|
||||||
|
result |= PlainBytes[4];
|
||||||
|
result <<= 8;
|
||||||
|
result |= PlainBytes[3];
|
||||||
|
result <<= 4;
|
||||||
|
result |= PlainBytes[2] >> 4;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t *GetPlainFromWeather(uint32_t weather)
|
||||||
|
{
|
||||||
|
static uint8_t result[5];
|
||||||
|
weather <<= 4;
|
||||||
|
result[1] = 0x50;
|
||||||
|
result[2] = (weather & 0xf0) | 0x02;
|
||||||
|
weather >>= 8;
|
||||||
|
result[3] = weather & 0xff;
|
||||||
|
weather >>= 8;
|
||||||
|
result[4] = weather & 0xff;
|
||||||
|
weather >>= 8;
|
||||||
|
result[0] = (weather & 0x0f) | 0x10;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CopyTimeToByteUint(uint8_t *data, uint8_t *key, DataContainer_t *container)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
container->mUintLowerTime <<= 8;
|
||||||
|
container->mUintLowerTime |= key[3 - i];
|
||||||
|
}
|
||||||
|
container->mByteUpperTime2 = key[4];
|
||||||
|
|
||||||
|
// copy R
|
||||||
|
container->mByteUint3.s.Byte0 = data[2];
|
||||||
|
container->mByteUint3.s.Byte1 = data[3];
|
||||||
|
container->mByteUint3.s.Byte2 = data[4];
|
||||||
|
container->mByteUint3.FullUint >>= 4;
|
||||||
|
|
||||||
|
// copy L
|
||||||
|
container->mByteUint2.s.Byte0 = data[0];
|
||||||
|
container->mByteUint2.s.Byte1 = data[1];
|
||||||
|
container->mByteUint2.s.Byte2 = (uint8_t)(data[2] & 0x0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ShiftTimeRight(int round, DataContainer_t *container)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
uint8_t tmp;
|
||||||
|
|
||||||
|
if ((round == 16) || (round == 8) || (round == 7) || (round == 3))
|
||||||
|
count = 2;
|
||||||
|
else
|
||||||
|
count = 1;
|
||||||
|
|
||||||
|
while (count-- != 0)
|
||||||
|
{
|
||||||
|
tmp = 0;
|
||||||
|
if ((container->mUintLowerTime & 0x00100000) != 0) // save time bit 20
|
||||||
|
tmp = 1;
|
||||||
|
|
||||||
|
container->mUintLowerTime &= 0xFFEFFFFF;
|
||||||
|
if ((container->mUintLowerTime & 1) != 0)
|
||||||
|
container->mUintLowerTime |= 0x00100000; // copy time bit 0 to time bit 19
|
||||||
|
container->mUintLowerTime >>= 1; // time >>= 1
|
||||||
|
|
||||||
|
if ((container->mByteUpperTime2 & 1) != 0)
|
||||||
|
container->mUintLowerTime |= 0x80000000;
|
||||||
|
container->mByteUpperTime2 >>= 1;
|
||||||
|
if (tmp != 0)
|
||||||
|
container->mByteUpperTime2 |= 0x80; // insert time bit 20 to time bit 39
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ShiftTimeLeft(int round, DataContainer_t *container)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
uint8_t tmp;
|
||||||
|
|
||||||
|
if ((round == 16) || (round == 8) || (round == 7) || (round == 3))
|
||||||
|
count = 2;
|
||||||
|
else
|
||||||
|
count = 1;
|
||||||
|
|
||||||
|
while (count-- != 0)
|
||||||
|
{
|
||||||
|
tmp = 0;
|
||||||
|
if ((container->mByteUpperTime2 & 0x80) != 0)
|
||||||
|
tmp = 1;
|
||||||
|
container->mByteUpperTime2 <<= 1;
|
||||||
|
|
||||||
|
if ((container->mUintLowerTime & 0x80000000) != 0)
|
||||||
|
container->mByteUpperTime2 |= 1;
|
||||||
|
|
||||||
|
container->mUintLowerTime <<= 1;
|
||||||
|
if ((container->mUintLowerTime & 0x00100000) != 0)
|
||||||
|
container->mUintLowerTime |= 1;
|
||||||
|
|
||||||
|
container->mUintLowerTime &= 0xFFEFFFFF;
|
||||||
|
if (tmp != 0)
|
||||||
|
container->mUintLowerTime |= 0x00100000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ExpandR(DataContainer_t *container)
|
||||||
|
{
|
||||||
|
uint32_t tmp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
container->mByteUint3.FullUint &= 0x000FFFFF; // clear 0D(4-7),0E
|
||||||
|
tmp = 0x00100000; // and set bits form 0B-0D(0-3)
|
||||||
|
for (i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
if ((container->mByteUint3.FullUint & mUintArrBitPattern12[i]) != 0)
|
||||||
|
container->mByteUint3.FullUint |= tmp;
|
||||||
|
tmp <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ExpandL(DataContainer_t *container)
|
||||||
|
{
|
||||||
|
uint32_t tmp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
container->mByteUint2.FullUint &= 0x000FFFFF; // clear 0D(4-7),0E
|
||||||
|
tmp = 0x00100000; // and set bits form 0B-0D(0-3)
|
||||||
|
for (i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
if ((container->mByteUint2.FullUint & mUintArrBitPattern12[i]) != 0)
|
||||||
|
container->mByteUint2.FullUint |= tmp;
|
||||||
|
tmp <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CompressKey(DataContainer_t *container)
|
||||||
|
{
|
||||||
|
uint32_t tmp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
container->mByteUint1.FullUint = 0; // clear 12-15
|
||||||
|
tmp = 0x00000001; // and set bits from 16-1A (time)
|
||||||
|
for (i = 0; i < 30; i++)
|
||||||
|
{
|
||||||
|
if ((container->mUintLowerTime & mUintArrBitPattern30_1[i]) != 0 || (container->mByteUpperTime2 & mUintArrBitPattern30_2[i]) != 0)
|
||||||
|
container->mByteUint1.FullUint |= tmp;
|
||||||
|
tmp <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DoSbox(DataContainer_t *container)
|
||||||
|
{
|
||||||
|
uint8_t tmp, helper; //mByteR1B;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
helper = container->mByteUint1.s.Byte3; // R1B = R15;
|
||||||
|
container->mByteUint1.s.Byte3 = container->mByteUint1.s.Byte2; // R15 = R14
|
||||||
|
|
||||||
|
// INNER LOOP
|
||||||
|
for (i = 5; i > 0; i--)
|
||||||
|
{
|
||||||
|
if ((i & 1) == 0) // round 4,2
|
||||||
|
{
|
||||||
|
tmp = (uint8_t)(container->mByteUint1.s.Byte0 >> 4); // swap R12
|
||||||
|
tmp |= (uint8_t)((container->mByteUint1.s.Byte0 & 0x0f) << 4);
|
||||||
|
container->mByteUint1.s.Byte0 = tmp;
|
||||||
|
}
|
||||||
|
container->mByteUint1.s.Byte3 &= 0xF0; // set R1C
|
||||||
|
tmp = (uint8_t)((container->mByteUint1.s.Byte0 & 0x0F) | container->mByteUint1.s.Byte3);
|
||||||
|
|
||||||
|
if ((i & 4) != 0)
|
||||||
|
tmp = mByteArrLookupTable1C_1[(tmp & 0x38) >> 3] >> (56 - (tmp & 0x07) * 8);
|
||||||
|
|
||||||
|
if ((i & 2) != 0)
|
||||||
|
tmp = mByteArrLookupTable1C_2[(tmp & 0x38) >> 3] >> (56 - (tmp & 0x07) * 8);
|
||||||
|
|
||||||
|
else if (i == 1)
|
||||||
|
tmp = mByteArrLookupTable1C_3[(tmp & 0x38) >> 3] >> (56 - (tmp & 0x07) * 8);
|
||||||
|
|
||||||
|
if ((i & 1) != 0)
|
||||||
|
container->mByteUint4.s.Byte0 = (uint8_t)(tmp & 0x0F);
|
||||||
|
else
|
||||||
|
container->mByteUint4.s.Byte0 |= (uint8_t)(tmp & 0xF0);
|
||||||
|
|
||||||
|
if ((i & 1) == 0) // copy 14->13->12, 1C->1E->1D
|
||||||
|
{
|
||||||
|
tmp = container->mByteUint1.s.Byte3;
|
||||||
|
container->mByteUint1.FullUint >>= 8;
|
||||||
|
container->mByteUint1.s.Byte3 = tmp;
|
||||||
|
container->mByteUint4.FullUint <<= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
container->mByteUint1.s.Byte3 >>= 1; // rotate R1B>R15 twice
|
||||||
|
if ((helper & 1) != 0)
|
||||||
|
container->mByteUint1.s.Byte3 |= 0x80;
|
||||||
|
helper >>= 1;
|
||||||
|
|
||||||
|
container->mByteUint1.s.Byte3 >>= 1;
|
||||||
|
if ((helper & 1) != 0)
|
||||||
|
container->mByteUint1.s.Byte3 |= 0x80;
|
||||||
|
helper >>= 1;
|
||||||
|
} // end of inner loop
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DoPbox(DataContainer_t *container)
|
||||||
|
{
|
||||||
|
uint32_t tmp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
container->mByteUint1.FullUint = 0xFF000000; // clear 12-14
|
||||||
|
tmp = 0x00000001; // and set bits from 1C-1E (result from F)
|
||||||
|
for (i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
if ((container->mByteUint4.FullUint & mUintArrBitPattern20[i]) != 0)
|
||||||
|
container->mByteUint1.FullUint |= tmp;
|
||||||
|
tmp <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* modified DES decrypt using strings */
|
||||||
|
static uint8_t *Decrypt(uint8_t *cipher, uint8_t *key)
|
||||||
|
{
|
||||||
|
DataContainer_t container;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
static uint8_t plain[5];
|
||||||
|
CopyTimeToByteUint(cipher, key, &container);
|
||||||
|
|
||||||
|
// OUTER LOOP 1
|
||||||
|
for (i = 16; i > 0; i--)
|
||||||
|
{
|
||||||
|
ShiftTimeRight(i, &container);
|
||||||
|
ExpandR(&container);
|
||||||
|
CompressKey(&container);
|
||||||
|
|
||||||
|
// expR XOR compr.Key
|
||||||
|
container.mByteUint1.FullUint ^= container.mByteUint3.FullUint; // 12-15 XOR 0B-0E
|
||||||
|
container.mByteUint3.s.Byte2 &= 0x0F; // clear 0D(4-7)
|
||||||
|
|
||||||
|
DoSbox(&container);
|
||||||
|
DoPbox(&container);
|
||||||
|
|
||||||
|
// L XOR P-Boxed Round-Key (L')
|
||||||
|
container.mByteUint1.FullUint ^= container.mByteUint2.FullUint;
|
||||||
|
|
||||||
|
// L = R
|
||||||
|
container.mByteUint2.FullUint = container.mByteUint3.FullUint & 0x00FFFFFF;
|
||||||
|
|
||||||
|
// R = L'
|
||||||
|
container.mByteUint3.FullUint = container.mByteUint1.FullUint & 0x00FFFFFF;
|
||||||
|
} // end of outer loop 1
|
||||||
|
|
||||||
|
container.mByteUint3.FullUint <<= 4;
|
||||||
|
container.mByteUint2.s.Byte2 &= 0x0F;
|
||||||
|
container.mByteUint2.s.Byte2 |= (uint8_t)(container.mByteUint3.s.Byte0 & 0xF0);
|
||||||
|
|
||||||
|
plain[0] = container.mByteUint2.s.Byte0;
|
||||||
|
plain[1] = container.mByteUint2.s.Byte1;
|
||||||
|
plain[2] = container.mByteUint2.s.Byte2;
|
||||||
|
plain[3] = container.mByteUint3.s.Byte1;
|
||||||
|
plain[4] = container.mByteUint3.s.Byte2;
|
||||||
|
|
||||||
|
return plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* modified DES encrypt using strings */
|
||||||
|
static uint8_t *Encrypt(uint8_t *plain, uint8_t *key)
|
||||||
|
{
|
||||||
|
static uint8_t cipher[5];
|
||||||
|
DataContainer_t container;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
CopyTimeToByteUint(plain, key, &container);
|
||||||
|
|
||||||
|
// OUTER LOOP 1
|
||||||
|
for (i = 1; i < 17; i++)
|
||||||
|
{
|
||||||
|
ExpandL(&container);
|
||||||
|
CompressKey(&container);
|
||||||
|
|
||||||
|
// expR XOR compr.Key
|
||||||
|
container.mByteUint1.FullUint ^= container.mByteUint2.FullUint; // L' XOR compr.Key
|
||||||
|
container.mByteUint3.s.Byte2 &= 0x0F; // clear 0D(4-7)
|
||||||
|
|
||||||
|
DoSbox(&container);
|
||||||
|
DoPbox(&container);
|
||||||
|
|
||||||
|
// L XOR P-Boxed Round-Key (L')
|
||||||
|
container.mByteUint1.FullUint ^= container.mByteUint3.FullUint;
|
||||||
|
// L = R
|
||||||
|
container.mByteUint3.FullUint = container.mByteUint2.FullUint & 0x00FFFFFF;
|
||||||
|
// R = L'
|
||||||
|
container.mByteUint2.FullUint = container.mByteUint1.FullUint & 0x00FFFFFF;
|
||||||
|
|
||||||
|
ShiftTimeLeft(i, &container);
|
||||||
|
} // end of outer loop 1
|
||||||
|
|
||||||
|
container.mByteUint3.FullUint <<= 4;
|
||||||
|
container.mByteUint2.s.Byte2 &= 0x0F;
|
||||||
|
container.mByteUint2.s.Byte2 |= (uint8_t)(container.mByteUint3.s.Byte0 & 0xF0);
|
||||||
|
|
||||||
|
cipher[0] = container.mByteUint2.s.Byte0;
|
||||||
|
cipher[1] = container.mByteUint2.s.Byte1;
|
||||||
|
cipher[2] = container.mByteUint2.s.Byte2;
|
||||||
|
cipher[3] = container.mByteUint3.s.Byte1;
|
||||||
|
cipher[4] = container.mByteUint3.s.Byte2;
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#define DEBUG_CIPER
|
||||||
|
|
||||||
|
/* decode given crypted frame and key
|
||||||
|
* return the weather info or -1 on checksum error
|
||||||
|
*/
|
||||||
|
int32_t weather_decode(uint64_t cipher, uint64_t key)
|
||||||
|
{
|
||||||
|
uint8_t CipherBytes[5];
|
||||||
|
uint8_t KeyBytes[5];
|
||||||
|
uint8_t *PlainBytes;
|
||||||
|
int32_t weather;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
CipherBytes[i] = cipher >> (i * 8);
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
KeyBytes[i] = key >> (i * 8);
|
||||||
|
|
||||||
|
PlainBytes = Decrypt(CipherBytes, KeyBytes);
|
||||||
|
|
||||||
|
weather = GetWeatherFromPlain(PlainBytes);
|
||||||
|
|
||||||
|
#ifdef DEBUG_CIPER
|
||||||
|
printf("cipher=%s\n", debug_hex(CipherBytes, 5));
|
||||||
|
printf("key =%s\n", debug_hex(KeyBytes, 5));
|
||||||
|
printf("plain =%s\n", debug_hex(PlainBytes, 5));
|
||||||
|
if (weather < 0)
|
||||||
|
printf("weather=error\n");
|
||||||
|
else
|
||||||
|
printf("weather=%06x\n", weather);
|
||||||
|
|
||||||
|
weather_encode(weather, key);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return weather;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encode given weather info and key
|
||||||
|
* return crypted frame
|
||||||
|
*/
|
||||||
|
uint64_t weather_encode(uint32_t weather, uint64_t key)
|
||||||
|
{
|
||||||
|
uint8_t KeyBytes[5];
|
||||||
|
uint8_t *PlainBytes;
|
||||||
|
uint8_t *CipherBytes;
|
||||||
|
uint64_t cipher = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
PlainBytes = GetPlainFromWeather(weather);
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
KeyBytes[i] = key >> (i * 8);
|
||||||
|
|
||||||
|
CipherBytes = Encrypt(PlainBytes, KeyBytes);
|
||||||
|
|
||||||
|
#ifdef DEBUG_CIPER
|
||||||
|
printf("plain =%s\n", debug_hex(PlainBytes, 5));
|
||||||
|
printf("key =%s\n", debug_hex(KeyBytes, 5));
|
||||||
|
printf("cipher=%s\n", debug_hex(CipherBytes, 5));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
cipher |= (uint64_t)(CipherBytes[i]) << (i * 8);
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
int32_t weather_decode(uint64_t cipher, uint64_t key);
|
||||||
|
uint64_t weather_encode(uint32_t weather, uint64_t key);
|
Loading…
Reference in New Issue