1 /*
2 Gpredict: Real-time satellite tracking and orbit prediction program
3
4 Copyright (C) 2001-2013 Alexandru Csete, OZ9AEC.
5 Parts are Copyright John A. Magliacane, KD2BD 1991-2003 (indicated below)
6
7 Authors: Alexandru Csete <oz9aec@gmail.com>
8 John A. Magliacane, KD2BD.
9 Charles Suprin <hamaa1vs@gmail.com>
10 Daniel Estevez <daniel@destevez.net>
11
12 Comments, questions and bugreports should be submitted via
13 http://sourceforge.net/projects/gpredict/
14 More details can be found at the project home page:
15
16 http://gpredict.oz9aec.net/
17
18 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
22
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, visit http://www.fsf.org/
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include <build-config.h>
34 #endif
35
36 #include <glib.h>
37 #include <glib/gi18n.h>
38
39 #include "gtk-sat-data.h"
40 #include "orbit-tools.h"
41 #include "predict-tools.h"
42 #include "sat-cfg.h"
43 #include "sat-log.h"
44 #include "sgpsdp/sgp4sdp4.h"
45 #include "time-tools.h"
46
47 static pass_t *get_pass_engine(sat_t * sat_in, qth_t * qth, gdouble start,
48 gdouble maxdt, gdouble min_el);
49
50 /**
51 * \brief SGP4SDP4 driver for doing AOS/LOS calculations.
52 * \param sat Pointer to the satellite data.
53 * \param qth Pointer to the QTH data.
54 * \param t The time for calculation (Julian Date)
55 */
predict_calc(sat_t * sat,qth_t * qth,gdouble t)56 void predict_calc(sat_t * sat, qth_t * qth, gdouble t)
57 {
58 obs_set_t obs_set;
59 geodetic_t sat_geodetic;
60 geodetic_t obs_geodetic;
61 double age;
62
63 obs_geodetic.lon = qth->lon * de2ra;
64 obs_geodetic.lat = qth->lat * de2ra;
65 obs_geodetic.alt = qth->alt / 1000.0;
66 obs_geodetic.theta = 0;
67
68 sat->jul_utc = t;
69 sat->tsince = (sat->jul_utc - sat->jul_epoch) * xmnpda;
70
71 /* call the norad routines according to the deep-space flag */
72 if (sat->flags & DEEP_SPACE_EPHEM_FLAG)
73 SDP4(sat, sat->tsince);
74 else
75 SGP4(sat, sat->tsince);
76
77 Convert_Sat_State(&sat->pos, &sat->vel);
78
79 /* get the velocity of the satellite */
80 Magnitude(&sat->vel);
81 sat->velo = sat->vel.w;
82 Calculate_Obs(sat->jul_utc, &sat->pos, &sat->vel, &obs_geodetic, &obs_set);
83 Calculate_LatLonAlt(sat->jul_utc, &sat->pos, &sat_geodetic);
84
85 while (sat_geodetic.lon < -pi)
86 sat_geodetic.lon += twopi;
87
88 while (sat_geodetic.lon > (pi))
89 sat_geodetic.lon -= twopi;
90
91 sat->az = Degrees(obs_set.az);
92 sat->el = Degrees(obs_set.el);
93 sat->range = obs_set.range;
94 sat->range_rate = obs_set.range_rate;
95 sat->ssplat = Degrees(sat_geodetic.lat);
96 sat->ssplon = Degrees(sat_geodetic.lon);
97 sat->alt = sat_geodetic.alt;
98 sat->ma = Degrees(sat->phase);
99 sat->ma *= 256.0 / 360.0;
100 sat->phase = Degrees(sat->phase);
101
102 /* same formulas, but the one from predict is nicer */
103 //sat->footprint = 2.0 * xkmper * acos (xkmper/sat->pos.w);
104 sat->footprint = 12756.33 * acos(xkmper / (xkmper + sat->alt));
105 age = sat->jul_utc - sat->jul_epoch;
106 sat->orbit = (long)floor((sat->tle.xno * xmnpda / twopi +
107 age * sat->tle.bstar * ae) * age +
108 (sat->tle.xmo + sat->tle.omegao) / twopi) + sat->tle.revnum ;
109 }
110
111 /**
112 * \brief Find the AOS time of the next pass.
113 * \author Alexandru Csete, OZ9AEC
114 * \author John A. Magliacane, KD2BD
115 * \param sat Pointer to the satellite data.
116 * \param qth Pointer to the QTH data.
117 * \param start The time where calculation should start.
118 * \param maxdt The upper time limit in days (0.0 = no limit)
119 * \return The time of the next AOS or 0.0 if the satellite has no AOS.
120 *
121 * This function finds the time of AOS for the first coming pass taking place
122 * no earlier that start.
123 * If the satellite is currently within range, the function first calls
124 * find_los to get the next LOS time. Then the calculations are done using
125 * the new start time.
126 */
find_aos(sat_t * sat,qth_t * qth,gdouble start,gdouble maxdt)127 gdouble find_aos(sat_t * sat, qth_t * qth, gdouble start, gdouble maxdt)
128 {
129 gdouble t = start;
130 gdouble aostime = 0.0;
131
132 /* make sure current sat values are in sync with the time */
133 predict_calc(sat, qth, start);
134
135 /* check whether satellite has aos */
136 if (!has_aos(sat, qth))
137 return 0.0;
138
139 if (sat->el > 0.0)
140 t = find_los(sat, qth, start, maxdt) + 0.014; // +20 min
141
142 /* invalid time (potentially returned by find_los) */
143 if (t < 0.1)
144 return 0.0;
145
146 /* update satellite data */
147 predict_calc(sat, qth, t);
148
149 /* use upper time limit */
150 if (maxdt > 0.0)
151 {
152
153 /* coarse time steps */
154 while ((sat->el < -1.0) && (t <= (start + maxdt)))
155 {
156 t -= 0.00035 * (sat->el * ((sat->alt / 8400.0) + 0.46) - 2.0);
157 predict_calc(sat, qth, t);
158 }
159
160 /* fine steps */
161 while ((aostime == 0.0) && (t <= (start + maxdt)))
162 {
163
164 if (fabs(sat->el) < 0.005)
165 {
166 aostime = t;
167 }
168 else
169 {
170 t -= sat->el * sqrt(sat->alt) / 530000.0;
171 predict_calc(sat, qth, t);
172 }
173
174 }
175
176 }
177 /* don't use upper time limit */
178 else
179 {
180 /* coarse time steps */
181 while (sat->el < -1.0)
182 {
183 t -= 0.00035 * (sat->el * ((sat->alt / 8400.0) + 0.46) - 2.0);
184 predict_calc(sat, qth, t);
185 }
186
187 /* fine steps */
188 while (aostime == 0.0)
189 {
190
191 if (fabs(sat->el) < 0.005)
192 {
193 aostime = t;
194 }
195 else
196 {
197 t -= sat->el * sqrt(sat->alt) / 530000.0;
198 predict_calc(sat, qth, t);
199 }
200 }
201 }
202
203 return aostime;
204 }
205
206 /**
207 * \brief Find the LOS time of the next pass.
208 * \author Alexandru Csete, OZ9AEC
209 * \author John A. Magliacane, KD2BD
210 * \param sat Pointer to the satellite data.
211 * \param qth Pointer to the QTH data.
212 * \param start The time where calculation should start.
213 * \param maxdt The upper time limit in days (0.0 = no limit)
214 * \return The time of the next LOS or 0.0 if the satellite has no LOS.
215 *
216 * This function finds the time of LOS for the first coming pass taking place
217 * no earlier that start.
218 * If the satellite is currently out of range, the function first calls
219 * find_aos to get the next AOS time. Then the calculations are done using
220 * the new start time.
221 * The function has a built-in watchdog to ensure that we don't end up in
222 * lengthy loops.
223 */
find_los(sat_t * sat,qth_t * qth,gdouble start,gdouble maxdt)224 gdouble find_los(sat_t * sat, qth_t * qth, gdouble start, gdouble maxdt)
225 {
226 gdouble t = start;
227 gdouble lostime = 0.0;
228 gdouble eltemp;
229
230 predict_calc(sat, qth, start);
231
232 /* check whether satellite has aos */
233 if (!has_aos(sat, qth))
234 {
235 return 0.0;
236 }
237
238 if (sat->el < 0.0)
239 t = find_aos(sat, qth, start, maxdt) + 0.001; // +1.5 min
240
241 /* invalid time (potentially returned by find_aos) */
242 if (t < 0.01)
243 return 0.0;
244
245 /* update satellite data */
246 predict_calc(sat, qth, t);
247
248 /* use upper time limit */
249 if (maxdt > 0.0)
250 {
251 /* coarse steps */
252 while ((sat->el >= 1.0) && (t <= (start + maxdt)))
253 {
254 t += cos((sat->el - 1.0) * de2ra) * sqrt(sat->alt) / 25000.0;
255 predict_calc(sat, qth, t);
256 }
257
258 /* fine steps */
259 while ((lostime == 0.0) && (t <= (start + maxdt)))
260 {
261 t += sat->el * sqrt(sat->alt) / 502500.0;
262 predict_calc(sat, qth, t);
263
264 if (fabs(sat->el) < 0.005)
265 {
266 /* Two things are true at LOS time, the elevation is a zero and
267 sat is descending. This checks that those two are true. */
268 eltemp = sat->el;
269
270 /* check elevation 1 second earlier */
271 predict_calc(sat, qth, t - 1.0 / 86400.0);
272
273 if (sat->el > eltemp)
274 lostime = t;
275 }
276 }
277 }
278 /* don't use upper limit */
279 else
280 {
281 /* coarse steps */
282 while (sat->el >= 1.0)
283 {
284 t += cos((sat->el - 1.0) * de2ra) * sqrt(sat->alt) / 25000.0;
285 predict_calc(sat, qth, t);
286 }
287
288 /* fine steps */
289 while (lostime == 0.0)
290 {
291 t += sat->el * sqrt(sat->alt) / 502500.0;
292 predict_calc(sat, qth, t);
293
294 if (fabs(sat->el) < 0.005)
295 {
296 /* two things are true at LOS time
297 The elevation is a zero and descending.
298 This checks that those two are true.
299 */
300 eltemp = sat->el;
301
302 /*check elevation 1 second earlier */
303 predict_calc(sat, qth, t - 1.0 / 86400.0);
304
305 if (sat->el > eltemp)
306 lostime = t;
307 }
308 }
309 }
310
311 return lostime;
312 }
313
314 /**
315 * \brief Find AOS time of current pass.
316 * \param sat The satellite to find AOS for.
317 * \param qth The ground station.
318 * \param start Start time, prefereably now.
319 * \return The time of the previous AOS or 0.0 if the satellite has no AOS.
320 *
321 * This function can be used to find the AOS time in the past of the
322 * current pass.
323 */
find_prev_aos(sat_t * sat,qth_t * qth,gdouble start)324 gdouble find_prev_aos(sat_t * sat, qth_t * qth, gdouble start)
325 {
326 gdouble aostime = start;
327
328 /* make sure current sat values are in sync with the time */
329 predict_calc(sat, qth, start);
330
331 /* check whether satellite has aos */
332 if (!has_aos(sat, qth))
333 {
334 return 0.0;
335 }
336
337 while (sat->el >= 0.0)
338 {
339 aostime -= 0.0005; // 0.75 min
340 predict_calc(sat, qth, aostime);
341 }
342
343 return aostime;
344 }
345
346 /**
347 * \brief Predict the next pass.
348 * \param sat Pointer to the satellite data.
349 * \param qth Pointer to the observer data.
350 * \param maxdt The maximum number of days to look ahead.
351 * \return Pointer newly allocated pass_t structure that should be freed
352 * with free_pass when no longer needed, or NULL if no pass can be
353 * found.
354 *
355 * This function simply wraps the get_pass function using the current time
356 * as parameter.
357 *
358 * \note the data in sat will be corrupt (future) and must be refreshed
359 * by the caller, if the caller will need it later on (eg. if the caller
360 * is GtkSatList).
361 */
get_next_pass(sat_t * sat,qth_t * qth,gdouble maxdt)362 pass_t *get_next_pass(sat_t * sat, qth_t * qth, gdouble maxdt)
363 {
364 gdouble now;
365
366 /* get the current time and call the get_pass function */
367 now = get_current_daynum();
368
369 return get_pass(sat, qth, now, maxdt);
370 }
371
372 /**
373 * \brief Predict upcoming passes starting now
374 * \param sat Pointer to the satellite data.
375 * \param qth Pointer to the observer data.
376 * \param maxdt The maximum number of days to look ahead.
377 * \param num The number of passes to predict.
378 * \return A singly linked list of pass_t structures or NULL if
379 * there was an error.
380 *
381 * This function simply wraps the get_passes function using the
382 * current time as parameter.
383 *
384 * \note the data in sat will be corrupt (future) and must be refreshed
385 * by the caller, if the caller will need it later on (eg. if the caller
386 * is GtkSatList).
387 */
get_next_passes(sat_t * sat,qth_t * qth,gdouble maxdt,guint num)388 GSList *get_next_passes(sat_t * sat, qth_t * qth, gdouble maxdt,
389 guint num)
390 {
391 gdouble now;
392
393 /* get the current time and call the get_pass function */
394 now = get_current_daynum();
395
396 return get_passes(sat, qth, now, maxdt, num);
397 }
398
399 /**
400 * \brief Predict first pass after a certain time.
401 * \param sat Pointer to the satellite data.
402 * \param qth Pointer to the location data.
403 * \param start Starting time.
404 * \param maxdt The maximum number of days to look ahead (0 for no limit).
405 * \return Pointer to a newly allocated pass_t structure or NULL if
406 * there was an error.
407 *
408 * This function assumes that you want a pass that achieves the
409 * minimum elevation of is configured for.
410 */
get_pass(sat_t * sat_in,qth_t * qth,gdouble start,gdouble maxdt)411 pass_t *get_pass(sat_t * sat_in, qth_t * qth, gdouble start, gdouble maxdt)
412 {
413 int min_ele = sat_cfg_get_int(SAT_CFG_INT_PRED_MIN_EL);
414
415 if (min_ele == 0)
416 min_ele = 1;
417
418 return get_pass_engine(sat_in, qth, start, maxdt, min_ele);
419 }
420
421 /**
422 * \brief Predict first pass after a certain time ignoring the min elevation.
423 * \param sat Pointer to the satellite data.
424 * \param qth Pointer to the location data.
425 * \param start Starting time.
426 * \param maxdt The maximum number of days to look ahead (0 for no limit).
427 * \return Pointer to a newly allocated pass_t structure or NULL if
428 * there was an error.
429 * This function assumes that you want a pass that achieves the
430 * minimum elevation of is configured for.
431 */
get_pass_no_min_el(sat_t * sat_in,qth_t * qth,gdouble start,gdouble maxdt)432 pass_t *get_pass_no_min_el(sat_t * sat_in, qth_t * qth, gdouble start,
433 gdouble maxdt)
434 {
435 return get_pass_engine(sat_in, qth, start, maxdt, 0.0);
436 }
437
438 /**
439 * \brief Predict first pass after a certain time.
440 * \param sat Pointer to the satellite data.
441 * \param qth Pointer to the location data.
442 * \param start Starting time.
443 * \param maxdt The maximum number of days to look ahead (0 for no limit).
444 * \return Pointer to a newly allocated pass_t structure or NULL if
445 * there was an error.
446 *
447 * This function will find the first upcoming pass with AOS no earlier than
448 * t = start and no later than t = (start+maxdt).
449 *
450 * \note For no time limit use maxdt = 0.0
451 *
452 * \note the data in sat will be corrupt (future) and must be refreshed
453 * by the caller, if the caller will need it later on (eg. if the caller
454 * is GtkSatList).
455 *
456 * \note Prepending to a singly linked list is much faster than appending.
457 * Therefore, the elements are prepended whereafter the GSList is
458 * reversed
459 */
get_pass_engine(sat_t * sat_in,qth_t * qth,gdouble start,gdouble maxdt,gdouble min_el)460 static pass_t *get_pass_engine(sat_t * sat_in, qth_t * qth, gdouble start,
461 gdouble maxdt, gdouble min_el)
462 {
463 gdouble aos = 0.0; /* time of AOS */
464 gdouble tca = 0.0; /* time of TCA */
465 gdouble los = 0.0; /* time of LOS */
466 gdouble dt = 0.0; /* time diff */
467 gdouble step = 0.0; /* time step */
468 gdouble t0 = start;
469 gdouble t; /* current time counter */
470 gdouble tres = 0.0; /* required time resolution */
471 gdouble max_el = 0.0; /* maximum elevation */
472 pass_t *pass = NULL;
473 pass_detail_t *detail = NULL;
474 gboolean done = FALSE;
475 guint iter = 0; /* number of iterations */
476 sat_t *sat, sat_working;
477
478 /* FIXME: watchdog */
479
480 /*copy sat_in to a working structure */
481 sat = memcpy(&sat_working, sat_in, sizeof(sat_t));
482
483 /* get time resolution; sat-cfg stores it in seconds */
484 tres = sat_cfg_get_int(SAT_CFG_INT_PRED_RESOLUTION) / 86400.0;
485
486 /* loop until we find a pass with elevation > SAT_CFG_INT_PRED_MIN_EL
487 or we run out of time
488 FIXME: we should have a safety break
489 */
490 while (!done)
491 {
492 /* Find los of next pass or of current pass */
493 los = find_los(sat, qth, t0, maxdt); // See if a pass is ongoing
494 aos = find_aos(sat, qth, t0, start + maxdt - t0);
495
496 if (aos > los)
497 // los is from an currently happening pass, find previous aos
498 aos = find_prev_aos(sat, qth, t0);
499
500 /* aos = 0.0 means no aos */
501 if (aos == 0.0)
502 done = TRUE;
503
504 /* check whether we are within time limits;
505 maxdt = 0 mean no time limit.
506 */
507 else if ((maxdt > 0.0) && (aos > (start + maxdt)))
508 {
509 done = TRUE;
510 }
511 else
512 {
513 //los = find_los (sat, qth, aos + 0.001, maxdt); // +1.5 min later
514 dt = los - aos;
515
516 /* get time step, which will give us the max number of entries */
517 step = dt / sat_cfg_get_int(SAT_CFG_INT_PRED_NUM_ENTRIES);
518
519 /* but if this is smaller than the required resolution
520 we go with the resolution
521 */
522 if (step < tres)
523 step = tres;
524
525 /* create a pass_t entry; FIXME: g_try_new in 2.8 */
526 pass = g_new(pass_t, 1);
527
528 pass->aos = aos;
529 pass->los = los;
530 pass->max_el = 0.0;
531 pass->aos_az = 0.0;
532 pass->los_az = 0.0;
533 pass->maxel_az = 0.0;
534 pass->vis[0] = '-';
535 pass->vis[1] = '-';
536 pass->vis[2] = '-';
537 pass->vis[3] = 0;
538 pass->satname = g_strdup(sat->nickname);
539 pass->details = NULL;
540 /*copy qth data into the pass for later comparisons */
541 qth_small_save(qth, &(pass->qth_comp));
542
543 /* iterate over each time step */
544 for (t = pass->aos; t <= pass->los; t += step)
545 {
546
547 /* calculate satellite data */
548 predict_calc(sat, qth, t);
549
550 /* in the first iter we want to store
551 pass->aos_az
552 */
553 if (t == pass->aos)
554 {
555 pass->aos_az = sat->az;
556 pass->orbit = sat->orbit;
557 }
558
559 /* append details to sat->details */
560 detail = g_new(pass_detail_t, 1);
561 detail->time = t;
562 detail->pos.x = sat->pos.x;
563 detail->pos.y = sat->pos.y;
564 detail->pos.z = sat->pos.z;
565 detail->pos.w = sat->pos.w;
566 detail->vel.x = sat->vel.x;
567 detail->vel.y = sat->vel.y;
568 detail->vel.z = sat->vel.z;
569 detail->vel.w = sat->vel.w;
570 detail->velo = sat->velo;
571 detail->az = sat->az;
572 detail->el = sat->el;
573 detail->range = sat->range;
574 detail->range_rate = sat->range_rate;
575 detail->lat = sat->ssplat;
576 detail->lon = sat->ssplon;
577 detail->alt = sat->alt;
578 detail->ma = sat->ma;
579 detail->phase = sat->phase;
580 detail->footprint = sat->footprint;
581 detail->orbit = sat->orbit;
582 detail->vis = get_sat_vis(sat, qth, t);
583
584 /* also store visibility "bit" */
585 switch (detail->vis)
586 {
587 case SAT_VIS_VISIBLE:
588 pass->vis[0] = 'V';
589 break;
590 case SAT_VIS_DAYLIGHT:
591 pass->vis[1] = 'D';
592 break;
593 case SAT_VIS_ECLIPSED:
594 pass->vis[2] = 'E';
595 break;
596 default:
597 break;
598 }
599
600 pass->details = g_slist_prepend(pass->details, detail);
601
602 /* store elevation if greater than the
603 previously stored one
604 */
605 if (sat->el > max_el)
606 {
607 max_el = sat->el;
608 tca = t;
609 pass->maxel_az = sat->az;
610 }
611
612 /* g_print ("TIME: %f\tAZ: %f\tEL: %f (MAX: %f)\n", */
613 /* t, sat->az, sat->el, max_el); */
614 }
615
616 pass->details = g_slist_reverse(pass->details);
617
618 /* calculate satellite data */
619 predict_calc(sat, qth, pass->los);
620 /* store los_az, max_el and tca */
621 pass->los_az = sat->az;
622 pass->max_el = max_el;
623 pass->tca = tca;
624
625 /* check whether this pass is good */
626 if (max_el >= min_el)
627 {
628 done = TRUE;
629 }
630 else
631 {
632 done = FALSE;
633 t0 = los + 0.014; // +20 min
634 free_pass(pass);
635 pass = NULL;
636 }
637
638 iter++;
639 }
640 }
641
642 return pass;
643 }
644
645 /**
646 * Predict passes after a certain time.
647 *
648 * This function calculates num upcoming passes with AOS no earlier
649 * than t = start and not later that t = (start+maxdt). The function will
650 * repeatedly call get_pass until the number of predicted passes is equal to
651 * num, the time has reached limit or the get_pass function returns NULL.
652 *
653 * \note For no time limit use maxdt = 0.0
654 *
655 * \note the data in sat will be corrupt (future) and must be refreshed
656 * by the caller, if the caller will need it later on (eg. if the caller
657 * is GtkSatList).
658 *
659 * \note Prepending to a singly linked list is much faster than appending.
660 * Therefore, the elements are prepended whereafter the GSList is
661 * reversed
662 */
get_passes(sat_t * sat,qth_t * qth,gdouble start,gdouble maxdt,guint num)663 GSList *get_passes(sat_t * sat, qth_t * qth, gdouble start,
664 gdouble maxdt, guint num)
665 {
666 GSList *passes = NULL;
667 pass_t *pass = NULL;
668 guint i;
669 gdouble t;
670
671 /* if no number has been specified
672 set it to something big */
673 if (num == 0)
674 num = 100;
675
676 t = start;
677
678 for (i = 0; i < num; i++)
679 {
680 pass = get_pass(sat, qth, t, maxdt);
681
682 if (pass != NULL)
683 {
684 passes = g_slist_prepend(passes, pass);
685 t = pass->los + 0.014; // +20 min
686
687 /* if maxdt > 0.0 check whether we have reached t = start+maxdt
688 if yes finish predictions
689 */
690 if ((maxdt > 0.0) && (t >= (start + maxdt)))
691 {
692 i = num;
693 }
694 }
695 else
696 {
697 /* we can't get any more passes */
698 i = num;
699 }
700
701 }
702
703 if (passes != NULL)
704 passes = g_slist_reverse(passes);
705
706 sat_log_log(SAT_LOG_LEVEL_INFO,
707 _("%s: Found %d passes for %s in time window [%f;%f]"),
708 __func__, g_slist_length(passes), sat->nickname, start,
709 start + maxdt);
710
711 return passes;
712 }
713
copy_pass(pass_t * pass)714 pass_t *copy_pass(pass_t * pass)
715 {
716 pass_t *new;
717
718 new = g_try_new(pass_t, 1);
719
720 if (new != NULL)
721 {
722 new->aos = pass->aos;
723 new->los = pass->los;
724 new->tca = pass->tca;
725 new->max_el = pass->max_el;
726 new->aos_az = pass->aos_az;
727 new->los_az = pass->los_az;
728 new->orbit = pass->orbit;
729 new->maxel_az = pass->maxel_az;
730 new->vis[0] = pass->vis[0];
731 new->vis[1] = pass->vis[1];
732 new->vis[2] = pass->vis[2];
733 new->vis[3] = pass->vis[3];
734 new->details = copy_pass_details(pass->details);
735
736 if (pass->satname != NULL)
737 new->satname = g_strdup(pass->satname);
738 else
739 new->satname = NULL;
740 }
741
742 return new;
743 }
744
copy_pass_details(GSList * details)745 GSList *copy_pass_details(GSList * details)
746 {
747 GSList *new = NULL;
748 guint i, n;
749
750 n = g_slist_length(details);
751 for (i = 0; i < n; i++)
752 {
753 new = g_slist_prepend(new,
754 copy_pass_detail(PASS_DETAIL
755 (g_slist_nth_data
756 (details, i))));
757 }
758
759 new = g_slist_reverse(new);
760
761 return new;
762 }
763
copy_pass_detail(pass_detail_t * detail)764 pass_detail_t *copy_pass_detail(pass_detail_t * detail)
765 {
766 pass_detail_t *new;
767
768 /* create a pass_t entry; FIXME: g_try_new in 2.8 */
769 new = g_new(pass_detail_t, 1);
770
771 new->time = detail->time;
772 new->pos.x = detail->pos.x;
773 new->pos.y = detail->pos.y;
774 new->pos.z = detail->pos.z;
775 new->pos.w = detail->pos.w;
776 new->vel.x = detail->vel.x;
777 new->vel.y = detail->vel.y;
778 new->vel.z = detail->vel.z;
779 new->vel.w = detail->vel.w;
780 new->velo = detail->velo;
781 new->az = detail->az;
782 new->el = detail->el;
783 new->range = detail->range;
784 new->range_rate = detail->range_rate;
785 new->lat = detail->lat;
786 new->lon = detail->lon;
787 new->alt = detail->alt;
788 new->ma = detail->ma;
789 new->phase = detail->phase;
790 new->footprint = detail->footprint;
791 new->orbit = detail->orbit;
792 new->vis = detail->vis;
793
794 return new;
795 }
796
free_pass(pass_t * pass)797 void free_pass(pass_t * pass)
798 {
799 if (pass != NULL)
800 {
801 free_pass_details(pass->details);
802
803 if (pass->satname != NULL)
804 {
805 g_free(pass->satname);
806 pass->satname = NULL;
807 }
808
809 g_free(pass);
810 pass = NULL;
811 }
812 }
813
814 /** \brief Free a list of passes. */
free_passes(GSList * passes)815 void free_passes(GSList * passes)
816 {
817 guint n, i;
818 gpointer pass;
819
820 n = g_slist_length(passes);
821
822 for (i = 0; i < n; i++)
823 {
824 pass = g_slist_nth_data(passes, i);
825
826 /* free element data */
827 free_pass(PASS(pass));
828 }
829
830 /* now free the list elements */
831 g_slist_free(passes);
832 passes = NULL;
833 }
834
835 /**
836 * \brief Free a pass detail structure.
837 *
838 * This function is not rarely useful except for the
839 * free_pass function.
840 */
free_pass_detail(pass_detail_t * detail)841 void free_pass_detail(pass_detail_t * detail)
842 {
843 g_free(detail);
844 detail = NULL;
845 }
846
847 /** Free the whole list of details. */
free_pass_details(GSList * details)848 void free_pass_details(GSList * details)
849 {
850 guint n, i;
851 gpointer detail;
852
853 n = g_slist_length(details);
854
855 for (i = 0; i < n; i++)
856 {
857
858 detail = g_slist_nth_data(details, i);
859
860 /* free element data */
861 free_pass_detail(PASS_DETAIL(detail));
862 }
863
864 /* free list elements */
865 g_slist_free(details);
866 details = NULL;
867 }
868
869 /**
870 * \brief Get current pass.
871 * \param sat Pointer to the satellite data.
872 * \param qth Pointer to the QTH data.
873 * \param start Time to start calculations; use 0.0 for now.
874 * \return Pointer to a newly allocated pass_t structure or NULL if
875 * there was an error.
876 *
877 * Assuming that sat->el > 0.0 this function calculates the details of the
878 * current pass from AOS time to LOS time.
879 * First the function goes back in time to before the AOS, then it calls
880 * the get_pass_no_min_el function to get the details of the current pass
881 * disregarding any minimum elevation requirements.
882 *
883 * \note The start parameter has been introduced to allow correct use of this
884 * function in non-realtime cases.
885 */
get_current_pass(sat_t * sat_in,qth_t * qth,gdouble start)886 pass_t *get_current_pass(sat_t * sat_in, qth_t * qth, gdouble start)
887 {
888 gdouble t, t0;
889 gdouble el0;
890 sat_t *sat, sat_working;
891 pass_t *pass;
892
893 /*copy sat_in to a working structure */
894 sat = memcpy(&sat_working, sat_in, sizeof(sat_t));
895
896 if (start > 0.0)
897 t = start;
898 else
899 t = get_current_daynum();
900 predict_calc(sat, qth, t);
901
902 /*save initial conditions for later comparison */
903 t0 = t;
904 el0 = sat->el;
905
906 /* check whether satellite has aos */
907 if (!has_aos(sat, qth))
908 return NULL;
909
910 /* find a time before AOS */
911 while (sat->el > 0.0)
912 {
913 predict_calc(sat, qth, t);
914 t -= 0.007; // +10 min
915 }
916
917 pass = get_pass_no_min_el(sat, qth, t, 0.0);
918 if (el0 > 0.0)
919 {
920 /* this function is only specified if the elevation
921 is greater than zero at the time it is called */
922 if (pass)
923 {
924 if (pass->aos > t0)
925 sat_log_log(SAT_LOG_LEVEL_ERROR,
926 _
927 ("%s: Returning a pass for %s that starts after the seeded time."),
928 __func__, sat->nickname);
929
930 if (pass->los < t0)
931 sat_log_log(SAT_LOG_LEVEL_ERROR,
932 _
933 ("%s: Returning a pass for %s that ends before the seeded time."),
934 __func__, sat->nickname);
935 }
936 }
937
938 return pass;
939 }
940