/* Conversion of logged cells to KML file */ /* (C) 2010 by Andreas Eversberg * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #warning todo bsic #include #include #include #include #include #include #define GSM_TA_M 553.85 #define PI 3.1415926536 #include #include #include #include "log.h" #include "geo.h" #include "locate.h" /* * structure of power and cell infos */ struct power power; struct sysinfo sysinfo; static struct node_power *node_power_first = NULL; static struct node_power **node_power_last_p = &node_power_first; struct node_mcc *node_mcc_first = NULL; int log_lines = 0, log_debug = 0; static void nomem(void) { fprintf(stderr, "No mem!\n"); exit(-ENOMEM); } static void add_power() { struct node_power *node_power; // printf("New Power\n"); /* append or insert to list */ node_power = calloc(1, sizeof(struct node_power)); if (!node_power) nomem(); *node_power_last_p = node_power; node_power_last_p = &node_power->next; memcpy(&node_power->power, &power, sizeof(power)); } static void print_si(void *priv, const char *fmt, ...) { char buffer[1000]; FILE *outfp = (FILE *)priv; va_list args; va_start(args, fmt); vsnprintf(buffer, sizeof(buffer) - 1, fmt, args); buffer[sizeof(buffer) - 1] = '\0'; va_end(args); if (buffer[0]) fprintf(outfp, "%s", buffer); } static void add_sysinfo() { struct gsm48_sysinfo s; struct node_mcc *mcc; struct node_mnc *mnc; struct node_lac *lac; struct node_cell *cell; struct node_meas *meas; memset(&s, 0, sizeof(s)); /* decode sysinfo */ if (sysinfo.si1[2]) gsm48_decode_sysinfo1(&s, (struct gsm48_system_information_type_1 *) sysinfo.si1, 23); if (sysinfo.si2[2]) gsm48_decode_sysinfo2(&s, (struct gsm48_system_information_type_2 *) sysinfo.si2, 23); if (sysinfo.si2bis[2]) gsm48_decode_sysinfo2bis(&s, (struct gsm48_system_information_type_2bis *) sysinfo.si2bis, 23); if (sysinfo.si2ter[2]) gsm48_decode_sysinfo2ter(&s, (struct gsm48_system_information_type_2ter *) sysinfo.si2ter, 23); if (sysinfo.si3[2]) gsm48_decode_sysinfo3(&s, (struct gsm48_system_information_type_3 *) sysinfo.si3, 23); if (sysinfo.si4[2]) gsm48_decode_sysinfo4(&s, (struct gsm48_system_information_type_4 *) sysinfo.si4, 23); printf("--------------------------------------------------------------------------\n"); gsm48_sysinfo_dump(&s, sysinfo.arfcn, print_si, stdout, NULL); mcc = get_node_mcc(s.mcc); if (!mcc) nomem(); mnc = get_node_mnc(mcc, s.mnc); if (!mnc) nomem(); lac = get_node_lac(mnc, s.lac); if (!lac) nomem(); cell = get_node_cell(lac, s.cell_id); if (!cell) nomem(); meas = add_node_meas(cell); if (!meas) nomem(); if (!cell->content) { cell->content = 1; memcpy(&cell->sysinfo, &sysinfo, sizeof(sysinfo)); memcpy(&cell->s, &s, sizeof(s)); } else { if (memcmp(&cell->sysinfo.si1, sysinfo.si1, sizeof(sysinfo.si1))) { new_sysinfo: fprintf(stderr, "FIXME: the cell changed sysinfo\n"); return; } if (memcmp(&cell->sysinfo.si2, sysinfo.si2, sizeof(sysinfo.si2))) goto new_sysinfo; if (memcmp(&cell->sysinfo.si2bis, sysinfo.si2bis, sizeof(sysinfo.si2bis))) goto new_sysinfo; if (memcmp(&cell->sysinfo.si2ter, sysinfo.si2ter, sizeof(sysinfo.si2ter))) goto new_sysinfo; if (memcmp(&cell->sysinfo.si3, sysinfo.si3, sizeof(sysinfo.si3))) goto new_sysinfo; if (memcmp(&cell->sysinfo.si4, sysinfo.si4, sizeof(sysinfo.si4))) goto new_sysinfo; } } void kml_header(FILE *outfp, char *name) { /* XML header */ fprintf(outfp, "\n"); /* KML open tag */ fprintf(outfp, "\n"); /* document open tag */ fprintf(outfp, "\n"); /* pushpin */ fprintf(outfp, "\t\n"); fprintf(outfp, "\t\n"); fprintf(outfp, "\t\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\tnormal\n"); fprintf(outfp, "\t\t\t#sn_placemark_red_pushpin" "\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\thighlight\n"); fprintf(outfp, "\t\t\t#sh_placemark_red_pushpin_highlight" "\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\n"); fprintf(outfp, "\t\n"); fprintf(outfp, "\t\n"); fprintf(outfp, "\t\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\tnormal\n"); fprintf(outfp, "\t\t\t#sn_placemark_grn_pushpin" "\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\thighlight\n"); fprintf(outfp, "\t\t\t#sh_placemark_grn_pushpin_highlight" "\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\n"); /* circle */ fprintf(outfp, "\t\n"); fprintf(outfp, "\t\n"); fprintf(outfp, "\t\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\tnormal\n"); fprintf(outfp, "\t\t\t#sn_placemark_circle\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\thighlight\n"); fprintf(outfp, "\t\t\t#sh_placemark_circle_highlight" "\n"); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\n"); } void kml_footer(FILE *outfp) { /* document close tag */ fprintf(outfp, "\n"); /* KML close tag */ fprintf(outfp, "\n"); } void kml_meas(FILE *outfp, struct node_meas *meas, int n, uint16_t mcc, uint16_t mnc, uint16_t lac, uint16_t cellid) { struct tm *tm = localtime(&meas->gmt); fprintf(outfp, "\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\t%d: %d\n", n, meas->rxlev); fprintf(outfp, "\t\t\t\t\t\t\n"); fprintf(outfp, "MCC=%s MNC=%s\nLAC=%04x CELL-ID=%04x\n(%s %s)\n", gsm_print_mcc(mcc), gsm_print_mnc(mnc), lac, cellid, gsm_get_mcc(mcc), gsm_get_mnc(mcc, mnc)); fprintf(outfp, "\n%s", asctime(tm)); fprintf(outfp, "RX-LEV %d dBm\n", meas->rxlev); if (meas->ta_valid) fprintf(outfp, "TA=%d (%d-%d meter)\n", meas->ta, (int)(GSM_TA_M * meas->ta), (int)(GSM_TA_M * (meas->ta + 1))); fprintf(outfp, "\t\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\t\t%.8f\n", meas->longitude); fprintf(outfp, "\t\t\t\t\t\t\t%.8f\n", meas->latitude); fprintf(outfp, "\t\t\t\t\t\t\t0\n"); fprintf(outfp, "\t\t\t\t\t\t\t0\n"); fprintf(outfp, "\t\t\t\t\t\t\trelativeToGround" "\n"); fprintf(outfp, "\t\t\t\t\t\t\trelativeToSeaFloor" "\n"); fprintf(outfp, "\t\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\t#msn_placemark_circle" "\n"); fprintf(outfp, "\t\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\t\t%.8f,%.8f\n", meas->longitude, meas->latitude); fprintf(outfp, "\t\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\n"); } double debug_long, debug_lat, debug_x_scale; FILE *debug_fp; void kml_cell(FILE *outfp, struct node_cell *cell) { struct node_meas *meas; double x, y, z, sum_x = 0, sum_y = 0, sum_z = 0, longitude, latitude; int n, known = 0; meas = cell->meas; n = 0; while (meas) { if (meas->gps_valid && meas->ta_valid) { geo2space(&x, &y, &z, meas->longitude, meas->latitude); sum_x += x; sum_y += y; sum_z += z; n++; } meas = meas->next; } if (!n) return; if (n < 3) { x = sum_x / n; y = sum_y / n; z = sum_z / n; space2geo(&longitude, &latitude, x, y, z); } else { struct probe *probe_first = NULL, *probe, **probe_last_p = &probe_first; double x_scale; /* translate to flat surface */ meas = cell->meas; x_scale = 1.0 / cos(meas->latitude / 180.0 * PI); longitude = meas->longitude; latitude = meas->latitude; debug_x_scale = x_scale; debug_long = longitude; debug_lat = latitude; debug_fp = outfp; while (meas) { if (meas->gps_valid && meas->ta_valid) { probe = calloc(1, sizeof(struct probe)); if (!probe) nomem(); probe->x = (meas->longitude - longitude) / x_scale; if (x < -180) x += 360; else if (x > 180) x -= 360; probe->y = meas->latitude - latitude; probe->dist = GSM_TA_M * (0.5 + (double)meas->ta) / (EQUATOR_RADIUS * PI / 180.0); *probe_last_p = probe; probe_last_p = &probe->next; } meas = meas->next; } /* locate */ locate_cell(probe_first, &x, &y); /* translate from flat surface */ longitude += x * x_scale; if (longitude < 0) longitude += 360; else if (longitude >= 360) longitude -= 360; latitude += y; /* remove probes */ while (probe_first) { probe = probe_first; probe_first = probe->next; free(probe); } known = 1; } if (!known) return; fprintf(outfp, "\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\tMCC=%s MNC=%s\nLAC=%04x " "CELL-ID=%04x\n(%s %s)\n", gsm_print_mcc(cell->s.mcc), gsm_print_mnc(cell->s.mnc), cell->s.lac, cell->s.cell_id, gsm_get_mcc(cell->s.mcc), gsm_get_mnc(cell->s.mcc, cell->s.mnc)); fprintf(outfp, "\t\t\t\t\t\t\n"); gsm48_sysinfo_dump(&cell->s, cell->sysinfo.arfcn, print_si, outfp, NULL); fprintf(outfp, "\t\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\t\t%.8f\n", longitude); fprintf(outfp, "\t\t\t\t\t\t\t%.8f\n", latitude); fprintf(outfp, "\t\t\t\t\t\t\t0\n"); fprintf(outfp, "\t\t\t\t\t\t\t0\n"); fprintf(outfp, "\t\t\t\t\t\t\trelativeToGround" "\n"); fprintf(outfp, "\t\t\t\t\t\t\trelativeToSeaFloor" "\n"); fprintf(outfp, "\t\t\t\t\t\t\n"); if (known) fprintf(outfp, "\t\t\t\t\t\t#msn_placemark_grn_" "pushpin\n"); else fprintf(outfp, "\t\t\t\t\t\t#msn_placemark_red_" "pushpin\n"); fprintf(outfp, "\t\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\t\t%.8f,%.8f\n", longitude, latitude); fprintf(outfp, "\t\t\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\t\n"); if (!log_lines) return; fprintf(outfp, "\t\n"); fprintf(outfp, "\t\tLines\n"); fprintf(outfp, "\t\t0\n"); fprintf(outfp, "\t\t0\n"); geo2space(&x, &y, &z, longitude, latitude); meas = cell->meas; n = 0; while (meas) { if (meas->gps_valid) { double mx, my, mz, dist; geo2space(&mx, &my, &mz, meas->longitude, meas->latitude); dist = distinspace(x, y, z, mx, my, mz); fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\tRange\n"); fprintf(outfp, "\t\t\t\n"); fprintf(outfp, "Distance: %d\n", (int)dist); fprintf(outfp, "TA=%d (%d-%d meter)\n", meas->ta, (int)(GSM_TA_M * meas->ta), (int)(GSM_TA_M * (meas->ta + 1))); fprintf(outfp, "\t\t\t\n"); fprintf(outfp, "\t\t\t0\n"); fprintf(outfp, "\t\t\t\n"); fprintf(outfp, "\t\t\t\t1\n"); fprintf(outfp, "\t\t\t\t\n"); fprintf(outfp, "%.8f,%.8f\n", longitude, latitude); fprintf(outfp, "%.8f,%.8f\n", meas->longitude, meas->latitude); fprintf(outfp, "\t\t\t\t\n"); fprintf(outfp, "\t\t\t\n"); fprintf(outfp, "\t\t\n"); } meas = meas->next; } fprintf(outfp, "\t\n"); } struct log_target *stderr_target; int main(int argc, char *argv[]) { FILE *infp, *outfp; int type, n, i; char *p; struct node_mcc *mcc; struct node_mnc *mnc; struct node_lac *lac; struct node_cell *cell; struct node_meas *meas; log_init(&log_info, NULL); stderr_target = log_target_create_stderr(); log_add_target(stderr_target); log_set_all_filter(stderr_target, 1); log_parse_category_mask(stderr_target, "Dxxx"); log_set_log_level(stderr_target, LOGL_INFO); if (argc <= 2) { usage: fprintf(stderr, "Usage: %s " "[lines] [debug]\n", argv[0]); fprintf(stderr, "lines: Add lines between cell and " "Measurement point\n"); fprintf(stderr, "debug: Add debugging of location algorithm.\n" ); return 0; } for (i = 3; i < argc; i++) { if (!strcmp(argv[i], "lines")) log_lines = 1; else if (!strcmp(argv[i], "debug")) log_debug = 1; else goto usage; } infp = fopen(argv[1], "r"); if (!infp) { fprintf(stderr, "Failed to open '%s' for reading\n", argv[1]); return -EIO; } while ((type = read_log(infp))) { switch (type) { case LOG_TYPE_SYSINFO: add_sysinfo(); break; case LOG_TYPE_POWER: add_power(); break; } } fclose(infp); if (!strcmp(argv[2], "-")) outfp = stdout; else outfp = fopen(argv[2], "w"); if (!outfp) { fprintf(stderr, "Failed to open '%s' for writing\n", argv[2]); return -EIO; } /* document name */ p = argv[2]; while (strchr(p, '/')) p = strchr(p, '/') + 1; kml_header(outfp, p); mcc = node_mcc_first; while (mcc) { printf("MCC: %02x\n", mcc->mcc); /* folder open */ fprintf(outfp, "\t\n"); fprintf(outfp, "\t\tMCC %s (%s)\n", gsm_print_mcc(mcc->mcc), gsm_get_mcc(mcc->mcc)); fprintf(outfp, "\t\t0\n"); mnc = mcc->mnc; while (mnc) { printf(" MNC: %02x\n", mnc->mnc); /* folder open */ fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\tMNC %s (%s)\n", gsm_print_mnc(mnc->mnc), gsm_get_mnc(mcc->mcc, mnc->mnc)); fprintf(outfp, "\t\t\t0\n"); lac = mnc->lac; while (lac) { printf(" LAC: %04x\n", lac->lac); /* folder open */ fprintf(outfp, "\t\t\t\n"); fprintf(outfp, "\t\t\t\tLAC %04x\n", lac->lac); fprintf(outfp, "\t\t\t\t0\n"); cell = lac->cell; while (cell) { printf(" CELL: %04x\n", cell->cellid); fprintf(outfp, "\t\t\t\t\n"); fprintf(outfp, "\t\t\t\t\tCELL-ID %04x\n", cell->cellid); fprintf(outfp, "\t\t\t\t\t0\n"); meas = cell->meas; n = 0; while (meas) { if (meas->ta_valid) printf(" TA: %d\n", meas->ta); if (meas->gps_valid) kml_meas(outfp, meas, ++n, mcc->mcc, mnc->mnc, lac->lac, cell->cellid); meas = meas->next; } kml_cell(outfp, cell); /* folder close */ fprintf(outfp, "\t\t\t\t\n"); cell = cell->next; } /* folder close */ fprintf(outfp, "\t\t\t\n"); lac = lac->next; } /* folder close */ fprintf(outfp, "\t\t\n"); mnc = mnc->next; } /* folder close */ fprintf(outfp, "\t\n"); mcc = mcc->next; } #if 0 FIXME: power /* folder open */ fprintf(outfp, "\t\n"); fprintf(outfp, "\t\tPower\n"); fprintf(outfp, "\t\t0\n"); power = node_power_first; n = 0; while (power) { /* folder open */ fprintf(outfp, "\t\t\n"); fprintf(outfp, "\t\t\tPower %d\n", ++n); fprintf(outfp, "\t\t\t0\n"); /* folder close */ fprintf(outfp, "\t\t\n"); power = power->next; } /* folder close */ fprintf(outfp, "\t\n"); #endif kml_footer(outfp); fclose(outfp); return 0; }