11 from telemetry
import ccsdspy
14 __version__ =
"1.1.0 (2024-05-20)"
18 print(
"tlmgen_pace", __version__)
21 parser = argparse.ArgumentParser(
22 formatter_class=argparse.RawTextHelpFormatter,
23 description=
"Convert S-band housekeeping telemetry to CSV for specified fields",
28 101 : Non-fatal file open error
29 102 : Invalid file or instrument from CFE header
30 103 : Invalid packet header
31 104 : Invalid packet [header/datatype/length]
32 110 : No valid packets found
33 120 : Multiple warnings; see log
39 help=
"path to S-band telemetry (HSK) file OR list of input files, one per line",
42 "-o",
"--ofile", type=str, help=
"output CSV file; defaults to ifile.csv"
47 help=
"path to directory containing packet structures for desired mnemonics.",
54 help=
"print status messages",
56 args = parser.parse_args()
59 loglevel = logging.INFO
if args.verbose
else logging.WARNING
60 logging.basicConfig(format=
"%(levelname)s: %(message)s", level=loglevel)
63 if args.packetdir
is None:
64 pktDir = os.path.join(
65 os.getenv(
"OCDATAROOT"),
"telemetry",
"pace",
"monitoring"
68 pktDir = args.packetdir
69 if not os.path.exists(pktDir):
70 logging.error(f
"ERROR: The directory {pktDir} does not exist.")
74 csvfile = os.path.join(pktDir,
"LinearConverters.csv")
75 if os.path.exists(csvfile):
76 conversions = pd.read_csv(csvfile)
77 for column
in [
"slope",
"intercept"]:
78 if isinstance(conversions[column][0], str):
79 conversions[column] = [eval(v)
for v
in conversions[column]]
83 for csvfile
in glob.glob(os.path.join(pktDir,
"APID[0-9]*.*.csv")):
85 os.path.basename(csvfile).split(
".", maxsplit=1)[0].replace(
"APID",
"")
87 packetDef[apid] = ccsdspy.FixedLength.from_file(csvfile)
90 for name
in [f._name
for f
in packetDef[apid]._fields]:
91 row = conversions.loc[conversions[
"mnemonic"] == name]
93 packetDef[apid].add_converted_field(
97 slope=row.slope.values[0], intercept=row.intercept.values[0]
101 ofile = f
"{args.ifile}.csv" if args.ofile
is None else args.ofile
105 infile = os.path.expandvars(args.ifile)
108 with open(infile, mode=
"rt")
as flist:
112 filelist.append(os.path.expandvars(ifile.rstrip()))
113 except UnicodeDecodeError:
117 logging.error(f
"{e}; exiting")
120 if not len(filelist):
121 filelist.append(infile)
126 for filename
in filelist:
127 logging.info(f
"Reading {filename}")
128 fname = os.path.basename(filename)
132 ifile = open(filename, mode=
"rb")
134 status = 120
if status > 0
else 101
135 logging.warning(f
"{e}; continuing")
139 filehdr = readFileHeader(ifile)
141 logging.info(filehdr)
146 filehdr[
"subtype"] == 101
147 and filehdr[
"length"] == 64
148 and filehdr[
"SCID"] == b
"PACE"
149 and filehdr[
"processorid"]
in (1, 2, 30)
152 if not filehdr
or not desired:
153 status = 120
if status > 0
else 102
155 logging.warning(f
"File {filename} has invalid header; continuing")
158 logging.error(f
"File {filename} has invalid header; returning")
163 ifile, include_primary_header=
True
167 for k, v
in header.items():
172 if header[
"CCSDS_PACKET_LENGTH"] > 16378:
173 status = 120
if status > 0
else 103
175 f
"File {filename} contains invalid CCSDS packet header: {header}"
180 if len(data) < header[
"CCSDS_PACKET_LENGTH"] + 1:
181 status = 120
if status > 0
else 104
183 f
"File {filename} has unexpected EOF: expected"
184 f
" {header['CCSDS_PACKET_LENGTH']+1} more bytes, got {len(data)}"
190 header[
"CCSDS_SECONDARY_FLAG"] == 1
199 apid = header[
"CCSDS_APID"]
200 if apid
in packetDef.keys():
201 myDict = (packetDef[apid]).
load(BytesIO(packet))
202 for key, val
in myDict.items():
203 if not key.endswith(
"time"):
205 outdict[
"filename"] = fname
206 outdict[
"time_val"] = timestamp.strftime(
207 "%Y-%m-%d %H:%M:%S.%f"
210 outdict[
"value"] = val[0]
211 outdict[
"alert_type"] =
""
212 outdict[
"recorded"] =
""
213 dictList.append(outdict)
221 if len(dictList) > 0:
222 logging.info(f
"Writing {len(dictList)} records from {fname} to {ofile}")
223 df = pd.DataFrame(dictList)
224 df.to_csv(ofile, sep=
",", index=
False, header=writeheader, mode=
"a")
230 logging.warning(f
"No requested packets found.")
231 status = 120
if status > 0
else 110
234 logging.warning(f
"Exiting with status code {status}")
238 if __name__ ==
"__main__":