Introducing "gsmmap" to convert SYSTEM INFORMATION log into a KML map
[osmocom-bb.git] / src / host / gsmmap / log.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
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include <osmocom/bb/common/osmocom_data.h>
27
28 #include "log.h"
29
30 extern struct power power;
31 extern struct sysinfo sysinfo;
32 extern struct node_power *node_power_first;
33 extern struct node_power **node_power_last_p;
34 extern struct node_mcc *node_mcc_first;
35
36 struct node_mcc *get_node_mcc(uint16_t mcc)
37 {
38         struct node_mcc *node_mcc;
39         struct node_mcc **node_mcc_p = &node_mcc_first;
40
41 //printf("add mcc %d\n", mcc);
42         while (*node_mcc_p) {
43                 /* found in list */
44                 if ((*node_mcc_p)->mcc == mcc)
45                         return *node_mcc_p;
46                 /* insert into list */
47                 if ((*node_mcc_p)->mcc > mcc)
48                         break;
49                 node_mcc_p = &((*node_mcc_p)->next);
50         }
51
52 //printf("new mcc %d\n", mcc);
53         /* append or insert to list */
54         node_mcc = calloc(1, sizeof(struct node_mcc));
55         if (!node_mcc)
56                 return NULL;
57         node_mcc->mcc = mcc;
58         node_mcc->next = *node_mcc_p;
59         *node_mcc_p = node_mcc;
60         return node_mcc;
61 }
62
63 struct node_mnc *get_node_mnc(struct node_mcc *mcc, uint16_t mnc)
64 {
65         struct node_mnc *node_mnc;
66         struct node_mnc **node_mnc_p = &mcc->mnc;
67
68         while (*node_mnc_p) {
69                 /* found in list */
70                 if ((*node_mnc_p)->mnc == mnc)
71                         return *node_mnc_p;
72                 /* insert into list */
73                 if ((*node_mnc_p)->mnc > mnc)
74                         break;
75                 node_mnc_p = &((*node_mnc_p)->next);
76         }
77
78         /* append or insert to list */
79         node_mnc = calloc(1, sizeof(struct node_mnc));
80         if (!node_mnc)
81                 return NULL;
82         node_mnc->mnc = mnc;
83         node_mnc->next = *node_mnc_p;
84         *node_mnc_p = node_mnc;
85         return node_mnc;
86 }
87
88 struct node_lac *get_node_lac(struct node_mnc *mnc, uint16_t lac)
89 {
90         struct node_lac *node_lac;
91         struct node_lac **node_lac_p = &mnc->lac;
92
93         while (*node_lac_p) {
94                 /* found in list */
95                 if ((*node_lac_p)->lac == lac)
96                         return *node_lac_p;
97                 /* insert into list */
98                 if ((*node_lac_p)->lac > lac)
99                         break;
100                 node_lac_p = &((*node_lac_p)->next);
101         }
102
103         /* append or insert to list */
104         node_lac = calloc(1, sizeof(struct node_lac));
105         if (!node_lac)
106                 return NULL;
107         node_lac->lac = lac;
108         node_lac->next = *node_lac_p;
109         *node_lac_p = node_lac;
110         return node_lac;
111 }
112
113 struct node_cell *get_node_cell(struct node_lac *lac, uint16_t cellid)
114 {
115         struct node_cell *node_cell;
116         struct node_cell **node_cell_p = &lac->cell;
117
118         while (*node_cell_p) {
119                 /* found in list */
120                 if ((*node_cell_p)->cellid == cellid)
121                         return *node_cell_p;
122                 /* insert into list */
123                 if ((*node_cell_p)->cellid > cellid)
124                         break;
125                 node_cell_p = &((*node_cell_p)->next);
126         }
127
128         /* append or insert to list */
129         node_cell = calloc(1, sizeof(struct node_cell));
130         if (!node_cell)
131                 return NULL;
132         node_cell->meas_last_p = &node_cell->meas;
133         node_cell->cellid = cellid;
134         node_cell->next = *node_cell_p;
135         *node_cell_p = node_cell;
136         return node_cell;
137 }
138
139 struct node_meas *add_node_meas(struct node_cell *cell)
140 {
141         struct node_meas *node_meas;
142
143         /* append to list */
144         node_meas = calloc(1, sizeof(struct node_meas));
145         if (!node_meas)
146                 return NULL;
147         node_meas->gmt = sysinfo.gmt;
148         node_meas->rxlev = sysinfo.rxlev;
149         if (sysinfo.ta_valid) {
150                 node_meas->ta_valid = 1;
151                 node_meas->ta = sysinfo.ta;
152         }
153         if (sysinfo.gps_valid) {
154                 node_meas->gps_valid = 1;
155                 node_meas->longitude = sysinfo.longitude;
156                 node_meas->latitude = sysinfo.latitude;
157         }
158         *cell->meas_last_p = node_meas;
159         cell->meas_last_p = &node_meas->next;
160         return node_meas;
161 }
162
163 /* read "<ncc>,<bcc>" */
164 static void read_log_bsic(char *buffer)
165 {
166         char *p;
167         uint8_t bsic;
168
169         /* skip first spaces */
170         while (*buffer == ' ')
171                 buffer++;
172
173         /* read ncc */
174         p = buffer;
175         while (*p > ' ' && *p != ',')
176                 p++;
177         if (*p == '\0')
178                 return; /* no value */
179         *p++ = '\0';
180         bsic = atoi(buffer) << 3;
181         buffer = p;
182
183         /* read latitude */
184         bsic |= atoi(buffer);
185
186         sysinfo.bsic = bsic;
187 }
188
189 /* read "<longitude> <latitude>" */
190 static void read_log_pos(char *buffer, double *longitude, double *latitude,
191         uint8_t *valid)
192 {
193         char *p;
194
195         /* skip first spaces */
196         while (*buffer == ' ')
197                 buffer++;
198
199         /* read longitude */
200         p = buffer;
201         while (*p > ' ')
202                 p++;
203         if (*p == '\0')
204                 return; /* no value after longitude */
205         *p++ = '\0';
206         *longitude = atof(buffer);
207         buffer = p;
208
209         /* skip second spaces */
210         while (*buffer == ' ')
211                 buffer++;
212
213         /* read latitude */
214         *latitude = atof(buffer);
215
216         *valid = 1;
217 }
218
219 /* read "<arfcn> <value> <next value> ...." */
220 static void read_log_power(char *buffer)
221 {
222         char *p;
223         int arfcn;
224
225         /* skip first spaces */
226         while (*buffer == ' ')
227                 buffer++;
228
229         /* read arfcn */
230         p = buffer;
231         while (*p > ' ')
232                 p++;
233         if (*p == '\0')
234                 return; /* no value after arfcn */
235         *p++ = '\0';
236         arfcn = atoi(buffer);
237         buffer = p;
238
239         while (*buffer) {
240                 /* wrong arfcn */
241                 if (arfcn < 0 || arfcn > 1023)
242                         break;
243                 /* skip spaces */
244                 while (*buffer == ' ')
245                         buffer++;
246                 /* get value */
247                 p = buffer;
248                 while (*p > ' ')
249                         p++;
250                 /* last value */
251                 if (*p == '\0') {
252                         power.rxlev[arfcn] = atoi(buffer);
253                         break;
254                 }
255                 *p++ = '\0';
256                 power.rxlev[arfcn] = atoi(buffer);
257                 arfcn++;
258                 buffer = p;
259         }
260 }
261
262 /* read "xx xx xx xx xx...." */
263 static void read_log_si(char *buffer, uint8_t *data)
264 {
265         uint8_t si[23];
266         int i;
267
268 //      printf("%s ", buffer);
269         for (i = 0; i < 23; i++) {
270                 while (*buffer == ' ')
271                         buffer++;
272                 if (*buffer >= '0' && *buffer <= '9')
273                         si[i] = (*buffer - '0') << 4;
274                 else if (*buffer >= 'a' && *buffer <= 'f')
275                         si[i] = (*buffer - 'a' + 10) << 4;
276                 else if (*buffer >= 'A' && *buffer <= 'F')
277                         si[i] = (*buffer - 'A' + 10) << 4;
278                 else
279                         break;
280                 buffer++;
281                 if (*buffer >= '0' && *buffer <= '9')
282                         si[i] += *buffer - '0';
283                 else if (*buffer >= 'a' && *buffer <= 'f')
284                         si[i] += *buffer - 'a' + 10;
285                 else if (*buffer >= 'A' && *buffer <= 'F')
286                         si[i] += *buffer - 'A' + 10;
287                 else
288                         break;
289                 buffer++;
290 //              printf("%02x ", si[i]);
291         }
292 //      printf("\n");
293
294         if (i == 23)
295                 memcpy(data, si, 23);
296 }
297
298 /* read next record from log file */
299 int read_log(FILE *infp)
300 {
301         static int type = LOG_TYPE_NONE, ret;
302         char buffer[256];
303
304         memset(&sysinfo, 0, sizeof(sysinfo));
305         memset(&power, 0, sizeof(power));
306         memset(&power.rxlev, -128, sizeof(power.rxlev));
307
308         if (feof(infp))
309                 return LOG_TYPE_NONE;
310
311         while (fgets(buffer, sizeof(buffer), infp)) {
312                 buffer[sizeof(buffer) - 1] = 0;
313                 if (buffer[0])
314                         buffer[strlen(buffer) - 1] = '\0';
315                 if (buffer[0] == '[') {
316                         if (!strcmp(buffer, "[sysinfo]")) {
317                                 ret = type;
318                                 type = LOG_TYPE_SYSINFO;
319                                 if (ret != LOG_TYPE_NONE)
320                                         return ret;
321                         } else
322                         if (!strcmp(buffer, "[power]")) {
323                                 ret = type;
324                                 type = LOG_TYPE_POWER;
325                                 if (ret != LOG_TYPE_NONE)
326                                         return ret;
327                         } else {
328                                 type = LOG_TYPE_NONE;
329                         }
330                         continue;
331                 }
332                 switch (type) {
333                 case LOG_TYPE_SYSINFO:
334                         if (!strncmp(buffer, "arfcn ", 6))
335                                 sysinfo.arfcn = atoi(buffer + 6);
336                         else if (!strncmp(buffer, "si1 ", 4))
337                                 read_log_si(buffer + 4, sysinfo.si1);
338                         else if (!strncmp(buffer, "si2 ", 4))
339                                 read_log_si(buffer + 4, sysinfo.si2);
340                         else if (!strncmp(buffer, "si2bis ", 7))
341                                 read_log_si(buffer + 7, sysinfo.si2bis);
342                         else if (!strncmp(buffer, "si2ter ", 7))
343                                 read_log_si(buffer + 7, sysinfo.si2ter);
344                         else if (!strncmp(buffer, "si3 ", 4))
345                                 read_log_si(buffer + 4, sysinfo.si3);
346                         else if (!strncmp(buffer, "si4 ", 4))
347                                 read_log_si(buffer + 4, sysinfo.si4);
348                         else if (!strncmp(buffer, "time ", 5))
349                                 sysinfo.gmt = strtoul(buffer + 5, NULL, 0);
350                         else if (!strncmp(buffer, "position ", 9))
351                                 read_log_pos(buffer + 9, &sysinfo.longitude,
352                                         &sysinfo.latitude, &sysinfo.gps_valid);
353                         else if (!strncmp(buffer, "rxlev ", 5))
354                                 sysinfo.rxlev =
355                                         strtoul(buffer + 5, NULL, 0);
356                         else if (!strncmp(buffer, "bsic ", 5))
357                                 read_log_bsic(buffer + 5);
358                         else if (!strncmp(buffer, "ta ", 3)) {
359                                 sysinfo.ta_valid = 1;
360                                 sysinfo.ta = atoi(buffer + 3);
361                         }
362                         break;
363                 case LOG_TYPE_POWER:
364                         if (!strncmp(buffer, "arfcn ", 6))
365                                 read_log_power(buffer + 6);
366                         else if (!strncmp(buffer, "time ", 5))
367                                 power.gmt = strtoul(buffer + 5, NULL, 0);
368                         else if (!strncmp(buffer, "position ", 9))
369                                 read_log_pos(buffer + 9, &power.longitude,
370                                         &power.latitude, &sysinfo.gps_valid);
371                         break;
372                 }
373         }
374
375         return type;
376 }
377