038f459c92c290eadb8e4097498c15ced27c4557
[osmocom-bb.git] / src / host / gsmmap / gsmmap.c
1 /* Conversion of logged cells to KML file */
2
3 /* (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22 #warning todo bsic
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <math.h>
28 #include <time.h>
29
30 #define GSM_TA_M 553.85
31 #define PI 3.1415926536
32
33 #include <osmocom/bb/common/osmocom_data.h>
34 #include <osmocom/bb/common/networks.h>
35 #include <osmocom/bb/common/logging.h>
36
37 #include "log.h"
38 #include "geo.h"
39 #include "locate.h"
40
41 /*
42  * structure of power and cell infos
43  */
44
45 struct power power;
46 struct sysinfo sysinfo;
47 static struct node_power *node_power_first = NULL;
48 static struct node_power **node_power_last_p = &node_power_first;
49 struct node_mcc *node_mcc_first = NULL;
50 int log_lines = 0, log_debug = 0;
51
52
53 static void nomem(void)
54 {
55         fprintf(stderr, "No mem!\n");
56         exit(-ENOMEM);
57 }
58
59 static void add_power()
60 {
61         struct node_power *node_power;
62
63 //      printf("New Power\n");
64         /* append or insert to list */
65         node_power = calloc(1, sizeof(struct node_power));
66         if (!node_power)
67                 nomem();
68         *node_power_last_p = node_power;
69         node_power_last_p = &node_power->next;
70         memcpy(&node_power->power, &power, sizeof(power));
71 }
72
73 static void add_sysinfo()
74 {
75         struct gsm48_sysinfo s;
76         struct node_mcc *mcc;
77         struct node_mnc *mnc;
78         struct node_lac *lac;
79         struct node_cell *cell;
80         struct node_meas *meas;
81
82         memset(&s, 0, sizeof(s));
83
84         /* decode sysinfo */
85         if (sysinfo.si1[2])
86                 gsm48_decode_sysinfo1(&s,
87                         (struct gsm48_system_information_type_1 *) sysinfo.si1,
88                         23);
89         if (sysinfo.si2[2])
90                 gsm48_decode_sysinfo2(&s,
91                         (struct gsm48_system_information_type_2 *) sysinfo.si2,
92                         23);
93         if (sysinfo.si2bis[2])
94                 gsm48_decode_sysinfo2bis(&s,
95                         (struct gsm48_system_information_type_2bis *)
96                                 sysinfo.si2bis,
97                         23);
98         if (sysinfo.si2ter[2])
99                 gsm48_decode_sysinfo2ter(&s,
100                         (struct gsm48_system_information_type_2ter *)
101                                 sysinfo.si2ter,
102                         23);
103         if (sysinfo.si3[2])
104                 gsm48_decode_sysinfo3(&s,
105                         (struct gsm48_system_information_type_3 *) sysinfo.si3,
106                         23);
107         if (sysinfo.si4[2])
108                 gsm48_decode_sysinfo4(&s,
109                         (struct gsm48_system_information_type_4 *) sysinfo.si4,
110                         23);
111
112         mcc = get_node_mcc(s.mcc);
113         if (!mcc)
114                 nomem();
115         mnc = get_node_mnc(mcc, s.mnc);
116         if (!mnc)
117                 nomem();
118         lac = get_node_lac(mnc, s.lac);
119         if (!lac)
120                 nomem();
121         cell = get_node_cell(lac, s.cell_id);
122         if (!cell)
123                 nomem();
124         meas = add_node_meas(cell);
125         if (!meas)
126                 nomem();
127         if (!cell->content) {
128                 cell->content = 1;
129                 memcpy(&cell->sysinfo, &sysinfo, sizeof(sysinfo));
130                 memcpy(&cell->s, &s, sizeof(s));
131         } else {
132                 if (memcmp(&cell->sysinfo.si1, sysinfo.si1,
133                         sizeof(sysinfo.si1))) {
134 new_sysinfo:
135                         fprintf(stderr, "FIXME: the cell changed sysinfo\n");
136                         return;
137                 }
138                 if (memcmp(&cell->sysinfo.si2, sysinfo.si2,
139                         sizeof(sysinfo.si2)))
140                         goto new_sysinfo;
141                 if (memcmp(&cell->sysinfo.si2bis, sysinfo.si2bis,
142                         sizeof(sysinfo.si2bis)))
143                         goto new_sysinfo;
144                 if (memcmp(&cell->sysinfo.si2ter, sysinfo.si2ter,
145                         sizeof(sysinfo.si2ter)))
146                         goto new_sysinfo;
147                 if (memcmp(&cell->sysinfo.si3, sysinfo.si3,
148                         sizeof(sysinfo.si3)))
149                         goto new_sysinfo;
150                 if (memcmp(&cell->sysinfo.si4, sysinfo.si4,
151                         sizeof(sysinfo.si4)))
152                         goto new_sysinfo;
153         }
154 }
155
156 void kml_header(FILE *outfp, char *name)
157 {
158         /* XML header */
159         fprintf(outfp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
160
161         /* KML open tag */
162         fprintf(outfp, "<kml xmlns=\"http://www.opengis.net/kml/2.2\" "
163                 "xmlns:gx=\"http://www.google.com/kml/ext/2.2\" "
164                 "xmlns:kml=\"http://www.opengis.net/kml/2.2\" "
165                 "xmlns:atom=\"http://www.w3.org/2005/Atom\">\n");
166
167         /* document open tag */
168         fprintf(outfp, "<Document>\n");
169
170         /* pushpin */
171         fprintf(outfp, "\t<Style id=\"sn_placemark_red_pushpin\">\n");
172         fprintf(outfp, "\t\t<IconStyle>\n");
173         fprintf(outfp, "\t\t\t<scale>1.1</scale>\n");
174         fprintf(outfp, "\t\t\t<Icon>\n");
175         fprintf(outfp, "\t\t\t\t<href>http://maps.google.com/mapfiles/kml/"
176                 "pushpin/red-pushpin.png</href>\n");
177         fprintf(outfp, "\t\t\t</Icon>\n");
178         fprintf(outfp, "\t\t</IconStyle>\n");
179         fprintf(outfp, "\t\t<ListStyle>\n");
180         fprintf(outfp, "\t\t</ListStyle>\n");
181         fprintf(outfp, "\t</Style>\n");
182         fprintf(outfp, "\t<Style id=\"sh_placemark_red_pushpin_highlight\">\n");
183         fprintf(outfp, "\t\t<IconStyle>\n");
184         fprintf(outfp, "\t\t\t<scale>1.3</scale>\n");
185         fprintf(outfp, "\t\t\t<Icon>\n");
186         fprintf(outfp, "\t\t\t\t<href>http://maps.google.com/mapfiles/kml/"
187                 "pushpin/red-pushpin.png</href>\n");
188         fprintf(outfp, "\t\t\t</Icon>\n");
189         fprintf(outfp, "\t\t</IconStyle>\n");
190         fprintf(outfp, "\t\t<ListStyle>\n");
191         fprintf(outfp, "\t\t</ListStyle>\n");
192         fprintf(outfp, "\t</Style>\n");
193         fprintf(outfp, "\t<StyleMap id=\"msn_placemark_red_pushpin\">\n");
194         fprintf(outfp, "\t\t<Pair>\n");
195         fprintf(outfp, "\t\t\t<key>normal</key>\n");
196         fprintf(outfp, "\t\t\t<styleUrl>#sn_placemark_red_pushpin"
197                 "</styleUrl>\n");
198         fprintf(outfp, "\t\t</Pair>\n");
199         fprintf(outfp, "\t\t<Pair>\n");
200         fprintf(outfp, "\t\t\t<key>highlight</key>\n");
201         fprintf(outfp, "\t\t\t<styleUrl>#sh_placemark_red_pushpin_highlight"
202                 "</styleUrl>\n");
203         fprintf(outfp, "\t\t</Pair>\n");
204         fprintf(outfp, "\t</StyleMap>\n");
205
206         fprintf(outfp, "\t<Style id=\"sn_placemark_grn_pushpin\">\n");
207         fprintf(outfp, "\t\t<IconStyle>\n");
208         fprintf(outfp, "\t\t\t<scale>1.1</scale>\n");
209         fprintf(outfp, "\t\t\t<Icon>\n");
210         fprintf(outfp, "\t\t\t\t<href>http://maps.google.com/mapfiles/kml/"
211                 "pushpin/grn-pushpin.png</href>\n");
212         fprintf(outfp, "\t\t\t</Icon>\n");
213         fprintf(outfp, "\t\t</IconStyle>\n");
214         fprintf(outfp, "\t\t<ListStyle>\n");
215         fprintf(outfp, "\t\t</ListStyle>\n");
216         fprintf(outfp, "\t</Style>\n");
217         fprintf(outfp, "\t<Style id=\"sh_placemark_grn_pushpin_highlight\">\n");
218         fprintf(outfp, "\t\t<IconStyle>\n");
219         fprintf(outfp, "\t\t\t<scale>1.3</scale>\n");
220         fprintf(outfp, "\t\t\t<Icon>\n");
221         fprintf(outfp, "\t\t\t\t<href>http://maps.google.com/mapfiles/kml/"
222                 "pushpin/grn-pushpin.png</href>\n");
223         fprintf(outfp, "\t\t\t</Icon>\n");
224         fprintf(outfp, "\t\t</IconStyle>\n");
225         fprintf(outfp, "\t\t<ListStyle>\n");
226         fprintf(outfp, "\t\t</ListStyle>\n");
227         fprintf(outfp, "\t</Style>\n");
228         fprintf(outfp, "\t<StyleMap id=\"msn_placemark_grn_pushpin\">\n");
229         fprintf(outfp, "\t\t<Pair>\n");
230         fprintf(outfp, "\t\t\t<key>normal</key>\n");
231         fprintf(outfp, "\t\t\t<styleUrl>#sn_placemark_grn_pushpin"
232                 "</styleUrl>\n");
233         fprintf(outfp, "\t\t</Pair>\n");
234         fprintf(outfp, "\t\t<Pair>\n");
235         fprintf(outfp, "\t\t\t<key>highlight</key>\n");
236         fprintf(outfp, "\t\t\t<styleUrl>#sh_placemark_grn_pushpin_highlight"
237                 "</styleUrl>\n");
238         fprintf(outfp, "\t\t</Pair>\n");
239         fprintf(outfp, "\t</StyleMap>\n");
240
241         /* circle */
242         fprintf(outfp, "\t<Style id=\"sn_placemark_circle\">\n");
243         fprintf(outfp, "\t\t<IconStyle>\n");
244         fprintf(outfp, "\t\t\t<scale>1.0</scale>\n");
245         fprintf(outfp, "\t\t\t<Icon>\n");
246         fprintf(outfp, "\t\t\t\t<href>http://maps.google.com/mapfiles/kml/"
247                 "shapes/placemark_circle.png</href>\n");
248         fprintf(outfp, "\t\t\t</Icon>\n");
249         fprintf(outfp, "\t\t</IconStyle>\n");
250         fprintf(outfp, "\t\t<ListStyle>\n");
251         fprintf(outfp, "\t\t</ListStyle>\n");
252         fprintf(outfp, "\t</Style>\n");
253         fprintf(outfp, "\t<Style id=\"sh_placemark_circle_highlight\">\n");
254         fprintf(outfp, "\t\t<IconStyle>\n");
255         fprintf(outfp, "\t\t\t<scale>1.2</scale>\n");
256         fprintf(outfp, "\t\t\t<Icon>\n");
257         fprintf(outfp, "\t\t\t\t<href>http://maps.google.com/mapfiles/kml/"
258                 "shapes/placemark_circle_highlight.png</href>\n");
259         fprintf(outfp, "\t\t\t</Icon>\n");
260         fprintf(outfp, "\t\t</IconStyle>\n");
261         fprintf(outfp, "\t\t<ListStyle>\n");
262         fprintf(outfp, "\t\t</ListStyle>\n");
263         fprintf(outfp, "\t</Style>\n");
264         fprintf(outfp, "\t<StyleMap id=\"msn_placemark_circle\">\n");
265         fprintf(outfp, "\t\t<Pair>\n");
266         fprintf(outfp, "\t\t\t<key>normal</key>\n");
267         fprintf(outfp, "\t\t\t<styleUrl>#sn_placemark_circle</styleUrl>\n");
268         fprintf(outfp, "\t\t</Pair>\n");
269         fprintf(outfp, "\t\t<Pair>\n");
270         fprintf(outfp, "\t\t\t<key>highlight</key>\n");
271         fprintf(outfp, "\t\t\t<styleUrl>#sh_placemark_circle_highlight"
272                 "</styleUrl>\n");
273         fprintf(outfp, "\t\t</Pair>\n");
274         fprintf(outfp, "\t</StyleMap>\n");
275 }
276
277 void kml_footer(FILE *outfp)
278 {
279         /* document close tag */
280         fprintf(outfp, "</Document>\n");
281
282         /* KML close tag */
283         fprintf(outfp, "</kml>\n");
284
285 }
286
287 void kml_meas(FILE *outfp, struct node_meas *meas, int n, uint16_t mcc,
288         uint16_t mnc, uint16_t lac, uint16_t cellid)
289 {
290         struct tm *tm = localtime(&meas->gmt);
291
292         fprintf(outfp, "\t\t\t\t\t<Placemark>\n");
293         fprintf(outfp, "\t\t\t\t\t\t<name>%d: %d</name>\n", n, meas->rxlev);
294         fprintf(outfp, "\t\t\t\t\t\t<description>\n");
295         fprintf(outfp, "MCC=%s MNC=%s\nLAC=%04x CELL-ID=%04x\n(%s %s)\n",
296                 gsm_print_mcc(mcc), gsm_print_mnc(mnc), lac, cellid,
297                 gsm_get_mcc(mcc), gsm_get_mnc(mcc, mnc));
298         fprintf(outfp, "\n%s", asctime(tm));
299         fprintf(outfp, "RX-LEV %d dBm\n", meas->rxlev);
300         if (meas->ta_valid)
301                 fprintf(outfp, "TA=%d (%d-%d meter)\n", meas->ta,
302                         (int)(GSM_TA_M * meas->ta),
303                         (int)(GSM_TA_M * (meas->ta + 1)));
304         fprintf(outfp, "\t\t\t\t\t\t</description>\n");
305         fprintf(outfp, "\t\t\t\t\t\t<LookAt>\n");
306         fprintf(outfp, "\t\t\t\t\t\t\t<longitude>%.8f</longitude>\n",
307                 meas->longitude);
308         fprintf(outfp, "\t\t\t\t\t\t\t<latitude>%.8f</latitude>\n",
309                 meas->latitude);
310         fprintf(outfp, "\t\t\t\t\t\t\t<altitude>0</altitude>\n");
311         fprintf(outfp, "\t\t\t\t\t\t\t<tilt>0</tilt>\n");
312         fprintf(outfp, "\t\t\t\t\t\t\t<altitudeMode>relativeToGround"
313                 "</altitudeMode>\n");
314         fprintf(outfp, "\t\t\t\t\t\t\t<gx:altitudeMode>relativeToSeaFloor"
315                 "</gx:altitudeMode>\n");
316         fprintf(outfp, "\t\t\t\t\t\t</LookAt>\n");
317         fprintf(outfp, "\t\t\t\t\t\t<styleUrl>#msn_placemark_circle"
318                 "</styleUrl>\n");
319         fprintf(outfp, "\t\t\t\t\t\t<Point>\n");
320         fprintf(outfp, "\t\t\t\t\t\t\t<coordinates>%.8f,%.8f</coordinates>\n",
321                 meas->longitude, meas->latitude);
322         fprintf(outfp, "\t\t\t\t\t\t</Point>\n");
323         fprintf(outfp, "\t\t\t\t\t</Placemark>\n");
324 }
325
326 static void print_si(void *priv, const char *fmt, ...)
327 {
328         char buffer[1000];
329         FILE *outfp = (FILE *)priv;
330         va_list args;
331
332         va_start(args, fmt);
333         vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
334         buffer[sizeof(buffer) - 1] = '\0';
335         va_end(args);
336
337         if (buffer[0])
338                 fprintf(outfp, "%s", buffer);
339 }
340
341 double debug_long, debug_lat, debug_x_scale;
342 FILE *debug_fp;
343
344 void kml_cell(FILE *outfp, struct node_cell *cell)
345 {
346         struct node_meas *meas;
347         double x, y, z, sum_x = 0, sum_y = 0, sum_z = 0, longitude, latitude;
348         int n, known = 0;
349
350         meas = cell->meas;
351         n = 0;
352         while (meas) {
353                 if (meas->gps_valid && meas->ta_valid) {
354                         geo2space(&x, &y, &z, meas->longitude, meas->latitude);
355                         sum_x += x;
356                         sum_y += y;
357                         sum_z += z;
358                         n++;
359                 }
360                 meas = meas->next;
361         }
362         if (!n)
363                 return;
364         if (n < 3) {
365                 x = sum_x / n;
366                 y = sum_y / n;
367                 z = sum_z / n;
368                 space2geo(&longitude, &latitude, x, y, z);
369         } else {
370                 struct probe *probe_first = NULL, *probe,
371                              **probe_last_p = &probe_first;
372                 double x_scale;
373
374                 /* translate to flat surface */
375                 meas = cell->meas;
376                 x_scale = 1.0 / cos(meas->latitude / 180.0 * PI);
377                 longitude = meas->longitude;
378                 latitude = meas->latitude;
379                 debug_x_scale = x_scale;
380                 debug_long = longitude;
381                 debug_lat = latitude;
382                 debug_fp = outfp;
383                 while (meas) {
384                         if (meas->gps_valid && meas->ta_valid) {
385                                 probe = calloc(1, sizeof(struct probe));
386                                 if (!probe)
387                                         nomem();
388                                 probe->x = (meas->longitude - longitude) /
389                                                 x_scale;
390                                 if (x < -180)
391                                         x += 360;
392                                 else if (x > 180)
393                                         x -= 360;
394                                 probe->y = meas->latitude - latitude;
395                                 probe->dist = GSM_TA_M * (0.5 +
396                                         (double)meas->ta) /
397                                         (EQUATOR_RADIUS * PI / 180.0);
398                                 *probe_last_p = probe;
399                                 probe_last_p = &probe->next;
400                         }
401                         meas = meas->next;
402                 }
403
404                 /* locate */
405                 locate_cell(probe_first, &x, &y);
406
407                 /* translate from flat surface */
408                 longitude += x * x_scale;
409                 if (longitude < 0)
410                         longitude += 360;
411                 else if (longitude >= 360)
412                         longitude -= 360;
413                 latitude += y;
414
415                 /* remove probes */
416                 while (probe_first) {
417                         probe = probe_first;
418                         probe_first = probe->next;
419                         free(probe);
420                 }
421
422                 known = 1;
423         }
424
425         if (!known)
426                 return;
427
428         fprintf(outfp, "\t\t\t\t\t<Placemark>\n");
429         fprintf(outfp, "\t\t\t\t\t\t<name>MCC=%s MNC=%s\nLAC=%04x "
430                 "CELL-ID=%04x\n(%s %s)</name>\n", gsm_print_mcc(cell->s.mcc),
431                 gsm_print_mnc(cell->s.mnc), cell->s.lac, cell->s.cell_id,
432                 gsm_get_mcc(cell->s.mcc),
433                 gsm_get_mnc(cell->s.mcc, cell->s.mnc));
434         fprintf(outfp, "\t\t\t\t\t\t<description>\n");
435         gsm48_sysinfo_dump(&cell->s, cell->sysinfo.arfcn, print_si, outfp,
436                 NULL);
437         fprintf(outfp, "\t\t\t\t\t\t</description>\n");
438         fprintf(outfp, "\t\t\t\t\t\t<LookAt>\n");
439         fprintf(outfp, "\t\t\t\t\t\t\t<longitude>%.8f</longitude>\n",
440                 longitude);
441         fprintf(outfp, "\t\t\t\t\t\t\t<latitude>%.8f</latitude>\n", latitude);
442         fprintf(outfp, "\t\t\t\t\t\t\t<altitude>0</altitude>\n");
443         fprintf(outfp, "\t\t\t\t\t\t\t<tilt>0</tilt>\n");
444         fprintf(outfp, "\t\t\t\t\t\t\t<altitudeMode>relativeToGround"
445                 "</altitudeMode>\n");
446         fprintf(outfp, "\t\t\t\t\t\t\t<gx:altitudeMode>relativeToSeaFloor"
447                 "</gx:altitudeMode>\n");
448         fprintf(outfp, "\t\t\t\t\t\t</LookAt>\n");
449         if (known)
450                 fprintf(outfp, "\t\t\t\t\t\t<styleUrl>#msn_placemark_grn_"
451                         "pushpin</styleUrl>\n");
452         else
453                 fprintf(outfp, "\t\t\t\t\t\t<styleUrl>#msn_placemark_red_"
454                         "pushpin</styleUrl>\n");
455         fprintf(outfp, "\t\t\t\t\t\t<Point>\n");
456         fprintf(outfp, "\t\t\t\t\t\t\t<coordinates>%.8f,%.8f</coordinates>\n",
457                 longitude, latitude);
458         fprintf(outfp, "\t\t\t\t\t\t</Point>\n");
459         fprintf(outfp, "\t\t\t\t\t</Placemark>\n");
460
461         if (!log_lines)
462                 return;
463
464         fprintf(outfp, "\t<Folder>\n");
465         fprintf(outfp, "\t\t<name>Lines</name>\n");
466         fprintf(outfp, "\t\t<open>0</open>\n");
467         fprintf(outfp, "\t\t<visibility>0</visibility>\n");
468
469         geo2space(&x, &y, &z, longitude, latitude);
470         meas = cell->meas;
471         n = 0;
472         while (meas) {
473                 if (meas->gps_valid) {
474                         double mx, my, mz, dist;
475
476                         geo2space(&mx, &my, &mz, meas->longitude,
477                                 meas->latitude);
478                         dist = distinspace(x, y, z, mx, my, mz);
479                         fprintf(outfp, "\t\t<Placemark>\n");
480                         fprintf(outfp, "\t\t\t<name>Range</name>\n");
481                         fprintf(outfp, "\t\t\t<description>\n");
482                         fprintf(outfp, "Distance: %d\n", (int)dist);
483                         fprintf(outfp, "TA=%d (%d-%d meter)\n", meas->ta,
484                                 (int)(GSM_TA_M * meas->ta),
485                                 (int)(GSM_TA_M * (meas->ta + 1)));
486                         fprintf(outfp, "\t\t\t</description>\n");
487                         fprintf(outfp, "\t\t\t<visibility>0</visibility>\n");
488                         fprintf(outfp, "\t\t\t<LineString>\n");
489                         fprintf(outfp, "\t\t\t\t<tessellate>1</tessellate>\n");
490                         fprintf(outfp, "\t\t\t\t<coordinates>\n");
491                         fprintf(outfp, "%.8f,%.8f\n", longitude, latitude);
492                         fprintf(outfp, "%.8f,%.8f\n", meas->longitude,
493                                 meas->latitude);
494                         fprintf(outfp, "\t\t\t\t</coordinates>\n");
495                         fprintf(outfp, "\t\t\t</LineString>\n");
496                         fprintf(outfp, "\t\t</Placemark>\n");
497                 }
498                 meas = meas->next;
499         }
500         fprintf(outfp, "\t</Folder>\n");
501 }
502
503 struct log_target *stderr_target;
504
505 int main(int argc, char *argv[])
506 {
507         FILE *infp, *outfp;
508         int type, n, i;
509         char *p;
510         struct node_mcc *mcc;
511         struct node_mnc *mnc;
512         struct node_lac *lac;
513         struct node_cell *cell;
514         struct node_meas *meas;
515
516         log_init(&log_info, NULL);
517         stderr_target = log_target_create_stderr();
518         log_add_target(stderr_target);
519         log_set_all_filter(stderr_target, 1);
520         log_parse_category_mask(stderr_target, "Dxxx");
521         log_set_log_level(stderr_target, LOGL_INFO);
522
523         if (argc <= 2) {
524 usage:
525                 fprintf(stderr, "Usage: %s <file.log> <file.kml> "
526                         "[lines] [debug]\n", argv[0]);
527                 fprintf(stderr, "lines: Add lines between cell and "
528                         "Measurement point\n");
529                 fprintf(stderr, "debug: Add debugging of location algorithm.\n"
530                         );
531                 return 0;
532         }
533
534         for (i = 3; i < argc; i++) {
535                 if (!strcmp(argv[i], "lines"))
536                         log_lines = 1;
537                 else if (!strcmp(argv[i], "debug"))
538                         log_debug = 1;
539                 else goto usage;
540         }
541
542         infp = fopen(argv[1], "r");
543         if (!infp) {
544                 fprintf(stderr, "Failed to open '%s' for reading\n", argv[1]);
545                 return -EIO;
546         }
547
548         while ((type = read_log(infp))) {
549                 switch (type) {
550                 case LOG_TYPE_SYSINFO:
551                         add_sysinfo();
552                         break;
553                 case LOG_TYPE_POWER:
554                         add_power();
555                         break;
556                 }
557         }
558
559         fclose(infp);
560
561         if (!strcmp(argv[2], "-"))
562                 outfp = stdout;
563         else
564                 outfp = fopen(argv[2], "w");
565         if (!outfp) {
566                 fprintf(stderr, "Failed to open '%s' for writing\n", argv[2]);
567                 return -EIO;
568         }
569
570         /* document name */
571         p = argv[2];
572         while (strchr(p, '/'))
573                 p = strchr(p, '/') + 1;
574
575         kml_header(outfp, p);
576         mcc = node_mcc_first;
577         while (mcc) {
578           printf("MCC: %02x\n", mcc->mcc);
579          /* folder open */
580           fprintf(outfp, "\t<Folder>\n");
581           fprintf(outfp, "\t\t<name>MCC %s (%s)</name>\n",
582                 gsm_print_mcc(mcc->mcc), gsm_get_mcc(mcc->mcc));
583           fprintf(outfp, "\t\t<open>0</open>\n");
584           mnc = mcc->mnc;
585           while (mnc) {
586             printf(" MNC: %02x\n", mnc->mnc);
587             /* folder open */
588             fprintf(outfp, "\t\t<Folder>\n");
589             fprintf(outfp, "\t\t\t<name>MNC %s (%s)</name>\n",
590                 gsm_print_mnc(mnc->mnc), gsm_get_mnc(mcc->mcc, mnc->mnc));
591             fprintf(outfp, "\t\t\t<open>0</open>\n");
592             lac = mnc->lac;
593             while (lac) {
594               printf("  LAC: %04x\n", lac->lac);
595               /* folder open */
596               fprintf(outfp, "\t\t\t<Folder>\n");
597               fprintf(outfp, "\t\t\t\t<name>LAC %04x</name>\n", lac->lac);
598               fprintf(outfp, "\t\t\t\t<open>0</open>\n");
599               cell = lac->cell;
600               while (cell) {
601                 printf("   CELL: %04x\n", cell->cellid);
602                 fprintf(outfp, "\t\t\t\t<Folder>\n");
603                 fprintf(outfp, "\t\t\t\t\t<name>CELL-ID %04x</name>\n", cell->cellid);
604                 fprintf(outfp, "\t\t\t\t\t<open>0</open>\n");
605                 meas = cell->meas;
606                 n = 0;
607                 while (meas) {
608                         if (meas->ta_valid)
609                                 printf("    TA: %d\n", meas->ta);
610                         if (meas->gps_valid)
611                                 kml_meas(outfp, meas, ++n, mcc->mcc, mnc->mnc,
612                                         lac->lac, cell->cellid);
613                         meas = meas->next;
614                 }
615                 kml_cell(outfp, cell);
616                 /* folder close */
617                 fprintf(outfp, "\t\t\t\t</Folder>\n");
618                 cell = cell->next;
619               }
620               /* folder close */
621               fprintf(outfp, "\t\t\t</Folder>\n");
622               lac = lac->next;
623             }
624             /* folder close */
625             fprintf(outfp, "\t\t</Folder>\n");
626             mnc = mnc->next;
627           }
628           /* folder close */
629           fprintf(outfp, "\t</Folder>\n");
630           mcc = mcc->next;
631         }
632 #if 0
633         FIXME: power
634         /* folder open */
635         fprintf(outfp, "\t<Folder>\n");
636         fprintf(outfp, "\t\t<name>Power</name>\n");
637         fprintf(outfp, "\t\t<open>0</open>\n");
638         power = node_power_first;
639         n = 0;
640         while (power) {
641                 /* folder open */
642                 fprintf(outfp, "\t\t<Folder>\n");
643                 fprintf(outfp, "\t\t\t<name>Power %d</name>\n", ++n);
644                 fprintf(outfp, "\t\t\t<open>0</open>\n");
645                 /* folder close */
646                 fprintf(outfp, "\t\t</Folder>\n");
647                 power = power->next;
648         }
649         /* folder close */
650         fprintf(outfp, "\t</Folder>\n");
651 #endif
652         kml_footer(outfp);
653
654         fclose(outfp);
655
656         return 0;
657 }