1 /*
2 Gpredict: Real-time satellite tracking and orbit prediction program
3
4 Copyright (C) 2001-2017 Alexandru Csete, OZ9AEC.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, visit http://www.fsf.org/
18 */
19 #ifdef HAVE_CONFIG_H
20 #include <build-config.h>
21 #endif
22 #include <glib/gi18n.h>
23 #include <gtk/gtk.h>
24
25 #include "config-keys.h"
26 #include "orbit-tools.h"
27 #include "predict-tools.h"
28 #include "sat-cfg.h"
29 #include "sat-info.h"
30 #include "sat-log.h"
31 #include "sat-pass-dialogs.h"
32 #include "sgpsdp/sgp4sdp4.h"
33 #include "trsp-conf.h"
34
35
36 /**
37 * Show satellite info in a dialog (callback)
38 *
39 * @param menuitem The menuitem from where the function is invoked.
40 * @param data Pointer to parent window or NULL.
41 */
show_sat_info_menu_cb(GtkWidget * menuitem,gpointer data)42 void show_sat_info_menu_cb(GtkWidget * menuitem, gpointer data)
43 {
44 sat_t *sat;
45
46 sat = SAT(g_object_get_data(G_OBJECT(menuitem), "sat"));
47 show_sat_info(sat, data);
48 }
49
50
51 /* Create transponder table. */
create_transponder_table(guint catnum)52 static GtkWidget *create_transponder_table(guint catnum)
53 {
54 GtkWidget *vbox, *label, *swin;
55 GSList *trsplist = NULL;
56 trsp_t *trsp = NULL;
57 guint i, n;
58 gchar *text;
59
60
61 trsplist = read_transponders(catnum);
62 if (trsplist == NULL)
63 {
64 swin = gtk_label_new(_("No transponders"));
65 }
66 else
67 {
68 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3);
69 gtk_box_set_homogeneous(GTK_BOX(vbox), FALSE);
70 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
71
72 /* Add each transponder to vbox */
73 n = g_slist_length(trsplist);
74 for (i = 0; i < n; i++)
75 {
76 gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(" "), FALSE, FALSE,
77 0);
78
79 trsp = (trsp_t *) g_slist_nth_data(trsplist, i);
80
81 /* transponder name */
82 text = g_strdup_printf("<b>%s</b>", trsp->name);
83 label = gtk_label_new(NULL);
84 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
85 gtk_label_set_markup(GTK_LABEL(label), text);
86 g_free(text);
87 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
88 gtk_box_pack_start(GTK_BOX(vbox),
89 gtk_separator_new(GTK_ORIENTATION_HORIZONTAL),
90 FALSE, FALSE, 0);
91
92 /* uplink */
93 if (trsp->uplow > 0.0)
94 {
95 if (trsp->uphigh > trsp->uplow)
96 {
97 /* we have a range */
98 text =
99 g_strdup_printf(_
100 ("Uplink: %.4f \342\200\222 %.4f MHz"),
101 trsp->uplow / 1.0e6,
102 trsp->uphigh / 1.0e6);
103 }
104 else
105 {
106 text =
107 g_strdup_printf(_("Uplink: %.4f MHz"),
108 trsp->uplow / 1.0e6);
109 }
110 label = gtk_label_new(text);
111 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
112 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
113 g_free(text);
114 }
115
116 /* downlink */
117 if (trsp->downlow > 0.0)
118 {
119 if (trsp->downhigh > trsp->downlow)
120 {
121 /* we have a range */
122 text =
123 g_strdup_printf(_
124 ("Downlink: %.4f \342\200\222 %.4f MHz"),
125 trsp->downlow / 1.0e6,
126 trsp->downhigh / 1.0e6);
127 }
128 else
129 {
130 text =
131 g_strdup_printf(_("Downlink: %.4f MHz"),
132 trsp->downlow / 1.0e6);
133 }
134 label = gtk_label_new(text);
135 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
136 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
137 g_free(text);
138 }
139
140 /* inverting */
141 if ((trsp->downhigh > trsp->downlow) &&
142 (trsp->uphigh > trsp->uplow))
143 {
144 text =
145 g_strdup_printf(_("Inverting: %s"),
146 trsp->invert ? "YES" : "NO");
147 label = gtk_label_new(text);
148 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
149 g_free(text);
150 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
151 }
152
153 /* mode string */
154 if (trsp->mode)
155 {
156 text = g_strdup_printf(_("Mode: %s"), trsp->mode);
157 label = gtk_label_new(text);
158 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
159 g_free(text);
160 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
161 }
162 if (trsp->baud)
163 {
164 text = g_strdup_printf(_("Baudrate: %9.2f"), trsp->baud);
165 label = gtk_label_new(text);
166 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
167 g_free(text);
168 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
169 }
170 }
171 free_transponders(trsplist);
172
173 /* pack into a scrolled window */
174 swin = gtk_scrolled_window_new(NULL, NULL);
175 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
176 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
177 gtk_container_add (GTK_CONTAINER (swin), vbox);
178 }
179
180 return swin;
181 }
182
183 /* BBBBB.BBBBBBBB] - Epoch Time -- 2-digit year, followed by 3-digit sequential
184 day of the year, followed by the time represented as the
185 fractional portion of one day, but...
186
187 we now have the converted fields, tle->epoch_year, tle->epoch_day and tle->epoch_fod
188
189 */
epoch_to_str(sat_t * sat)190 static gchar *epoch_to_str(sat_t * sat)
191 {
192 GDate *epd;
193 guint h, m, s, sec;
194 gchar *buff;
195 gchar *fmt;
196 struct tm tms;
197 time_t t;
198 guint size;
199
200 /* http://celestrak.com/columns/v04n03/#FAQ02
201 ... While talking about the epoch, this is perhaps a good place to answer
202 the other time-related questions. First, how is the epoch time format
203 interpreted? This question is best answered by using an example. An epoch
204 of 98001.00000000 corresponds to 0000 UT on 1998 January 01st in other
205 words, midnight between 1997 December 31 and 1998 January 01. An epoch of
206 98000.00000000 would actually correspond to the beginning of 1997 December
207 31st strange as that might seem. Note that the epoch day starts at UT
208 midnight (not noon) and that all times are measured mean solar rather than
209 sidereal time units (the answer to our third question).
210 */
211 epd = g_date_new_dmy(1, 1, sat->tle.epoch_year);
212 g_date_add_days(epd, sat->tle.epoch_day - 1);
213
214 /* convert date to struct tm */
215 g_date_to_struct_tm(epd, &tms);
216
217 /* add HMS */
218 sec = (guint) floor(sat->tle.epoch_fod * 86400); /* fraction of day in seconds */
219
220 /* hour */
221 h = (guint) floor(sec / 3600);
222 tms.tm_hour = h;
223
224 /* minutes */
225 m = (guint) floor((sec - (h * 3600)) / 60);
226 tms.tm_min = m;
227
228 s = (guint) floor(sec - (h * 3600) - (m * 60));
229 tms.tm_sec = s;
230
231 /* get format string */
232 fmt = sat_cfg_get_str(SAT_CFG_STR_TIME_FORMAT);
233
234 /* format either local time or UTC depending on check box */
235 t = mktime(&tms);
236 buff = g_try_malloc(51);
237
238 if (sat_cfg_get_bool(SAT_CFG_BOOL_USE_LOCAL_TIME))
239 size = strftime(buff, 50, fmt, localtime(&t));
240 else
241 size = strftime(buff, 50, fmt, gmtime(&t));
242
243 if (size < 50)
244 buff[size] = '\0';
245 else
246 buff[50] = '\0';
247
248 g_date_free(epd);
249 g_free(fmt);
250
251 return buff;
252 }
253
254 /**
255 * Show satellite info in a dialog
256 *
257 * @param sat Pointer to the sat info.
258 * @param data Pointer to parent window or NULL.
259 *
260 * FIXME: see nice drawing at http://www.amsat.org/amsat-new/tools/keps_tutorial.php
261 */
show_sat_info(sat_t * sat,gpointer data)262 void show_sat_info(sat_t * sat, gpointer data)
263 {
264 GtkWidget *dialog;
265 GtkWidget *notebook;
266 GtkWidget *table;
267 GtkWidget *label;
268 GtkWindow *toplevel = NULL;
269 gchar *str;
270
271
272 if (data != NULL)
273 toplevel = GTK_WINDOW(data);
274
275 /* create table */
276 table = gtk_grid_new();
277 gtk_grid_set_column_spacing(GTK_GRID(table), 5);
278 gtk_grid_set_row_spacing(GTK_GRID(table), 5);
279 gtk_container_set_border_width(GTK_CONTAINER(table), 10);
280
281 /* satellite name */
282 label = gtk_label_new(NULL);
283 gtk_label_set_markup(GTK_LABEL(label), _("<b>Satellite name:</b>"));
284 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
285 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
286
287 label = gtk_label_new(NULL);
288 str = g_markup_printf_escaped(_("<b>%s</b>"), sat->nickname);
289 gtk_label_set_markup(GTK_LABEL(label), str);
290 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
291 gtk_grid_attach(GTK_GRID(table), label, 1, 0, 1, 1);
292 g_free(str);
293
294 /* operational status */
295 label = gtk_label_new(_("Operational Status:"));
296 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
297 gtk_grid_attach(GTK_GRID(table), label, 0, 1, 1, 1);
298
299 switch (sat->tle.status)
300 {
301
302 case OP_STAT_OPERATIONAL:
303 label = gtk_label_new(_("Operational"));
304 break;
305
306 case OP_STAT_NONOP:
307 label = gtk_label_new(_("Non-operational"));
308 break;
309
310 case OP_STAT_PARTIAL:
311 label = gtk_label_new(_("Partially operational"));
312 break;
313
314 case OP_STAT_STDBY:
315 label = gtk_label_new(_("Backup/Standby"));
316 break;
317
318 case OP_STAT_SPARE:
319 label = gtk_label_new(_("Spare"));
320 break;
321
322 case OP_STAT_EXTENDED:
323 label = gtk_label_new(_("Extended Mission"));
324 break;
325
326 default:
327 label = gtk_label_new(_("Unknown"));
328 break;
329
330 }
331
332 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
333 gtk_grid_attach(GTK_GRID(table), label, 1, 1, 1, 1);
334
335 /* Catnum */
336 label = gtk_label_new(_("Catalogue number:"));
337 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
338 gtk_grid_attach(GTK_GRID(table), label, 0, 2, 1, 1);
339
340 str = g_strdup_printf("%d", sat->tle.catnr);
341 label = gtk_label_new(str);
342 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
343 gtk_grid_attach(GTK_GRID(table), label, 1, 2, 1, 1);
344 g_free(str);
345
346 /* international designator */
347 label = gtk_label_new(_("International designator:"));
348 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
349 gtk_grid_attach(GTK_GRID(table), label, 0, 3, 1, 1);
350
351 label = gtk_label_new(sat->tle.idesg);
352 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
353 gtk_grid_attach(GTK_GRID(table), label, 1, 3, 1, 1);
354
355 /* elset number */
356 label = gtk_label_new(_("Element set number:"));
357 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
358 gtk_grid_attach(GTK_GRID(table), label, 0, 4, 1, 1);
359
360 str = g_strdup_printf("%d", sat->tle.elset);
361 label = gtk_label_new(str);
362 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
363 gtk_grid_attach(GTK_GRID(table), label, 1, 4, 1, 1);
364 g_free(str);
365
366 /* elset epoch */
367 label = gtk_label_new(_("Epoch time:"));
368 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
369 gtk_grid_attach(GTK_GRID(table), label, 0, 5, 1, 1);
370
371 str = epoch_to_str(sat);
372 label = gtk_label_new(str);
373 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
374 gtk_grid_attach(GTK_GRID(table), label, 1, 5, 1, 1);
375 g_free(str);
376
377 /* Revolution Number @ Epoch */
378 label = gtk_label_new(_("Orbit number @ epoch:"));
379 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
380 gtk_grid_attach(GTK_GRID(table), label, 0, 6, 1, 1);
381
382 str = g_strdup_printf("%d", sat->tle.revnum);
383 label = gtk_label_new(str);
384 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
385 gtk_grid_attach(GTK_GRID(table), label, 1, 6, 1, 1);
386 g_free(str);
387
388 /* ephermis type left out, since it is always 0 */
389
390 /* separator */
391 gtk_grid_attach(GTK_GRID(table),
392 gtk_separator_new(GTK_ORIENTATION_HORIZONTAL),
393 0, 7, 2, 1);
394
395 /* Orbit inclination */
396 label = gtk_label_new(_("Inclination:"));
397 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
398 gtk_grid_attach(GTK_GRID(table), label, 0, 8, 1, 1);
399
400 str = g_strdup_printf("%.4f\302\260", sat->tle.xincl / de2ra);
401 label = gtk_label_new(str);
402 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
403 gtk_grid_attach(GTK_GRID(table), label, 1, 8, 1, 1);
404 g_free(str);
405
406 /* RAAN */
407 label = gtk_label_new(_("RAAN:"));
408 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
409 gtk_grid_attach(GTK_GRID(table), label, 0, 9, 1, 1);
410
411 str = g_strdup_printf("%.4f\302\260", sat->tle.xnodeo / de2ra);
412 label = gtk_label_new(str);
413 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
414 gtk_grid_attach(GTK_GRID(table), label, 1, 9, 1, 1);
415 g_free(str);
416
417 /* Eccentricity */
418 label = gtk_label_new(_("Eccentricity:"));
419 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
420 gtk_grid_attach(GTK_GRID(table), label, 0, 10, 1, 1);
421
422 str = g_strdup_printf("%.7f", sat->tle.eo);
423 label = gtk_label_new(str);
424 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
425 gtk_grid_attach(GTK_GRID(table), label, 1, 10, 1, 1);
426 g_free(str);
427
428 /* Argument of perigee */
429 label = gtk_label_new(_("Arg. of perigee:"));
430 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
431 gtk_grid_attach(GTK_GRID(table), label, 0, 11, 1, 1);
432
433 str = g_strdup_printf("%.4f\302\260", sat->tle.omegao / de2ra);
434 label = gtk_label_new(str);
435 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
436 gtk_grid_attach(GTK_GRID(table), label, 1, 11, 1, 1);
437 g_free(str);
438
439 /* Mean Anomaly */
440 label = gtk_label_new(_("Mean anomaly:"));
441 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
442 gtk_grid_attach(GTK_GRID(table), label, 0, 12, 1, 1);
443
444 str = g_strdup_printf("%.4f\302\260", sat->tle.xmo / de2ra);
445 label = gtk_label_new(str);
446 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
447 gtk_grid_attach(GTK_GRID(table), label, 1, 12, 1, 1);
448 g_free(str);
449
450 /* Mean Motion */
451 label = gtk_label_new(_("Mean motion:"));
452 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
453 gtk_grid_attach(GTK_GRID(table), label, 0, 13, 1, 1);
454
455 str = g_strdup_printf("%.8f [rev/day]", sat->meanmo);
456 label = gtk_label_new(str);
457 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
458 gtk_grid_attach(GTK_GRID(table), label, 1, 13, 1, 1);
459 g_free(str);
460
461 /* one half of the first time derivative of mean motion */
462 label = gtk_label_new(_("\302\275 d/dt (mean motion):"));
463 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
464 gtk_grid_attach(GTK_GRID(table), label, 0, 14, 1, 1);
465
466 str = g_strdup_printf("%.5e [rev/day<sup>2</sup>]",
467 sat->tle.xndt2o / (twopi / xmnpda / xmnpda));
468 label = gtk_label_new(NULL);
469 gtk_label_set_markup(GTK_LABEL(label), str);
470 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
471 gtk_grid_attach(GTK_GRID(table), label, 1, 14, 1, 1);
472 g_free(str);
473
474 /* one sixth of the second time derivative of mean motion */
475 label = gtk_label_new(NULL);
476 gtk_label_set_markup(GTK_LABEL(label),
477 _("1/6 d<sup>2</sup>/dt<sup>2</sup> (mean motion):"));
478 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
479 gtk_grid_attach(GTK_GRID(table), label, 0, 15, 1, 1);
480
481 str = g_strdup_printf("%.5e [rev/day<sup>3</sup>]",
482 sat->tle.xndd6o * xmnpda / (twopi / xmnpda / xmnpda));
483 label = gtk_label_new(NULL);
484 gtk_label_set_markup(GTK_LABEL(label), str);
485 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
486 gtk_grid_attach(GTK_GRID(table), label, 1, 15, 1, 1);
487 g_free(str);
488
489 /* B* drag term */
490 label = gtk_label_new(_("B* drag term:"));
491 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
492 gtk_grid_attach(GTK_GRID(table), label, 0, 16, 1, 1);
493
494 str = g_strdup_printf("%.5e [R<sub>E</sub><sup>-1</sup>]",
495 sat->tle.bstar * ae);
496 label = gtk_label_new(NULL);
497 gtk_label_set_markup(GTK_LABEL(label), str);
498 g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
499 gtk_grid_attach(GTK_GRID(table), label, 1, 16, 1, 1);
500 g_free(str);
501
502 /* Orbit type */
503
504 /* Next Event */
505
506 gtk_widget_show_all(table);
507
508 notebook = gtk_notebook_new();
509 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), table,
510 gtk_label_new(_("Orbit Info")));
511 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
512 create_transponder_table(sat->tle.catnr),
513 gtk_label_new(_("Transponders")));
514
515 /* create dialog window with NULL parent */
516 dialog = gtk_dialog_new_with_buttons(_("Satellite Info"),
517 toplevel,
518 GTK_DIALOG_DESTROY_WITH_PARENT,
519 "_OK",
520 GTK_RESPONSE_ACCEPT, NULL);
521
522 /* allow interaction with other windows */
523 gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
524
525 g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
526
527 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
528 gtk_box_pack_start(GTK_BOX(content_area), notebook, TRUE, TRUE, 0);
529
530 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
531
532 gtk_widget_show_all(dialog);
533 }
534