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