1#!/usr/bin/env python3
2
3# SK 17/05/2023 created
4
5"""Convert TM raw telemetry packets entries to TM events."""
6
7import logging
8
9from chart.db import ts
10from chart.events.event import Event
11from chart.events.event import include_event_check
12from chart.products.events.multitable_utils import process_ordering_sensing_time
13from chart.products.pus.packetdef import PacketDef
14from chart.products.pus.packetdef import PacketDomain
15from chart import settings
16from chart.db.model.table import TableInfo
17from chart.common.traits import is_listlike
18from chart.web.user import User
19
20# This module is used for event classes where <db-table> matches DECODER_ID
21DECODER_ID = 'TM'
22
23# Table to read all telemetry from
24TM_TABLE = 'TM'
25
26# ??? !!! For some reason we can't get this from the events XML file where we should get it
27# from, so as a terrible and lazy hack it's hard-coded here
28EVENT_CLASSNAME = 'SGA1-ACC-THR-ON-TIME'
29
30# tm_parameter = {
31 # # 'ASTD06E0': 'HKA_MODE',
32 # # 'ASTD07D6': 'HKA_SUBMODE',
33 # # 'PFET0015': 'SADEA CAL. POSITION A',
34 # 'AST0155A': 'THRONTACC(1)',
35 # 'AST00F01': 'THRONTACC(2)',
36 # 'AST013A9': 'THRONTACC(3)',
37 # 'AST010E1': 'THRONTACC(4)',
38 # 'AST01249': 'THRONTACC(5)',
39 # 'AST008F3': 'THRONTACC(6)',
40 # 'AST01690': 'THRONTACC(7)',
41 # 'AST0101A': 'THRONTACC(8)',
42 # # 'AST01E19': 'THRABONTACC(1)',
43 # # 'AST01DF8': 'THRABONTACC(2)',
44 # # 'AST01E71': 'THRABONTACC(3)',
45 # # 'AST01DD8': 'THRABONTACC(4)',
46 # # 'AST00AB5': 'THRNUMPULSESACC(1)',
47 # # 'AST01409': 'THRNUMPULSESACC(2)',
48 # # 'AST00ED4': 'THRNUMPULSESACC(3)',
49 # # 'AST016CA': 'THRNUMPULSESACC(4)',
50 # # 'AST0062A': 'THRNUMPULSESACC(5)',
51 # # 'AST00F0A': 'THRNUMPULSESACC(6)',
52 # # 'AST0126B': 'THRNUMPULSESACC(7)',
53 # # 'AST01386': 'THRNUMPULSESACC(8)',
54 # # 'AST01F2A': 'THRABNUMPULSESACC(1)',
55 # # 'AST01C54': 'THRABNUMPULSESACC(2)',
56 # # 'AST01E00': 'THRABNUMPULSESACC(3)',
57 # # 'AST01D2F': 'THRABNUMPULSESACC(4)',
58 # # 'AST0060A': 'FINEATTRATE_C1',
59 # # 'AST004E8': 'FINEATTRATE_C2',
60 # # 'AST00731': 'FINEATTRATE_C3',
61 # # 'AST012EE': 'DVESTSUMSTATELOG_C(1)',
62 # # 'AST015EC': 'DVESTSUMSTATELOG_C(2)',
63 # # 'AST00720': 'DVESTSUMSTATELOG_C(3)',
64 # # 'AST01F2B': 'DVESTSUMSTATELOG_O(1)',
65 # # 'AST01ECC': 'DVESTSUMSTATELOG_O(2)',
66 # # 'AST01F86': 'DVESTSUMSTATELOG_O(3)',
67 # # 'AST016A9': 'THTANKPRESSEST',
68 # # 'AST011E5': 'THRFUELMASSCONSTOT'
69#}
70
71# print("tm_parameter:")
72# for k, v in tm_parameter.items():
73 # print(f"{k}: {v}")
74
75logger = logging.getLogger()
76
77def find_events(sid,
78 start_time,
79 start_time_eq,
80 stop_time,
81 event_classes,
82 ordering,
83 from_to,
84 properties,
85 count,
86 single,
87 filtering,
88 multitable_extra_params,
89 user: User = None):
90 """Build Event records from records extracted from ts table in given time range.
91
92 Args:
93 `sid` (SID): Source-ID to search for
94 `start_time` (datetime): Start of time range to search
95 `stop_time` (datetime): End of time range to search
96 `event_classes` (list of EventClass): Class definitions to search for - this is relevant for
97 implementations of find_event() which are reading from tables which could return
98 multiple different types of event.
99 `ordering` (str or list of str): Field(s) to sort by
100 `from_to` (tuple): (page_start, page_stop)
101 `properties`: (list): list of property triplets (name, value, op)
102 `count`: (bool): just return the number of events found
103 `single`: (bool): just return the first event which matches input requirements
104 `filtering` (EventTimeFilter): Specify if the start_time/stop_time range is applied
105 to the sensing_time or the execution_time column
106 `multitable_extra_params` (tuple): Special method of storing additional table-specific information
107 in an Event object, which is passed via json to the event viewer table and back,
108 and used again in this function to ecreate the original Event
109
110 Returns:
111 event_count: (int) number of events which match input requirements
112 events: list of events which match input requirements
113 """
114
115 if from_to is not None:
116 page_start, page_stop = from_to
117
118 # if returning a single record, set limit = 1
119 # Note: there can be so many TM packets so when a single set, for the 'Snap' case
120 # set limit option to prevent database hanging. Do not set limit when single
121 # set due selecting event pop-up as handled by ts.select
122 limit = None
123 if single and start_time_eq is None:
124 limit = 1
125
126 # Instead of returning an iterator, we build the whole list and return it
127 events = []
128 # Total count of events. This may be larger than len(events) since we may be pagingating
129 # using the `from_to` parameter and as an optimisation, we don't bother to instantiate all
130 # the required Events objects, just enough for the event viewer to work. However we still
131 # want to tell the user how many events are available
132 event_count = 0
133
134 # Reset ordering for sensing_time
135 order_clauses = process_ordering_sensing_time(ordering)
136
137 table_info = TableInfo(TM_TABLE, sid=sid, fast_load=True)
138
139 if not single and count:
140 # just return count of events
141 event_count = ts.count(
142 table=table_info.storage_table,
143 field='SENSING_TIME',
144 method='ap',
145 sid=sid,
146 sensing_start=start_time,
147 sensing_stop=stop_time)
148
149 return event_count, events
150
151 # fields = ('SENSING_TIME',)
152 # for key in tm_parameter.keys():
153 # fields += (table_info.fields.get(key),)
154
155 # # get each row using ts select
156 # for row in ts.select(sid=sid,
157 # sensing_start=start_time,
158 # sensing_stop=stop_time,
159 # sensing_time=start_time_eq,
160 # table=table_info.storage_table,
161 # fields=fields,
162 # ordering=order_clauses,
163 # limit=limit):
164
165 for sensing_time, spid, payload in ts.select(
166 table=table_info.storage_table,
167 sid=sid,
168 sensing_start=start_time,
169 sensing_stop=stop_time,
170 sensing_time=start_time_eq,
171 fields=('SENSING_TIME', 'SPID', 'PAYLOAD'),
172 where=('spid in (30622, 30507)', '(payload?\'AST0155A\' or payload?\'AST00F01\' or payload?\'AST013A9\' or payload?\'AST010E1\' or payload?\'AST01249\' or payload?\'AST008F3\' or payload?\'AST01690\' or payload?\'AST0101A\' or payload?\'AST01E19\' or payload?\'AST01DF8\' or payload?\'AST01E71\' or payload?\'AST01DD8\')'),
173 ordering=order_clauses):
174
175 # print(sensing_time, spid, payload.get('AST0155A'), payload.get('AST01DD8'))
176 sensing_time = sensing_time
177 # ASTD06E0_values = row[1]
178 # ASTD07D6_values = row[2]
179 # PFET0015_values = row[1]
180 AST0155A_values = payload.get('AST0155A')
181 AST00F01_values = payload.get('AST00F01')
182 AST013A9_values = payload.get('AST013A9')
183 AST010E1_values = payload.get('AST010E1')
184 AST01249_values = payload.get('AST01249')
185 AST008F3_values = payload.get('AST008F3')
186 AST01690_values = payload.get('AST01690')
187 AST0101A_values = payload.get('AST0101A')
188 AST01E19_values = payload.get('AST01E19')
189 AST01DF8_values = payload.get('AST01DF8')
190 AST01E71_values = payload.get('AST01E71')
191 AST01DD8_values = payload.get('AST01DD8')
192 # AST00AB5_values = row[16]
193 # AST01409_values = row[17]
194 # AST00ED4_values = row[18]
195 # AST016CA_values = row[19]
196 # AST0062A_values = row[20]
197 # AST00F0A_values = row[21]
198 # AST0126B_values = row[22]
199 # AST01386_values = row[23]
200 # AST01F2A_values = row[24]
201 # AST01C54_values = row[25]
202 # AST01E00_values = row[26]
203 # AST01D2F_values = row[27]
204 # AST0060A_values = row[28]
205 # AST004E8_values = row[29]
206 # AST00731_values = row[30]
207 # AST012EE_values = row[31]
208 # AST015EC_values = row[32]
209 # AST00720_values = row[33]
210 # AST01F2B_values = row[34]
211 # AST01ECC_values = row[35]
212 # AST01F86_values = row[36]
213 # AST016A9_values = row[37]
214 # AST011E5_values = row[38]
215
216 inst_properties = {
217 'SID': sid,
218 # 'ASTD06E0': ASTD06E0_values,
219 # 'ASTD07D6': ASTD07D6_values,
220 # 'PFET0015': PFET0015_values,
221 'AST0155A': AST0155A_values,
222 'AST00F01': AST00F01_values,
223 'AST013A9': AST013A9_values,
224 'AST010E1': AST010E1_values,
225 'AST01249': AST01249_values,
226 'AST008F3': AST008F3_values,
227 'AST01690': AST01690_values,
228 'AST0101A': AST0101A_values,
229 'AST01E19': AST01E19_values,
230 'AST01DF8': AST01DF8_values,
231 'AST01E71': AST01E71_values,
232 'AST01DD8': AST01DD8_values,
233 # 'AST00AB5': AST00AB5_values,
234 # 'AST01409': AST01409_values,
235 # 'AST00ED4': AST00ED4_values,
236 # 'AST016CA': AST016CA_values,
237 # 'AST0062A': AST0062A_values,
238 # 'AST00F0A': AST00F0A_values,
239 # 'AST0126B': AST0126B_values,
240 # 'AST01386': AST01386_values,
241 # 'AST01F2A': AST01F2A_values,
242 # 'AST01C54': AST01C54_values,
243 # 'AST01E00': AST01E00_values,
244 # 'AST01D2F': AST01D2F_values,
245 # 'AST0060A': AST0060A_values,
246 # 'AST004E8': AST004E8_values,
247 # 'AST00731': AST00731_values,
248 # 'AST012EE': AST012EE_values,
249 # 'AST015EC': AST015EC_values,
250 # 'AST00720': AST00720_values,
251 # 'AST01F2B': AST01F2B_values,
252 # 'AST01ECC': AST01ECC_values,
253 # 'AST01F86': AST01F86_values,
254 # 'AST016A9': AST016A9_values,
255 # 'AST011E5': AST011E5_values,
256 }
257
258 #print("inst_properties",inst_properties)
259
260 if multitable_extra_params is not None:
261 req_spid, req_sequence_count = multitable_extra_params
262 if req_spid != packet_reader.spid or req_sequence_count != sequence_count:
263 continue
264
265 # now filter properties in inst_properties before keeping event for viewing
266 if not include_event_check(properties, inst_properties):
267 continue
268
269 # if we are counting, just bump the counter, else yield event and bump counter
270 # Note: must count all events which meet the filtering criterea to keep paging upto date
271 event_count += 1
272
273 if not count:
274 # build event and append to events to return
275 if from_to is None or (page_start <= event_count and event_count <= page_stop):
276 # build event and append to events to return, if within Eventviewer display page
277 events.append(Event(sid=sid,
278 event_classname=EVENT_CLASSNAME,
279 start_time=sensing_time,
280 #multitable_extra_params=(spid, sequence_count),
281 instance_properties=inst_properties))
282
283 if single:
284 # just return first event, which matches search requirements
285 break
286
287 return event_count, events