1 /*
2   Gpredict: Real-time satellite tracking and orbit prediction program
3 
4   Copyright (C)  2001-2009  Alexandru Csete, OZ9AEC.
5 
6   Authors: Alexandru Csete <oz9aec@gmail.com>
7            Daniel Estevez <daniel@destevez.net>
8 
9   Comments, questions and bugreports should be submitted via
10   http://sourceforge.net/projects/gpredict/
11   More details can be found at the project home page:
12 
13   http://gpredict.oz9aec.net/
14 
15   This program is free software; you can redistribute it and/or modify
16   it under the terms of the GNU General Public License as published by
17   the Free Software Foundation; either version 2 of the License, or
18   (at your option) any later version.
19 
20   This program is distributed in the hope that it will be useful,
21   but WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23   GNU General Public License for more details.
24 
25   You should have received a copy of the GNU General Public License
26   along with this program; if not, visit http://www.fsf.org/
27 */
28 
29 #include <glib.h>
30 #include <glib/gi18n.h>
31 #include "sgpsdp/sgp4sdp4.h"
32 #include "gtk-sat-data.h"
33 #include "sat-log.h"
34 #ifdef HAVE_CONFIG_H
35 #include <build-config.h>
36 #endif
37 #include "orbit-tools.h"
38 #include "time-tools.h"
39 #include "compat.h"
40 
41 
42 /**
43  * Read TLE data for a given satellite into memory.
44  *
45  * @param catnum The catalog number of the satellite.
46  * @param sat Pointer to a valid sat_t structure.
47  * @return 0 if successfull, 1 if an I/O error occurred,
48  *         2 if the TLE data appears to be bad.
49  *
50  */
gtk_sat_data_read_sat(gint catnum,sat_t * sat)51 gint gtk_sat_data_read_sat(gint catnum, sat_t * sat)
52 {
53     guint           errorcode = 0;
54     GError         *error = NULL;
55     GKeyFile       *data;
56     gchar          *filename = NULL, *path = NULL;
57     gchar          *tlestr1, *tlestr2, *rawtle;
58 
59 
60     /* ensure that sat != NULL */
61     g_return_val_if_fail(sat != NULL, 1);
62 
63     /* .sat file names */
64     filename = g_strdup_printf("%d.sat", catnum);
65     path = sat_file_name_from_catnum(catnum);
66 
67     /* open .sat file */
68     data = g_key_file_new();
69     if (!g_key_file_load_from_file
70         (data, path, G_KEY_FILE_KEEP_COMMENTS, &error))
71     {
72         /* an error occurred */
73         sat_log_log(SAT_LOG_LEVEL_ERROR,
74                     _("%s: Failed to load data from %s (%s)"),
75                     __func__, path, error->message);
76 
77         g_clear_error(&error);
78 
79         errorcode = 1;
80     }
81     else
82     {
83         /* read name, nickname, and website */
84         sat->name = g_key_file_get_string(data, "Satellite", "NAME", &error);
85         if (error != NULL)
86         {
87             sat_log_log(SAT_LOG_LEVEL_ERROR,
88                         _("%s: Error reading NAME from %s (%s)"),
89                         __func__, path, error->message);
90             g_clear_error(&error);
91             sat->name = g_strdup("Error");
92         }
93         sat->nickname =
94             g_key_file_get_string(data, "Satellite", "NICKNAME", &error);
95         if (error != NULL)
96         {
97             sat_log_log(SAT_LOG_LEVEL_INFO,
98                         _("%s: Satellite %d has no NICKNAME"),
99                         __func__, catnum);
100             g_clear_error(&error);
101             sat->nickname = g_strdup(sat->name);
102         }
103 
104         sat->website = g_key_file_get_string(data, "Satellite", "WEBSITE", NULL);       /* website may be NULL */
105 
106         /* get TLE data */
107         tlestr1 = g_key_file_get_string(data, "Satellite", "TLE1", NULL);
108         if (error != NULL)
109         {
110             sat_log_log(SAT_LOG_LEVEL_ERROR,
111                         _("%s: Error reading TLE line 1 from %s (%s)"),
112                         __func__, path, error->message);
113             g_clear_error(&error);
114         }
115         tlestr2 = g_key_file_get_string(data, "Satellite", "TLE2", NULL);
116         if (error != NULL)
117         {
118             sat_log_log(SAT_LOG_LEVEL_ERROR,
119                         _("%s: Error reading TLE line 2 from %s (%s)"),
120                         __func__, path, error->message);
121             g_clear_error(&error);
122         }
123 
124         rawtle = g_strconcat(tlestr1, tlestr2, NULL);
125 
126         if (!Good_Elements(rawtle))
127         {
128             sat_log_log(SAT_LOG_LEVEL_ERROR,
129                         _("%s: TLE data for %d appears to be bad"),
130                         __func__, catnum);
131             errorcode = 2;
132         }
133         else
134         {
135             Convert_Satellite_Data(rawtle, &sat->tle);
136         }
137         if (g_key_file_has_key(data, "Satellite", "STATUS", NULL))
138             sat->tle.status =
139                 g_key_file_get_integer(data, "Satellite", "STATUS", NULL);
140 
141         g_free(tlestr1);
142         g_free(tlestr2);
143         g_free(rawtle);
144 
145         /* VERY, VERY important! If not done, some sats
146            will not get initialised, the first time SGP4/SDP4
147            is called. Consequently, the resulting data will
148            be NAN, INF or similar nonsense.
149            For some reason, not even using g_new0 seems to
150            be enough.
151          */
152         sat->flags = 0;
153 
154         select_ephemeris(sat);
155 
156         /* initialise variable fields */
157         sat->jul_utc = 0.0;
158         sat->tsince = 0.0;
159         sat->az = 0.0;
160         sat->el = 0.0;
161         sat->range = 0.0;
162         sat->range_rate = 0.0;
163         sat->ra = 0.0;
164         sat->dec = 0.0;
165         sat->ssplat = 0.0;
166         sat->ssplon = 0.0;
167         sat->alt = 0.0;
168         sat->velo = 0.0;
169         sat->ma = 0.0;
170         sat->footprint = 0.0;
171         sat->phase = 0.0;
172         sat->aos = 0.0;
173         sat->los = 0.0;
174 
175         /* calculate satellite data at epoch */
176         gtk_sat_data_init_sat(sat, NULL);
177     }
178 
179     g_free(filename);
180     g_free(path);
181     g_key_file_free(data);
182 
183     return errorcode;
184 }
185 
186 /**
187  * Initialise satellite data.
188  *
189  * @param sat The satellite to initialise.
190  * @param qth Optional QTH info, use (0,0) if NULL.
191  *
192  * This function calculates the satellite data at t = 0, ie. epoch time
193  * The function is called automatically by gtk_sat_data_read_sat.
194  */
gtk_sat_data_init_sat(sat_t * sat,qth_t * qth)195 void gtk_sat_data_init_sat(sat_t * sat, qth_t * qth)
196 {
197     geodetic_t      obs_geodetic;
198     obs_set_t       obs_set;
199     geodetic_t      sat_geodetic;
200     double          jul_utc, age;
201 
202     g_return_if_fail(sat != NULL);
203 
204     jul_utc = Julian_Date_of_Epoch(sat->tle.epoch);     // => tsince = 0.0
205     sat->jul_epoch = jul_utc;
206 
207     /* initialise observer location */
208     if (qth != NULL)
209     {
210         obs_geodetic.lon = qth->lon * de2ra;
211         obs_geodetic.lat = qth->lat * de2ra;
212         obs_geodetic.alt = qth->alt / 1000.0;
213         obs_geodetic.theta = 0;
214     }
215     else
216     {
217         obs_geodetic.lon = 0.0;
218         obs_geodetic.lat = 0.0;
219         obs_geodetic.alt = 0.0;
220         obs_geodetic.theta = 0;
221     }
222 
223     /* execute computations */
224     if (sat->flags & DEEP_SPACE_EPHEM_FLAG)
225         SDP4(sat, 0.0);
226     else
227         SGP4(sat, 0.0);
228 
229     /* scale position and velocity to km and km/sec */
230     Convert_Sat_State(&sat->pos, &sat->vel);
231 
232     /* get the velocity of the satellite */
233     Magnitude(&sat->vel);
234     sat->velo = sat->vel.w;
235     Calculate_Obs(jul_utc, &sat->pos, &sat->vel, &obs_geodetic, &obs_set);
236     Calculate_LatLonAlt(jul_utc, &sat->pos, &sat_geodetic);
237 
238     while (sat_geodetic.lon < -pi)
239         sat_geodetic.lon += twopi;
240 
241     while (sat_geodetic.lon > (pi))
242         sat_geodetic.lon -= twopi;
243 
244     sat->az = Degrees(obs_set.az);
245     sat->el = Degrees(obs_set.el);
246     sat->range = obs_set.range;
247     sat->range_rate = obs_set.range_rate;
248     sat->ssplat = Degrees(sat_geodetic.lat);
249     sat->ssplon = Degrees(sat_geodetic.lon);
250     sat->alt = sat_geodetic.alt;
251     sat->ma = Degrees(sat->phase);
252     sat->ma *= 256.0 / 360.0;
253     sat->footprint = 2.0 * xkmper * acos(xkmper / sat->pos.w);
254     age = 0.0;
255     sat->orbit = (long)floor((sat->tle.xno * xmnpda / twopi +
256                               age * sat->tle.bstar * ae) * age -
257                              (sat->tle.xmo + sat->tle.omegao) / twopi) +
258         sat->tle.revnum;
259 
260     /* orbit type */
261     sat->otype = get_orbit_type(sat);
262 }
263 
264 /**
265  * Copy satellite data.
266  *
267  * @param source Pointer to the source satellite to copy data from.
268  * @param dest Pointer to the destination satellite to copy data into.
269  * @param qth Pointer to the observer data (needed to initialize sat)
270  *
271  * This function copies the satellite data from a source sat_t structure into
272  * the destination. The function copies the tle_t data and calls gtk_sat_data_inti_sat()
273  * function for initializing the other fields.
274  *
275  */
gtk_sat_data_copy_sat(const sat_t * source,sat_t * dest,qth_t * qth)276 void gtk_sat_data_copy_sat(const sat_t * source, sat_t * dest, qth_t * qth)
277 {
278     guint           i;
279 
280     g_return_if_fail((source != NULL) && (dest != NULL));
281 
282     dest->tle.epoch = source->tle.epoch;
283     dest->tle.epoch_year = source->tle.epoch_year;
284     dest->tle.epoch_day = source->tle.epoch_day;
285     dest->tle.epoch_fod = source->tle.epoch_fod;
286     dest->tle.xndt2o = source->tle.xndt2o;
287     dest->tle.xndd6o = source->tle.xndd6o;
288     dest->tle.bstar = source->tle.bstar;
289     dest->tle.xincl = source->tle.xincl;
290     dest->tle.xnodeo = source->tle.xnodeo;
291     dest->tle.eo = source->tle.eo;
292     dest->tle.omegao = source->tle.omegao;
293     dest->tle.xmo = source->tle.xmo;
294     dest->tle.xno = source->tle.xno;
295     dest->tle.catnr = source->tle.catnr;
296     dest->tle.elset = source->tle.elset;
297     dest->tle.revnum = source->tle.revnum;
298 
299     dest->name = g_strdup(source->name);
300     dest->nickname = g_strdup(source->nickname);
301     for (i = 0; i < 9; i++)
302         dest->tle.idesg[i] = source->tle.idesg[i];
303 
304     dest->tle.status = source->tle.status;
305     dest->tle.xincl1 = source->tle.xincl1;
306     dest->tle.omegao1 = source->tle.omegao1;
307 
308     dest->otype = source->otype;
309 
310     /* very important */
311     dest->flags = 0;
312     select_ephemeris(dest);
313 
314     /* initialise variable fields */
315     dest->jul_utc = 0.0;
316     dest->tsince = 0.0;
317     dest->az = 0.0;
318     dest->el = 0.0;
319     dest->range = 0.0;
320     dest->range_rate = 0.0;
321     dest->ra = 0.0;
322     dest->dec = 0.0;
323     dest->ssplat = 0.0;
324     dest->ssplon = 0.0;
325     dest->alt = 0.0;
326     dest->velo = 0.0;
327     dest->ma = 0.0;
328     dest->footprint = 0.0;
329     dest->phase = 0.0;
330     dest->aos = 0.0;
331     dest->los = 0.0;
332 
333     gtk_sat_data_init_sat(dest, qth);
334 }
335 
336 /**
337  * Free satellite data
338  *
339  * @param sat Pointer to the satellite data to free
340  *
341  * This function frees the memory that has been dyunamically allocated
342  * when creating a new satellite object.
343  */
gtk_sat_data_free_sat(sat_t * sat)344 void gtk_sat_data_free_sat(sat_t * sat)
345 {
346     if (!sat)
347         return;
348 
349     if (sat->name)
350     {
351         g_free(sat->name);
352         sat->name = NULL;
353     }
354     if (sat->nickname)
355     {
356         g_free(sat->nickname);
357         sat->nickname = NULL;
358     }
359     if (sat->website)
360     {
361         g_free(sat->website);
362         sat->website = NULL;
363     }
364 
365     g_free(sat);
366 }
367