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