Skip to content

Commit 33865ba

Browse files
authored
Merge pull request #321 from NASA-AMMOS/issue-320
Issue #320 - Add limits_find_dn utility
2 parents 57d26d1 + 7c4c3ae commit 33865ba

File tree

4 files changed

+169
-0
lines changed

4 files changed

+169
-0
lines changed

ait/core/bin/ait_limits_find_dn.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#!/usr/bin/env python
2+
# Advanced Multi-Mission Operations System (AMMOS) Instrument Toolkit (AIT)
3+
# Bespoke Link to Instruments and Small Satellites (BLISS)
4+
#
5+
# Copyright 2021, by the California Institute of Technology. ALL RIGHTS
6+
# RESERVED. United States Government Sponsorship acknowledged. Any
7+
# commercial use must be negotiated with the Office of Technology Transfer
8+
# at the California Institute of Technology.
9+
#
10+
# This software may be subject to U.S. export control laws. By accepting
11+
# this software, the user agrees to comply with all applicable U.S. export
12+
# laws and regulations. User has the responsibility to obtain export licenses,
13+
# or other export authority as may be required before exporting such
14+
# information to foreign countries or providing access to foreign persons.
15+
16+
'''
17+
ait-limits-find-dn
18+
19+
Extract the DN-equivalent value for EU limit trip thresholds
20+
21+
usage:
22+
> ait-limits-find-dn
23+
24+
This utility requires well-formed telemetry and limits dictionaries. DN thresholds
25+
are brute forced for each limit. Partial limit definitions (i.e., without an
26+
upper and lower error / warn value) are supported. Any missing limit values or
27+
points where a threshold cannot be found for the field's DN-to-EU equation will
28+
be displayed as None in the final table.
29+
30+
Note, "value" limits are not supported by this script and will be skipped. An
31+
example value limit:
32+
33+
- !Limit
34+
source: Ethernet_HS_Packet.product_type
35+
desc: Ethernet Product Type field
36+
value:
37+
error: MEM_DUMP
38+
warn:
39+
- TABLE_FOO
40+
- TABLE_BAR
41+
'''
42+
43+
from ait.core import limits
44+
from ait.core import log
45+
from ait.core import tlm
46+
47+
48+
def main():
49+
DNLimits = {}
50+
EULimits = {}
51+
EUValues = {}
52+
53+
ld = limits.getDefaultDict()
54+
td = tlm.getDefaultDict()
55+
56+
all_vals = [
57+
[
58+
"Telem Point",
59+
"EU lower.error",
60+
"EU lower.warn",
61+
"EU upper.warn",
62+
"EU upper.error",
63+
"DN lower.error",
64+
"DN lower.warn",
65+
"DN upper.warn",
66+
"DN upper.error",
67+
"DN to EU LE",
68+
"DN to EU LW",
69+
"DN to EU UW",
70+
"DN to EU UE",
71+
]
72+
]
73+
74+
for source in sorted(ld.keys(), key=lambda x: x.split(".")[1]):
75+
log.info(f"Processing {source}")
76+
limit = ld[source]
77+
pkt_name, name = source.split(".")
78+
79+
# Don't support limits specifying individual values. This is usually
80+
# used to specify enumerations that aren't valid and we don't properly
81+
# handle those cases.
82+
if ld[source].value is not None:
83+
log.warn(f'Skipping unsupported "value" limit {source}')
84+
continue
85+
86+
DNLimits.setdefault(name, [None, None, None, None])
87+
EULimits.setdefault(name, [None, None, None, None])
88+
EUValues.setdefault(name, [None, None, None, None])
89+
90+
if ld[source].lower is not None:
91+
try:
92+
EULimits[name][0] = ld[source].lower.error
93+
except AttributeError:
94+
pass
95+
96+
try:
97+
EULimits[name][1] = ld[source].lower.warn
98+
except AttributeError:
99+
pass
100+
101+
if ld[source].upper is not None:
102+
try:
103+
EULimits[name][2] = ld[source].upper.warn
104+
except AttributeError:
105+
pass
106+
107+
try:
108+
EULimits[name][3] = ld[source].upper.error
109+
except AttributeError:
110+
pass
111+
112+
values = []
113+
114+
defn = td[pkt_name]
115+
data = bytearray(defn.nbytes)
116+
packet = tlm.Packet(defn, data)
117+
for dn in range(65536):
118+
setattr(packet, name, dn)
119+
eu = getattr(packet, name)
120+
121+
if eu is not None:
122+
values.append((dn, eu))
123+
124+
values.sort(key=lambda pair: pair[1])
125+
126+
for dn, eu in values:
127+
for n in range(4):
128+
if (
129+
EULimits[name][n] is not None
130+
and DNLimits[name][n] is None
131+
and eu > EULimits[name][n]
132+
):
133+
value = dn - 1 if dn > 0 else 0
134+
DNLimits[name][n] = value
135+
136+
setattr(packet, name, value)
137+
EUValues[name][n] = getattr(packet, name)
138+
139+
if all(DNLimits[name][n] is not None for n in range(4)):
140+
break
141+
142+
values = [source]
143+
values.extend(map(str, EULimits[name]))
144+
values.extend(map(str, DNLimits[name]))
145+
values.extend(map(str, EUValues[name]))
146+
all_vals.append(values)
147+
148+
s = [[str(e) for e in row] for row in all_vals]
149+
lens = [max(map(len, col)) for col in zip(*s)]
150+
fmt = "\t".join("{{:{}}}".format(x) for x in lens)
151+
table = [fmt.format(*row) for row in s]
152+
print("\n".join(table))
153+
154+
if __name__ == '__main__':
155+
main()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ait.core.bin.ait\_limits\_find\_dn module
2+
=========================================
3+
4+
.. automodule:: ait.core.bin.ait_limits_find_dn
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

doc/source/ait.core.bin.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Submodules
1414
ait.core.bin.ait_cmd_send
1515
ait.core.bin.ait_create_dirs
1616
ait.core.bin.ait_dict_writer
17+
ait.core.bin.ait_limits_find_dn
1718
ait.core.bin.ait_mps_seq_convert
1819
ait.core.bin.ait_pcap
1920
ait.core.bin.ait_pcap_segment

doc/source/command_line.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ ait-create-dirs
120120
:start-after: '''
121121
:end-before: '''
122122

123+
ait-limits-find-dn
124+
^^^^^^^^^^^^^^^^^^
125+
.. literalinclude:: ../../ait/core/bin/ait_limits_find_dn.py
126+
:start-after: '''
127+
:end-before: '''
128+
123129
ait-yaml-validate
124130
^^^^^^^^^^^^^^^^^^^
125131
.. literalinclude:: ../../ait/core/bin/ait_yaml_validate.py

0 commit comments

Comments
 (0)