1#!/usr/bin/env python3
  2
  3"""Command line SID and time conversion functions.
  4
  5Allows:
  6- Test the settings.SOURCES XML SID configuration file
  7- List and query SID, satellites and ground stations
  8- Synthesize ANX events to create test or repair data for computing orbital stats
  9- Convert between timestamps and satellite orbit numbers
 10"""
 11import sys
 12
 13from datetime import datetime
 14
 15from chart.common.prettyprint import Table
 16from chart.common.args import ArgumentParser
 17from chart.db.connection import db_connect
 18from chart.timeconv import convert
 19from chart.project import settings
 20from chart.project import SID
 21# from chart.db.func import ANY
 22
 23
 24NEWLINE = '\n'
 25
 26
 27def list_sids(operational=None, visible=None, target=sys.stdout):
 28    """Show available SIDs."""
 29    t = Table(headings=('ID', 'Name', 'Operational', 'Visible', 'Long name / desc'))
 30    for sid in SID.all(operational=operational, visible=visible):
 31        row = []
 32        if hasattr(sid, 'sid_num'):
 33            row.append(sid.sid_num)
 34
 35        row.extend([sid.name, sid.operational, sid.visible])
 36        row.append('. '.join(s for s in (sid.long_name, sid.description) if s is not None))
 37        t.append(row)
 38
 39    t.write()
 40
 41
 42def list_special_packets(target=sys.stdout):
 43    t = Table(title='PUS ingestion special packets',
 44              headings=('Name', 'SPID'))
 45    for sp in ('good_frame_spid', 'bad_frame_spid', 'unknown_packet_spid', 'bad_packet_spid',
 46               'idle_packet_spid', 'idle_frame_spid'):
 47        t.append((sp, getattr(SID.special_packets, sp)))
 48
 49    t.write()
 50
 51
 52def synth_anx(sid, first_orbit, first_time, orbit_delta, time_delta, last_orbit=None, last_time=None):
 53    """Synthesize ANX events to allow orbital stats to be computed."""
 54    db_conn = db_connect('FDF_EVENTS')
 55    ins_cur = db_conn.prepared_cursor(
 56        'INSERT INTO FDF_EVENTS ('
 57        '  start_time, stop_time, scid, orbit, name, target, fdf_uid, extra, gen_time) VALUES ('
 58        '  :start_time, :stop_time, :scid, :orbit, :name, :target, :fdf_uid, :extra, :gen)')
 59    orbit = first_orbit
 60    timestamp = first_time
 61    while True:
 62        ins_cur.execute(None,
 63                        start_time=timestamp,
 64                        stop_time=timestamp,
 65                        scid=sid.scid,
 66                        orbit=orbit,
 67                        name='ANX',
 68                        target=None,
 69                        fdf_uid=1,
 70                        extra=None,
 71                        gen=datetime.utcnow())
 72        print(orbit, timestamp)
 73        orbit += orbit_delta
 74        timestamp += time_delta
 75        if (orbit_delta < 0 and orbit < last_orbit) or\
 76           (orbit_delta > 0 and orbit > last_orbit):
 77            break
 78
 79    db_conn.commit()
 80
 81# synth_anx(SID('N18'), 5958, datetime(2006, 7, 17, 1, 28, 30), -1, timedelta(minutes=-102), last_orbit=1)
 82
 83
 84def main():
 85    """Command line entry point."""
 86    parser = ArgumentParser()
 87    parser.add_argument('--db',
 88                        metavar='CONN',
 89                        help='Use database connection CONNECTION')
 90    parser.add_argument('--sid', '-s',
 91                        help='Source ID',
 92                        type=ArgumentParser.sid)
 93    parser.add_argument('--time', '-t',
 94                        help='Show info on single time point',
 95                        type=ArgumentParser.datetime)
 96    parser.add_argument('--orbit', '-o',
 97                        help='Show info on single orbit',
 98                        type=int)
 99    parser.add_argument('--start',
100                        type=ArgumentParser.start_time,
101                        metavar='TIME',
102                        help='Begin search at TIME.')
103    parser.add_argument('--stop',
104                        type=ArgumentParser.stop_time,
105                        metavar='TIME',
106                        help='End search at TIME.')
107    parser.add_argument('--list-sids', '--list', '-l',
108                        action='store_true',
109                        help='Show available SID objects')
110    parser.add_argument('--visible',
111                        type=bool,
112                        default=None,
113                        help='Show/hide visible SIDs')
114    parser.add_argument('--operational',
115                        type=bool,
116                        default=None,
117                        help='Show/hide operational SIDs')
118    parser.add_argument('--list-special-packets',
119                        action='store_true',
120                        help='Show the PUS special packets for this mission')
121
122    args = parser.parse_args()
123
124    target = sys.stdout
125
126    if args.list_sids:
127        list_sids(operational=args.operational, visible=args.visible)
128        parser.exit()
129
130    if args.list_special_packets:
131        list_special_packets()
132        parser.exit()
133
134    # switch databases (must be first option handled)
135    if args.db:
136        settings.set_db_name(args.db)
137
138    if args.sid:
139        if args.time and not args.orbit and not args.start and not args.stop:
140            target.write('Orbit: {o}\n'.format(o=args.sid.orbit.find_orbit(args.time)))
141            parser.exit()
142
143        elif args.orbit and not args.start and not args.stop:
144            res = args.sid.orbit.get_orbit_times(args.orbit)
145            if res is None:
146                target.write('Orbit not found\n')
147
148            else:
149                target.write("""Start time: {strt}
150Stop time: {stop}
151Duration: {dur}
152""".format(strt=res[0], stop=res[1], dur=res[1] - res[0]))
153
154            parser.exit()
155
156        elif args.start and args.stop:
157            t = Table(headings=('Orbit', 'Start', 'Stop'))
158            for o in args.sid.orbit.orbits_in_range(args.start, args.stop):
159                t.append((o['number'], o['start_time'], o['stop_time']))
160
161            t.write()
162
163            parser.exit()
164
165        else:
166            parser.error('Unrecognised options')
167
168    elif args.orbit:
169        parser.error('Cannot pass --orbit without --sid')
170
171    elif args.start or args.stop:
172        parser.error('Unrecognised options')
173
174    else:
175        dt = args.time
176        target.write("""Time: {dt}
177DOY: {doy}
178Week: {week}
179""".format(dt=dt, doy=convert.to_day_of_year(dt), week=convert.to_week(dt)))
180
181if __name__ == '__main__':
182    main()