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()