aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/anetz/Makefile.am1
-rw-r--r--src/anetz/main.c21
-rw-r--r--src/anetz/stations.c271
-rw-r--r--src/anetz/stations.h4
-rw-r--r--src/bnetz/Makefile.am1
-rw-r--r--src/bnetz/main.c18
-rw-r--r--src/bnetz/stations.c295
-rw-r--r--src/bnetz/stations.h4
8 files changed, 612 insertions, 3 deletions
diff --git a/src/anetz/Makefile.am b/src/anetz/Makefile.am
index 9cbfefa..a043a42 100644
--- a/src/anetz/Makefile.am
+++ b/src/anetz/Makefile.am
@@ -6,6 +6,7 @@ bin_PROGRAMS = \
anetz_SOURCES = \
anetz.c \
dsp.c \
+ stations.c \
image.c \
main.c
anetz_LDADD = \
diff --git a/src/anetz/main.c b/src/anetz/main.c
index 1276304..4e73f0a 100644
--- a/src/anetz/main.c
+++ b/src/anetz/main.c
@@ -33,6 +33,7 @@
#include "../common/besetztton.h"
#include "anetz.h"
#include "dsp.h"
+#include "stations.h"
#include "image.h"
/* settings */
@@ -43,6 +44,10 @@ void print_help(const char *arg0)
{
print_help_common(arg0, "");
/* - - */
+ printf(" -g --geo <lat>,<lon>\n");
+ printf(" Give your coordinates of your location, to find closest base station.\n");
+ printf(" (e.g. '--geo 51.186959,7.080194') Or use '--geo list' to get a list of\n");
+ printf(" all base station locations.\n");
printf(" -P --page-sequence 0 | <ms>\n");
printf(" Cycle paging tones, rather than sending simultaniously.\n");
printf(" (default = '%d')\n", page_sequence);
@@ -56,14 +61,16 @@ void print_help(const char *arg0)
static int handle_options(int argc, char **argv)
{
int skip_args = 0;
+ char *p;
static struct option long_options_special[] = {
+ {"geo", 1, 0, 'g'},
{"page-sequence", 1, 0, 'P'},
{"loss", 1, 0, '0'},
{0, 0, 0, 0}
};
- set_options_common("P:0:", long_options_special);
+ set_options_common("g:P:0:", long_options_special);
while (1) {
int option_index = 0, c;
@@ -74,6 +81,18 @@ static int handle_options(int argc, char **argv)
break;
switch (c) {
+ case 'g':
+ if (!strcasecmp(optarg, "list")) {
+ station_list();
+ exit(0);
+ }
+ if ((p = strchr(optarg, ','))) {
+ get_station_by_coordinates(atof(optarg), atof(p + 1));
+ exit(0);
+ }
+ fprintf(stderr, "Invalid geo parameter\n");
+ exit(0);
+ break;
case 'P':
page_sequence = atoi(optarg);
skip_args += 2;
diff --git a/src/anetz/stations.c b/src/anetz/stations.c
new file mode 100644
index 0000000..1b5bc50
--- /dev/null
+++ b/src/anetz/stations.c
@@ -0,0 +1,271 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+static struct anetz_stations {
+ const char *standort;
+ int kanal21; /* Channel for prefix 21 */
+ int kanal22; /* Channel for prefix 22 (0 = use previous channel) */
+ int kanal23; /* ... */
+ int kanal24;
+ int kanal25;
+ const char *coordinates;
+} anetz_stations[] = {
+/* Standort Prefix 21..25 Coorinates */
+ { "Niebuell", 32, 0, 0, 0, 0, "54o47 08o50" },
+ { "Flensburg", 39, 0, 0, 0, 0, "54o47 09o26" },
+ { "Schleswig", 35, 0, 0, 0, 0, "54o31 09o34" },
+ { "Kiel", 36, 0, 0,38, 0, "54o20 10o08" },
+ { "Toenning", 37, 0, 0, 0, 0, "54o19 08o57" },
+ { "Heide", 34, 0, 0, 0, 0, "54o12 09o06" },
+ { "Eutin", 30, 0, 0, 0, 0, "54o08 10o37" },
+ { "Neumuenster", 32, 0, 0, 0, 0, "54o04 09o59" },
+ { "Luebeck", 37, 0, 0,42, 0, "53o52 10o41" },
+ { "Cuxhaven", 30, 0, 0, 0, 0, "53o52 08o41" },
+ { "Hemmoor", 40, 0, 0, 0, 0, "53o42 09o08" },
+ { "Ratzeburg", 40, 0, 0, 0, 0, "53o42 10o45" },
+ { "Hamburg", 39,35,31,41,33, "53o34 10o00" },
+ { "Bremerhaven", 39, 0, 0,41, 0, "53o33 08o35" },
+ { "Wilhelmshaven", 36, 0, 0, 0, 0, "53o31 08o08" },
+ { "Aurich", 32, 0, 0, 0, 0, "53o28 07o29" },
+ { "Lueneburg", 32, 0, 0, 0, 0, "53o15 10o25" },
+ { "Leer", 35, 0, 0, 0, 0, "53o14 07o27" },
+ { "Oldenburg", 30, 0, 0,31, 0, "53o09 08o13" },
+ { "Rotenburg", 30, 0, 0, 0, 0, "53o06 09o24" },
+ { "Bremen", 37,44,33,42, 0, "53o05 08o48" },
+ { "Soltau", 35, 0, 0, 0, 0, "52o59 09o50" },
+ { "Luechow", 30, 0, 0, 0, 0, "52o58 11o09" },
+ { "Uelzen", 34, 0, 0, 0, 0, "52o58 10o33" },
+ { "Werlte", 34, 0, 0, 0, 0, "52o51 07o41" },
+ { "Hoya", 32, 0, 0, 0, 0, "52o48 09o08" },
+ { "Lingen", 36, 0, 0, 0, 0, "52o31 07o19" },
+ { "Berlin", 39,33,35,41, 0, "52o31 13o23" },
+ { "Wolfsburg", 30, 0, 0, 0, 0, "52o25 10o47" },
+ { "Hannover", 36,44,33,38, 0, "52o22 09o43" },
+ { "Osnabrueck", 39, 0, 0,41, 0, "52o17 08o03" },
+ { "Minden", 30, 0, 0,40, 0, "52o17 08o55" },
+ { "Braunschweig", 37, 0, 0,42, 0, "52o16 10o31" },
+ { "Burgsteinfurt", 37, 0, 0, 0, 0, "52o09 07o21" },
+ { "Bielefeld", 34,33, 0,43, 0, "52o01 08o31" },
+ { "Alfeld", 39, 0, 0, 0, 0, "51o59 09o50" },
+ { "Muenster", 32, 0, 0,42, 0, "51o58 07o38" },
+ { "Kleve", 32, 0,31,38, 0, "51o47 06o08" },
+ { "Paderborn", 37, 0, 0, 0, 0, "51o43 08o46" },
+ { "Wesel", 45, 0, 0, 0, 0, "51o40 06o37" },
+ { "Goettingen", 34, 0, 0, 0, 0, "51o32 09o56" },
+ { "Dortmund", 36, 0, 31,38,0, "51o31 07o28" },
+ { "Essen", 34, 0, 0, 0,43, "51o27 07o01" },
+ { "Duisburg", 39,44,33,41, 0, "51o26 06o46" },
+ { "Meschede", 35, 0, 0, 0, 0, "51o21 08o17" },
+ { "Kassel", 32, 0, 0, 0, 0, "51o19 09o30" },
+ { "Wuppertal", 30, 0, 0, 0,40, "51o16 07o11" },
+ { "Korbach", 38, 0, 0, 0, 0, "51o17 08o52" },
+ { "Luedenscheid", 39, 0, 0, 0, 0, "51o13 07o38" },
+ { "Winterberg", 33, 0, 0, 0, 0, "51o12 08o31" },
+ { "Duesseldorf", 37, 0, 31,42,0, "51o14 06o47" },
+ { "Eschwege", 39, 0, 0, 0, 0, "51o11 10o03" },
+ { "Koeln", 36,35,33,38, 0, "50o56 06o57" },
+ { "Siegen", 36, 0, 0, 0, 0, "50o53 08o01" },
+ { "Aachen", 34, 0, 0, 0, 0, "50o47 06o05" },
+ { "Alsfeld", 36, 0, 0,40, 0, "50o45 09o16" },
+ { "Bonn", 32, 0, 0,41, 0, "50o44 07o06" },
+ { "Dillenburg", 42, 0, 0, 0, 0, "50o44 08o17" },
+ { "Giessen", 34, 0, 0, 0, 0, "50o35 08o40" },
+ { "Fulda", 30, 0, 0, 0, 0, "50o33 09o41" },
+ { "Montabaur", 46, 0, 0, 0, 0, "50o26 07o50" },
+ { "Usingen", 30, 0, 0, 0, 0, "50o20 08o32" },
+ { "Mayen", 34, 0, 0, 0, 0, "50o20 07o13" },
+ { "Hof", 39, 0, 0, 0, 0, "50o19 11o55" },
+ { "Coburg", 35, 0, 0, 0, 0, "50o16 10o58" },
+ { "Boppard", 39, 31,0, 35,0, "50o14 07o35" },
+ { "Koblenz", 40, 0, 0, 0, 0, "50o22 07o36" },
+ { "Pruem", 35, 0, 0, 0, 0, "50o12 06o25" },
+ { "Gelnhausen", 41, 0, 0, 0, 0, "50o12 09o10" },
+ { "Wiesbaden", 30, 0, 0, 0,40, "50o05 08o14" },
+ { "Hanau", 39, 0, 0, 0, 0, "50o08 08o55" },
+ { "Frankfurt", 37,35,31,42,33, "50o07 08o41" },
+ { "Schweinfurt", 34, 0, 0, 0, 0, "50o03 10o14" },
+ { "Aschaffenburg", 45, 0, 0, 0, 0, "49o58 09o09" },
+ { "Bingen", 36, 0, 0,41, 0, "49o58 07o54" },
+ { "Bayreuth", 30, 0, 0, 0, 0, "49o57 11o35" },
+ { "Bernkastel", 37, 0, 0, 0, 0, "49o55 07o04" },
+ { "Bamberg", 37, 0, 0, 0, 0, "49o54 10o54" },
+ { "Darmstadt", 32, 0, 0,38, 0, "49o52 08o39" },
+ { "Marktheidenfeld", 36, 0, 0, 0, 0, "49o51 09o36" },
+ { "Wuerzburg", 39, 0, 0,44, 0, "49o47 09o56" },
+ { "Pegnitz", 34, 0, 0, 0, 0, "49o45 11o34" },
+ { "Trier", 39, 0, 0, 0, 0, "49o45 06o38" },
+ { "Kitzingen", 32, 0, 0, 0, 0, "49o44 10o10" },
+ { "Idar-Oberstein", 32, 0, 0, 0, 0, "49o43 07o19" },
+ { "Lindenfels", 34, 0, 0, 0, 0, "49o41 08o47" },
+ { "Weiden", 32, 0, 0, 0, 0, "49o40 12o09" },
+ { "Mannheim", 39,35,44,41, 0, "49o29 08o28" },
+ { "Fuerth", 44, 0, 0, 0, 0, "49o28 11o00" },
+ { "Kaiserslautern", 34, 0, 0,43, 0, "49o27 07o46" },
+ { "Nuernberg", 39, 0, 33,41,0, "49o27 11o05" },
+ { "Heidelberg", 37, 0, 0,42, 0, "49o25 08o43" },
+ { "Ansbach", 30, 0, 0, 0, 0, "49o18 10o35" },
+ { "Neumarkt", 35, 0, 0, 0, 0, "49o17 11o28" },
+ { "Saarbruecken", 30, 0, 0,40, 0, "49o14 07o00" },
+ { "Heilbronn", 32, 0, 0,43, 0, "49o09 09o13" },
+ { "Schwaebisch Hall", 41, 0, 0, 0, 0, "49o07 09o44" },
+ { "Weissenburg", 36, 0, 0, 0, 0, "49o02 10o58" },
+ { "Regensburg", 30, 0, 0, 0, 0, "49o01 12o05" },
+ { "Karlsruhe", 30, 0, 0, 0,40, "49o01 08o24" },
+ { "Pforzheim", 46, 0, 0, 0, 0, "48o54 08o43" },
+ { "Deggendorf", 37, 0, 0, 0, 0, "48o50 12o58" },
+ { "Schwaebisch Gmuend", 34, 0, 0, 0, 0, "48o48 09o48" },
+ { "Stuttgart", 35,44,33,38,40, "48o47 09o11" },
+ { "Calw", 31, 0, 0, 0, 0, "48o43 08o44" },
+ { "Geislingen", 35, 0, 0, 0, 0, "48o37 09o50" },
+ { "Passau", 36, 0, 0, 0, 0, "48o34 13o28" },
+ { "Landshut", 34, 0, 0, 0, 0, "48o32 12o09" },
+ { "Pfaffenhofen", 32, 0, 0, 0, 0, "48o32 11o31" },
+ { "Tuebingen", 37, 0, 0, 0, 0, "48o31 09o03" },
+ { "Offenburg", 32, 0, 0,38, 0, "48o28 07o56" },
+ { "Freudenstadt", 39, 0, 0, 0, 0, "48o28 08o25" },
+ { "Pfarrkirchen", 35, 0, 0, 0, 0, "48o25 12o55" },
+ { "Ulm", 39, 0, 0,41, 0, "48o24 09o59" },
+ { "Augsburg", 37, 0, 0,42, 0, "48o22 10o54" },
+ { "Rottweil", 34, 0, 0,43, 0, "48o10 08o37" },
+ { "Riedlingen", 33, 0, 0, 0, 0, "48o09 09o28" },
+ { "Muenchen", 39,35,33,41,44, "48o08 11o34" },
+ { "Wasserburg", 36, 0, 0,42, 0, "48o03 12o14" },
+ { "Freiburg", 37, 0, 0,31, 0, "47o59 07o51" },
+ { "Donaueschingen", 37, 0, 0, 0, 0, "47o57 08o30" },
+ { "Neustadt", 30, 0, 0, 0, 0, "47o55 08o13" },
+ { "Weilheim", 30, 0, 0, 0, 0, "47o50 11o09" },
+ { "Ravensburg", 30, 0, 0, 0, 0, "47o47 09o37" },
+ { "Singen", 31, 0, 0, 0, 0, "47o46 08o50" },
+ { "Bad Toelz", 37, 0, 0, 0, 0, "47o46 11o33" },
+ { "Kempten", 34, 0, 0,43, 0, "47o44 10o19" },
+ { "Bad Reichenhall", 41, 0, 0, 0, 0, "47o43 12o53" },
+ { "Loerrach", 44, 0, 0, 0, 0, "47o37 07o40" },
+ { "Saeckingen", 34, 0, 0, 0, 0, "47o33 07o57" },
+ { "Garmisch-Partenkirchen", 36, 0, 0, 0, 0, "47o30 11o05" },
+ { NULL, 0, 0, 0, 0, 0, NULL }
+};
+
+double lat_from_coordinates(const char *string)
+{
+ if (strlen(string) != 11)
+ abort();
+ if (string[0] < '0' && string[0] > '9')
+ abort();
+ if (string[1] < '0' && string[1] > '9')
+ abort();
+ if (string[2] != 'o')
+ abort();
+ if (string[3] < '0' && string[3] > '9')
+ abort();
+ if (string[4] < '0' && string[4] > '9')
+ abort();
+
+ return (double)(string[0] - '0') * 10.0 +
+ (double)(string[1] - '0') +
+ (double)(string[3] - '0') / 6.0 +
+ (double)(string[4] - '0') / 60.0;
+}
+
+double lon_from_coordinates(const char *string)
+{
+ if (strlen(string) != 11)
+ abort();
+ if (string[6] < '0' && string[6] > '9')
+ abort();
+ if (string[7] < '0' && string[7] > '9')
+ abort();
+ if (string[8] != 'o')
+ abort();
+ if (string[9] < '0' && string[9] > '9')
+ abort();
+ if (string[10] < '0' && string[10] > '9')
+ abort();
+
+ return (double)(string[6] - '0') * 10.0 +
+ (double)(string[7] - '0') +
+ (double)(string[9] - '0') / 6.0 +
+ (double)(string[10] - '0') / 60.0;
+}
+
+#define EQUATOR_RADIUS 6378137.0
+#define POLE_RADIUS 6356752.314
+
+#define PI M_PI
+
+void station_list(void)
+{
+ int i;
+
+ printf("List of all base stations:\n");
+ for (i = 0; anetz_stations[i].standort; i++) {
+ printf("%s (%.2f° N %.2f° E)\n", anetz_stations[i].standort, lat_from_coordinates(anetz_stations[i].coordinates), lon_from_coordinates(anetz_stations[i].coordinates));
+ }
+}
+
+/* convert geo coordinates (lon/lat) to space coordinates in meters (x/y/z) */
+static void geo2space(double *x, double *y, double *z, double lat, double lon)
+{
+ *z = sin(lat / 180.0 * PI) * POLE_RADIUS;
+ *x = sin(lon / 180.0 * PI) * cos(lat / 180.0 * PI) * EQUATOR_RADIUS;
+ *y = -cos(lon / 180.0 * PI) * cos(lat / 180.0 * PI) * EQUATOR_RADIUS;
+}
+
+/* calculate distance */
+static double distinspace(double x1, double y1, double z1, double x2, double y2, double z2)
+{
+ double x = x1 - x2;
+ double y = y1 - y2;
+ double z = z1 - z2;
+
+ return sqrt(x * x + y * y + z * z);
+}
+
+
+int get_station_by_coordinates(double lat, double lon)
+{
+ double dist, min = 0.0;
+ int i, min_i = 0;
+ double x, y, z;
+ double s_lat, s_lon;
+ double s_x, s_y, s_z;
+ int kanal[5];
+
+ geo2space(&x, &y, &z, lat, lon);
+
+ for (i = 0; anetz_stations[i].standort; i++) {
+ s_lat = lat_from_coordinates(anetz_stations[i].coordinates);
+ s_lon = lon_from_coordinates(anetz_stations[i].coordinates);
+ geo2space(&s_x, &s_y, &s_z, s_lat, s_lon);
+ dist = distinspace(x, y, z, s_x, s_y, s_z);
+ if (i == 0 || dist < min) {
+ min = dist;
+ min_i = i;
+ }
+ }
+
+ /* don't allow distance more than 100KM */
+ if (min > 100000) {
+ fprintf(stderr, "Given coordinates are more than 100 km away from base station.\n");
+ return 0;
+ }
+ kanal[0] = anetz_stations[min_i].kanal21;
+ kanal[1] = anetz_stations[min_i].kanal22;
+ kanal[2] = anetz_stations[min_i].kanal23;
+ kanal[3] = anetz_stations[min_i].kanal24;
+ kanal[4] = anetz_stations[min_i].kanal25;
+
+ for (i = 0; i < 5; i++) {
+ if (i && kanal[i] == 0)
+ kanal[i] = kanal[i - 1];
+ }
+
+ printf("Closest base station: %s (distance = %.2f km)\n", anetz_stations[min_i].standort, min / 1000.0);
+ printf("Frequencies allocated in your area were:\n");
+ for (i = 0; i < 5; i++)
+ printf(" Channel %d for phone numbers '%dxxxxx'\n", kanal[i], i + 21);
+
+ return 0;
+}
+
diff --git a/src/anetz/stations.h b/src/anetz/stations.h
new file mode 100644
index 0000000..ddfba91
--- /dev/null
+++ b/src/anetz/stations.h
@@ -0,0 +1,4 @@
+
+void station_list(void);
+int get_station_by_coordinates(double lat, double lon);
+
diff --git a/src/bnetz/Makefile.am b/src/bnetz/Makefile.am
index 8cbe388..7966a59 100644
--- a/src/bnetz/Makefile.am
+++ b/src/bnetz/Makefile.am
@@ -6,6 +6,7 @@ bin_PROGRAMS = \
bnetz_SOURCES = \
bnetz.c \
dsp.c \
+ stations.c \
image.c \
ansage.c \
main.c
diff --git a/src/bnetz/main.c b/src/bnetz/main.c
index 27d9132..c625672 100644
--- a/src/bnetz/main.c
+++ b/src/bnetz/main.c
@@ -33,6 +33,7 @@
#include "../common/besetztton.h"
#include "bnetz.h"
#include "dsp.h"
+#include "stations.h"
#include "image.h"
#include "ansage.h"
@@ -45,8 +46,11 @@ void print_help(const char *arg0)
{
print_help_common(arg0, "");
/* - - */
- printf(" -g --gfs <gruppenfreisignal>\n");
+ printf(" -g --gfs <gruppenfreisignal> | <lat>,<lon>\n");
printf(" Gruppenfreisignal\" 1..9 | 19 | 10..18 (default = '%d')\n", gfs);
+ printf(" Alternative give your coordinates of your location, to find closest\n");
+ printf(" base station. (e.g. '--gfs 54.487291,9.069993') Or use '--gfs list' to\n");
+ printf(" get a list of all base station locations.\n");
printf(" -P --pilot tone | positive | negative | <file>=<on>:<off>\n");
printf(" Send a tone, give a signal or write to a file when switching to\n");
printf(" channel 19. (paging the phone).\n");
@@ -67,6 +71,7 @@ void print_help(const char *arg0)
static int handle_options(int argc, char **argv)
{
int skip_args = 0;
+ char *p;
static struct option long_options_special[] = {
{"gfs", 1, 0, 'g'},
@@ -87,7 +92,16 @@ static int handle_options(int argc, char **argv)
switch (c) {
case 'g':
- gfs = atoi(optarg);
+ if (!strcasecmp(optarg, "list")) {
+ station_list();
+ exit(0);
+ }
+ if ((p = strchr(optarg, ','))) {
+ gfs = get_station_by_coordinates(atof(optarg), atof(p + 1));
+ if (gfs == 0)
+ exit(0);
+ } else
+ gfs = atoi(optarg);
skip_args += 2;
break;
case 'P':
diff --git a/src/bnetz/stations.c b/src/bnetz/stations.c
new file mode 100644
index 0000000..10b0ad5
--- /dev/null
+++ b/src/bnetz/stations.c
@@ -0,0 +1,295 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+static struct bnetz_stations {
+ const char *standort;
+ int gfs;
+ const char *coordinates;
+} bnetz_stations[] = {
+/* Standort GFS Koorinaten */
+ /* Germany */
+ { "Flensburg", 8, "54o47 09o26" },
+ { "Bredstedt", 2, "54o37 08o58" },
+ { "Eckernfoerde", 5, "54o28 09o50" },
+ { "Kiel", 6, "54o20 10o08" },
+ { "Heide", 7, "54o12 09o06" },
+ { "Eutin", 2, "54o08 10o37" },
+ { "Neumuenster", 1, "54o04 09o59" },
+ { "Luebeck Nord", 5, "53o54 10o38" },
+ { "Cuxhaven", 6, "53o52 08o41" },
+ { "Luebeck Sued", 8, "53o52 10o41" },
+ { "Kaltenkirchen", 4, "53o50 09o58" },
+ { "Hemmoor", 8, "53o42 09o08" },
+ { "Hamburg", 9, "53o34 10o00" },
+ { "Bremerhaven", 2, "53o33 08o35" },
+ { "Wilhelmshaven", 1, "53o31 08o08" },
+ { "Emden", 9, "53o22 07o12" },
+ { "Zeven", 5, "53o18 09o17" },
+ { "Lueneburg", 7, "53o15 10o25" },
+ { "Leer", 3, "53o14 07o27" },
+ { "Oldenburg", 8, "53o09 08o13" },
+ { "Bremen", 7, "53o05 08o48" },
+ { "Uelzen", 4, "52o58 10o33" },
+ { "Luechow", 3, "52o58 11o09" },
+ { "Werlte", 2, "52o51 07o41" },
+ { "Bergen", 2, "52o49 09o58" },
+ { "Hoya", 3, "52o48 09o08" },
+ { "Vechta", 6, "52o44 08o17" },
+ { "Lingen", 7, "52o31 07o19" },
+ { "Berlin Nord", 1, "52o31 13o23" },
+ { "Berlin Sued", 2, "52o30 13o23" },
+ { "Wolfsburg", 5, "52o25 10o47" },
+ { "Hannover", 8, "52o22 09o43" },
+ { "Osnabrueck", 4, "52o17 08o03" },
+ { "Minden", 5, "52o17 08o55" },
+ { "Braunschweig", 1, "52o16 10o31" },
+ { "Burgsteinfurt", 3, "52o09 07o21" },
+ { "Hildesheim", 7, "52o09 09o57" },
+ { "Bielefeld", 7, "52o01 08o31" },
+ { "Alfeld", 6, "51o59 09o50" },
+ { "Muenster", 6, "51o58 07o38" },
+ { "Kleve", 4, "51o47 06o08" },
+ { "Recklinghausen", 5, "51o35 07o10" },
+ { "Wesel", 8, "51o40 06o37" },
+ { "Uslar", 4, "51o40 09o38" },
+ { "Soest", 2, "51o34 08o07" },
+ { "Goettingen", 5, "51o32 09o56" },
+ { "Warburg", 3, "51o30 09o10" },
+ { "Dortmund", 1, "51o31 07o28" },
+ { "Essen", 7, "51o27 07o01" },
+ { "Duisburg", 9, "51o26 06o46" },
+ { "Meschede", 8, "51o21 08o17" },
+ { "Kassel", 7, "51o19 09o30" },
+ { "Wuppertal", 3, "51o16 07o11" },
+ { "Luedenscheid", 4, "51o13 07o38" },
+ { "Duesseldorf", 2, "51o14 06o47" },
+ { "Eschwege", 9, "51o11 10o03" },
+ { "Schmallenberg-Dorlar", 5, "51o08 08o18" },
+ { "Bad Wildungen", 1, "51o07 09o07" },
+ { "Koeln", 5, "50o56 06o57" },
+ { "Biedenkopf", 8, "50o55 08o32" },
+ { "Siegen", 7, "50o53 08o01" },
+ { "Bad Hersfeld", 2, "50o52 09o42" },
+ { "Dueren", 6, "50o48 06o29" },
+ { "Aachen", 4, "50o47 06o05" },
+ { "Bonn", 8, "50o44 07o06" },
+ { "Lauterbach", 4, "50o38 09o24" },
+ { "Lahn-Giessen", 3, "50o35 08o40" },
+ { "Fulda", 6, "50o33 09o41" },
+ { "Limburg", 2, "50o23 08o04" },
+ { "Koblenz", 9, "50o22 07o36" },
+ { "Mayen", 1, "50o20 07o13" },
+ { "Friedberg", 9, "50o20 08o45" },
+ { "Bad Brueckenau", 5, "50o19 09o47" },
+ { "Bad Neustadt", 8, "50o19 10o13" },
+ { "Hof / Saale", 4, "50o19 11o55" },
+ { "Bad Koenigshofen", 1, "50o18 10o25" },
+ { "Coburg", 2, "50o16 10o58" },
+ { "Pruem", 7, "50o12 06o25" },
+ { "St. Gorshausen", 4, "50o09 07o43" },
+ { "Hanau", 7, "50o08 08o55" },
+ { "Frankfurt", 6, "50o07 08o41" },
+ { "Wiesbaden", 5, "50o05 08o14" },
+ { "Bingen", 7, "49o58 07o54" },
+ { "Aschaffenburg", 8, "49o58 09o09" },
+ { "Bamberg", 5, "49o54 10o54" },
+ { "Darmstadt", 1, "49o52 08o39" },
+ { "Marktheidenfeld", 2, "49o51 09o36" },
+ { "Wuerzburg", 9, "49o47 09o56" },
+ { "Trier", 5, "49o45 06o38" },
+ { "Pegnitz", 1, "49o45 11o34" },
+ { "Idar-Oberstein", 8, "49o43 07o19" },
+ { "Mannheim", 3, "49o29 08o28" },
+ { "Kaiserslautern", 2, "49o27 07o46" },
+ { "Nuernberg", 9, "49o27 11o05" },
+ { "Heidelberg", 4, "49o25 08o43" },
+ { "Ansbach", 2, "49o18 10o35" },
+ { "Saarbruecken", 3, "49o14 07o00" },
+ { "Heilbronn", 7, "49o09 09o13" },
+ { "Schwaebisch Hall", 4, "49o07 09o44" },
+ { "Karlsruhe", 9, "49o01 08o24" },
+ { "Regensburg", 7, "49o01 12o05" },
+ { "Pforzheim", 6, "48o54 08o43" },
+ { "Deggendorf", 1, "48o50 12o58" },
+ { "Schwaebisch Gmuend", 1, "48o48 09o48" },
+ { "Stuttgart", 8, "48o47 09o11" },
+ { "Geislingen", 3, "48o37 09o50" },
+ { "Passau", 8, "48o34 13o28" },
+ { "Pfaffenhofen", 1, "48o32 11o31" },
+ { "Landshut", 3, "48o32 12o09" },
+ { "Offenburg", 4, "48o28 07o56" },
+ { "Pfarrkirchen", 6, "48o25 12o55" },
+ { "Ulm", 6, "48o24 09o59" },
+ { "Augsburg", 8, "48o22 10o54" },
+ { "Rottweil", 7, "48o10 08o37" },
+ { "Riedlingen", 1, "48o09 09o28" },
+ { "Muenchen", 4, "48o08 11o34" },
+ { "Wasserburg", 5, "48o03 12o14" },
+ { "Wittlich", 6, "49o59 06o53" },
+ { "Traben-Trarbach", 3, "49o57 07o07" },
+ { "Bayreuth", 6, "49o57 11o35" },
+ { "Volkach", 4, "49o52 10o13" },
+ { "Bad Kreuznach", 9, "49o51 07o52" },
+ { "Weiden", 8, "49o40 12o09" },
+ { "Wadern", 1, "49o31 06o52" },
+ { "Buchen", 1, "49o31 09o19" },
+ { "Bad Mergentheim", 5, "49o30 09o46" },
+ { "Amberg", 2, "49o27 11o51" },
+ { "Rothenburg", 6, "49o23 10o11" },
+ { "Roth", 3, "49o15 11o05" },
+ { "Pirmasens", 5, "49o12 07o36" },
+ { "Crailsheim", 8, "49o08 10o04" },
+ { "Hemau", 4, "49o03 11o47" },
+ { "Regen", 9, "48o58 13o08" },
+ { "Backnang", 9, "48o57 09o26" },
+ { "Baden-Baden", 1, "48o46 08o14" },
+ { "Wildbad", 2, "48o45 08o33" },
+ { "Donauwoerth", 5, "48o42 10o48" },
+ { "Heidenheim", 7, "48o41 10o09" },
+ { "Markt Schwaben", 9, "48o11 11o52" },
+ { "Mindelheim", 3, "48o02 10o28" },
+ { "Freiburg", 5, "47o59 07o51" },
+ { "Donaueschingen", 2, "47o57 08o30" },
+ { "Todtnau", 6, "47o50 07o57" },
+ { "Weilheim", 6, "47o50 11o09" },
+ { "Ravensburg", 4, "47o47 09o37" },
+ { "Bad Toelz", 7, "47o46 11o33" },
+ { "Kempten", 9, "47o44 10o19" },
+ { "Konstanz", 8, "47o40 09o11" },
+ { "Bad Reichenhall", 2, "47o43 12o53" },
+ { "Loerrach", 7, "47o37 07o40" },
+ { "Saeckingen", 1, "47o33 07o57" },
+ { "Garmisch-Partenkirchen", 2, "47o30 11o05" },
+
+ /* Austria */
+ { "Linz", 1, "48o18 14o17" },
+ { "Amstetten", 2, "48o07 14o52" },
+ { "St. Poelten", 3, "08o12 15o37" },
+ { "Wien-West", 1, "48o11 16o21" },
+ { "Wien-Ost", 2, "48o13 16o23" },
+ { "WR-Neustadt", 4, "48o14 16o24" },
+ { "Voecklamarkt", 4, "48o00 13o29" },
+ { "Gmunden", 3, "47o55 13o48" },
+ { "Schwaz", 8, "47o21 11o42" },
+ { "Salzburg", 3, "47o48 13o02" },
+ { "Innsbruck", 1, "47o16 11o23" },
+ { "Bruck", 3, "47o25 15o16" },
+ { "Graz", 5, "47o04 15o26" },
+
+ /* Luxemburg */
+ { "Neidhausen", 9, "50o02 06o04" },
+ { "Luxemburg", 9, "49o37 06o08" },
+
+ { NULL, 0, NULL }
+};
+
+double lat_from_coordinates(const char *string)
+{
+ if (strlen(string) != 11)
+ abort();
+ if (string[0] < '0' && string[0] > '9')
+ abort();
+ if (string[1] < '0' && string[1] > '9')
+ abort();
+ if (string[2] != 'o')
+ abort();
+ if (string[3] < '0' && string[3] > '9')
+ abort();
+ if (string[4] < '0' && string[4] > '9')
+ abort();
+
+ return (double)(string[0] - '0') * 10.0 +
+ (double)(string[1] - '0') +
+ (double)(string[3] - '0') / 6.0 +
+ (double)(string[4] - '0') / 60.0;
+}
+
+double lon_from_coordinates(const char *string)
+{
+ if (strlen(string) != 11)
+ abort();
+ if (string[6] < '0' && string[6] > '9')
+ abort();
+ if (string[7] < '0' && string[7] > '9')
+ abort();
+ if (string[8] != 'o')
+ abort();
+ if (string[9] < '0' && string[9] > '9')
+ abort();
+ if (string[10] < '0' && string[10] > '9')
+ abort();
+
+ return (double)(string[6] - '0') * 10.0 +
+ (double)(string[7] - '0') +
+ (double)(string[9] - '0') / 6.0 +
+ (double)(string[10] - '0') / 60.0;
+}
+
+#define EQUATOR_RADIUS 6378137.0
+#define POLE_RADIUS 6356752.314
+
+#define PI M_PI
+
+void station_list(void)
+{
+ int i;
+
+ printf("List of all base stations:\n");
+ for (i = 0; bnetz_stations[i].standort; i++) {
+ printf("%s (%.2f° N %.2f° E)\n", bnetz_stations[i].standort, lat_from_coordinates(bnetz_stations[i].coordinates), lon_from_coordinates(bnetz_stations[i].coordinates));
+ }
+}
+
+/* convert geo coordinates (lon/lat) to space coordinates in meters (x/y/z) */
+static void geo2space(double *x, double *y, double *z, double lat, double lon)
+{
+ *z = sin(lat / 180.0 * PI) * POLE_RADIUS;
+ *x = sin(lon / 180.0 * PI) * cos(lat / 180.0 * PI) * EQUATOR_RADIUS;
+ *y = -cos(lon / 180.0 * PI) * cos(lat / 180.0 * PI) * EQUATOR_RADIUS;
+}
+
+/* calculate distance */
+static double distinspace(double x1, double y1, double z1, double x2, double y2, double z2)
+{
+ double x = x1 - x2;
+ double y = y1 - y2;
+ double z = z1 - z2;
+
+ return sqrt(x * x + y * y + z * z);
+}
+
+
+int get_station_by_coordinates(double lat, double lon)
+{
+ double dist, min = 0.0;
+ int i, min_i = 0;
+ double x, y, z;
+ double s_lat, s_lon;
+ double s_x, s_y, s_z;
+
+ geo2space(&x, &y, &z, lat, lon);
+
+ for (i = 0; bnetz_stations[i].standort; i++) {
+ s_lat = lat_from_coordinates(bnetz_stations[i].coordinates);
+ s_lon = lon_from_coordinates(bnetz_stations[i].coordinates);
+ geo2space(&s_x, &s_y, &s_z, s_lat, s_lon);
+ dist = distinspace(x, y, z, s_x, s_y, s_z);
+ if (i == 0 || dist < min) {
+ min = dist;
+ min_i = i;
+ }
+ }
+
+ /* don't allow distance more than 100KM */
+ if (min > 100000) {
+ fprintf(stderr, "Given coordinates are more than 100 km away from base station.\n");
+ return 0;
+ }
+ printf("Closest base station: %s (distance = %.2f km)\n", bnetz_stations[min_i].standort, min / 1000.0);
+ printf(" Gruppenfreisignal = %d\n", bnetz_stations[min_i].gfs);
+
+ return bnetz_stations[min_i].gfs;
+}
+
diff --git a/src/bnetz/stations.h b/src/bnetz/stations.h
new file mode 100644
index 0000000..ddfba91
--- /dev/null
+++ b/src/bnetz/stations.h
@@ -0,0 +1,4 @@
+
+void station_list(void);
+int get_station_by_coordinates(double lat, double lon);
+