1 /* Conversion of logged cells to KML file */
3 /* (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
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.
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.
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.
30 #define GSM_TA_M 553.85
31 #define PI 3.1415926536
33 #include <osmocom/bb/common/osmocom_data.h>
34 #include <osmocom/bb/common/networks.h>
35 #include <osmocom/bb/common/logging.h>
42 * structure of power and cell infos
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;
53 static void nomem(void)
55 fprintf(stderr
, "No mem!\n");
59 static void add_power()
61 struct node_power
*node_power
;
63 // printf("New Power\n");
64 /* append or insert to list */
65 node_power
= calloc(1, sizeof(struct node_power
));
68 *node_power_last_p
= node_power
;
69 node_power_last_p
= &node_power
->next
;
70 memcpy(&node_power
->power
, &power
, sizeof(power
));
73 static void add_sysinfo()
75 struct gsm48_sysinfo s
;
79 struct node_cell
*cell
;
80 struct node_meas
*meas
;
82 memset(&s
, 0, sizeof(s
));
86 gsm48_decode_sysinfo1(&s
,
87 (struct gsm48_system_information_type_1
*) sysinfo
.si1
,
90 gsm48_decode_sysinfo2(&s
,
91 (struct gsm48_system_information_type_2
*) sysinfo
.si2
,
93 if (sysinfo
.si2bis
[2])
94 gsm48_decode_sysinfo2bis(&s
,
95 (struct gsm48_system_information_type_2bis
*)
98 if (sysinfo
.si2ter
[2])
99 gsm48_decode_sysinfo2ter(&s
,
100 (struct gsm48_system_information_type_2ter
*)
104 gsm48_decode_sysinfo3(&s
,
105 (struct gsm48_system_information_type_3
*) sysinfo
.si3
,
108 gsm48_decode_sysinfo4(&s
,
109 (struct gsm48_system_information_type_4
*) sysinfo
.si4
,
112 mcc
= get_node_mcc(s
.mcc
);
115 mnc
= get_node_mnc(mcc
, s
.mnc
);
118 lac
= get_node_lac(mnc
, s
.lac
);
121 cell
= get_node_cell(lac
, s
.cell_id
);
124 meas
= add_node_meas(cell
);
127 if (!cell
->content
) {
129 memcpy(&cell
->sysinfo
, &sysinfo
, sizeof(sysinfo
));
130 memcpy(&cell
->s
, &s
, sizeof(s
));
132 if (memcmp(&cell
->sysinfo
.si1
, sysinfo
.si1
,
133 sizeof(sysinfo
.si1
))) {
135 fprintf(stderr
, "FIXME: the cell changed sysinfo\n");
138 if (memcmp(&cell
->sysinfo
.si2
, sysinfo
.si2
,
139 sizeof(sysinfo
.si2
)))
141 if (memcmp(&cell
->sysinfo
.si2bis
, sysinfo
.si2bis
,
142 sizeof(sysinfo
.si2bis
)))
144 if (memcmp(&cell
->sysinfo
.si2ter
, sysinfo
.si2ter
,
145 sizeof(sysinfo
.si2ter
)))
147 if (memcmp(&cell
->sysinfo
.si3
, sysinfo
.si3
,
148 sizeof(sysinfo
.si3
)))
150 if (memcmp(&cell
->sysinfo
.si4
, sysinfo
.si4
,
151 sizeof(sysinfo
.si4
)))
156 void kml_header(FILE *outfp
, char *name
)
159 fprintf(outfp
, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
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");
167 /* document open tag */
168 fprintf(outfp
, "<Document>\n");
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"
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"
203 fprintf(outfp
, "\t\t</Pair>\n");
204 fprintf(outfp
, "\t</StyleMap>\n");
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"
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"
238 fprintf(outfp
, "\t\t</Pair>\n");
239 fprintf(outfp
, "\t</StyleMap>\n");
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"
273 fprintf(outfp
, "\t\t</Pair>\n");
274 fprintf(outfp
, "\t</StyleMap>\n");
277 void kml_footer(FILE *outfp
)
279 /* document close tag */
280 fprintf(outfp
, "</Document>\n");
283 fprintf(outfp
, "</kml>\n");
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
)
290 struct tm
*tm
= localtime(&meas
->gmt
);
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
);
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",
308 fprintf(outfp
, "\t\t\t\t\t\t\t<latitude>%.8f</latitude>\n",
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"
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");
326 static void print_si(void *priv
, const char *fmt
, ...)
329 FILE *outfp
= (FILE *)priv
;
333 vsnprintf(buffer
, sizeof(buffer
) - 1, fmt
, args
);
334 buffer
[sizeof(buffer
) - 1] = '\0';
338 fprintf(outfp
, "%s", buffer
);
341 double debug_long
, debug_lat
, debug_x_scale
;
344 void kml_cell(FILE *outfp
, struct node_cell
*cell
)
346 struct node_meas
*meas
;
347 double x
, y
, z
, sum_x
= 0, sum_y
= 0, sum_z
= 0, longitude
, latitude
;
353 if (meas
->gps_valid
&& meas
->ta_valid
) {
354 geo2space(&x
, &y
, &z
, meas
->longitude
, meas
->latitude
);
368 space2geo(&longitude
, &latitude
, x
, y
, z
);
370 struct probe
*probe_first
= NULL
, *probe
,
371 **probe_last_p
= &probe_first
;
374 /* translate to flat surface */
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
;
384 if (meas
->gps_valid
&& meas
->ta_valid
) {
385 probe
= calloc(1, sizeof(struct probe
));
388 probe
->x
= (meas
->longitude
- longitude
) /
394 probe
->y
= meas
->latitude
- latitude
;
395 probe
->dist
= GSM_TA_M
* (0.5 +
397 (EQUATOR_RADIUS
* PI
/ 180.0);
398 *probe_last_p
= probe
;
399 probe_last_p
= &probe
->next
;
405 locate_cell(probe_first
, &x
, &y
);
407 /* translate from flat surface */
408 longitude
+= x
* x_scale
;
411 else if (longitude
>= 360)
416 while (probe_first
) {
418 probe_first
= probe
->next
;
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
,
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",
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");
450 fprintf(outfp
, "\t\t\t\t\t\t<styleUrl>#msn_placemark_grn_"
451 "pushpin</styleUrl>\n");
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");
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");
469 geo2space(&x
, &y
, &z
, longitude
, latitude
);
473 if (meas
->gps_valid
) {
474 double mx
, my
, mz
, dist
;
476 geo2space(&mx
, &my
, &mz
, meas
->longitude
,
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
,
494 fprintf(outfp
, "\t\t\t\t</coordinates>\n");
495 fprintf(outfp
, "\t\t\t</LineString>\n");
496 fprintf(outfp
, "\t\t</Placemark>\n");
500 fprintf(outfp
, "\t</Folder>\n");
503 struct log_target
*stderr_target
;
505 int main(int argc
, char *argv
[])
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
;
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
);
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"
534 for (i
= 3; i
< argc
; i
++) {
535 if (!strcmp(argv
[i
], "lines"))
537 else if (!strcmp(argv
[i
], "debug"))
542 infp
= fopen(argv
[1], "r");
544 fprintf(stderr
, "Failed to open '%s' for reading\n", argv
[1]);
548 while ((type
= read_log(infp
))) {
550 case LOG_TYPE_SYSINFO
:
561 if (!strcmp(argv
[2], "-"))
564 outfp
= fopen(argv
[2], "w");
566 fprintf(stderr
, "Failed to open '%s' for writing\n", argv
[2]);
572 while (strchr(p
, '/'))
573 p
= strchr(p
, '/') + 1;
575 kml_header(outfp
, p
);
576 mcc
= node_mcc_first
;
578 printf("MCC: %02x\n", mcc
->mcc
);
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");
586 printf(" MNC: %02x\n", mnc
->mnc
);
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");
594 printf(" LAC: %04x\n", lac
->lac
);
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");
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");
609 printf(" TA: %d\n", meas
->ta
);
611 kml_meas(outfp
, meas
, ++n
, mcc
->mcc
, mnc
->mnc
,
612 lac
->lac
, cell
->cellid
);
615 kml_cell(outfp
, cell
);
617 fprintf(outfp
, "\t\t\t\t</Folder>\n");
621 fprintf(outfp
, "\t\t\t</Folder>\n");
625 fprintf(outfp
, "\t\t</Folder>\n");
629 fprintf(outfp
, "\t</Folder>\n");
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
;
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");
646 fprintf(outfp
, "\t\t</Folder>\n");
650 fprintf(outfp
, "\t</Folder>\n");