diff --git a/imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml b/imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml index 3012140ba6..a2ce61c7f1 100644 --- a/imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +++ b/imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml @@ -15,10 +15,10 @@ imap_idex_l1a_sci: Logical_source: imap_idex_l1a_sci-1week Logical_source_description: IMAP Mission IDEX Instrument Level-1A Weekly Data. -imap_idex_l1a_evt: +imap_idex_l1a_msg: <<: *instrument_base - Data_type: L1A_EVT>Level-1A Event Message Data - Logical_source: imap_idex_l1a_evt + Data_type: L1A_MSG>Level-1A Event Message Data + Logical_source: imap_idex_l1a_msg Logical_source_description: IMAP Mission IDEX Instrument Level-1A Event Message Data. imap_idex_l1a_catlst: @@ -33,10 +33,10 @@ imap_idex_l1b_sci: Logical_source: imap_idex_l1b_sci-1week Logical_source_description: IMAP Mission IDEX Instrument Level-1B Weekly Data. -imap_idex_l1b_evt: +imap_idex_l1b_msg: <<: *instrument_base - Data_type: L1B_EVT>Level-1B Event Message Data - Logical_source: imap_idex_l1b_evt + Data_type: L1B_MSG>Level-1B Event Message Data + Logical_source: imap_idex_l1b_msg Logical_source_description: IMAP Mission IDEX Instrument Level-1B Event Message Data. imap_idex_l1b_catlst: diff --git a/imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml b/imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml index a95396315d..4cf422b550 100644 --- a/imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +++ b/imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml @@ -208,6 +208,12 @@ shfine: LABLAXIS: Packet Generation Time (Fine) UNITS: seconds +messages: + <<: *string_base + CATDESC: Rendered IDEX event message text + FIELDNAM: Event message text + FORMAT: A160 + checksum: <<: *trigger_base CATDESC: CRC 16 Checksum diff --git a/imap_processing/cli.py b/imap_processing/cli.py index bda67b625f..67b4a73726 100644 --- a/imap_processing/cli.py +++ b/imap_processing/cli.py @@ -1081,7 +1081,7 @@ def do_processing( sci_dependencies = [load_cdf(f) for f in sci_files] # sort science files by the first epoch value sci_dependencies.sort(key=lambda ds: ds["epoch"].values[0]) - hk_files = dependencies.get_file_paths(source="idex", descriptor="evt") + hk_files = dependencies.get_file_paths(source="idex", descriptor="msg") # Remove duplicate housekeeping files hk_dependencies = [load_cdf(dep) for dep in list(set(hk_files))] # sort housekeeping files by the first epoch value diff --git a/imap_processing/idex/evt_msg_decode_utils.py b/imap_processing/idex/evt_msg_decode_utils.py new file mode 100644 index 0000000000..c2e9948401 --- /dev/null +++ b/imap_processing/idex/evt_msg_decode_utils.py @@ -0,0 +1,82 @@ +"""Helper functions for decoding event messages.""" + +import re + +# Regex to match spaces where we need to embed params in the event message templates, +# e.g. {p0}, {p1+2}, {p3:dict}, {p4+1|dict} +EMBEDDED_PARAM_RE = re.compile(r"\{p(\d+)(?:\+(\d+))?(?::[\w]+)?(?:\|(\w+))?\}") + + +def render_event_template( + event_description_template: str, params_bytes: list, msg_json_data: dict +) -> str: + """ + Produce an event message string by replacing placeholders with parameter values. + + Example template: + "Event {p0} occurred with value {p1+2:dictName}" + + This would replace {p0} with the hex value of params[0], and replace {p1+2:dictName} + with the combined hex value of params[1] and params[2] (treated as big-endian bytes) + looked up in the dictionary named "dictName" for a human-readable string, or + rendered as hex if not found in the dictionary. + + Parameters + ---------- + event_description_template : str + The event message template containing placeholders like {p0}, {p1+2}, + {p3:dict}, {p4+1|dict}. + params_bytes : list + The list of parameter values to substitute into the template. + msg_json_data : dict + Mapping of parameter values to human-readable strings for decoding event + messages. + + Returns + ------- + str + The rendered event message with placeholders replaced by parameter values. + """ + + def replace(m: re.Match[str]) -> str: + """ + Replace a single placeholder match with the corresponding parameter value. + + Parameters + ---------- + m : re.Match[str] + A regex match object for a placeholder in the template. + + Returns + ------- + str + The string to replace the placeholder with. + """ + # We are parsing the placeholder value here to determine which parameter + # to substitute and how to format them. + # group one is the parameter index e.g. p0-3 + idx = int(m.group(1)) + # group two is the optional byte length e.g. +2 (so we know how many params + # to combine) + n_bytes = int(m.group(2)) if m.group(2) else 1 + # group three is an optional dictionary name to use for decoding this parameter + dict_name = m.group(3) + value = 0 + for i in range(n_bytes): + # combine the next n_bytes params into a single integer value, treating + # them as big-endian bytes + value = (value << 8) | ( + params_bytes[idx + i] if idx + i < len(params_bytes) else 0 + ) + # If a dictionary name is provided use it to decode the value, otherwise just + # render as hex. + if dict_name: + resolved = msg_json_data.get(dict_name, {}).get( + value, f"0x{value:0{2 * n_bytes}X}" + ) + return f"{dict_name}({resolved})" # wrap with dict name + + return f"{value:02x}" + + # Replace all placeholders in the template using the replace function defined above. + return EMBEDDED_PARAM_RE.sub(replace, event_description_template) diff --git a/imap_processing/idex/idex_evt_msg_parsing_dictionaries.json b/imap_processing/idex/idex_evt_msg_parsing_dictionaries.json new file mode 100644 index 0000000000..be721d716e --- /dev/null +++ b/imap_processing/idex/idex_evt_msg_parsing_dictionaries.json @@ -0,0 +1,1377 @@ +{ + "logEntryIdDictionary": { + "0": "EMPTY", + "8": "PMLOG_INIT", + "10": "TASK_START", + "11": "SLICE_ERR", + "12": "PERF_PARAM_ERR", + "13": "PERF_DURR_ERR", + "14": "TASK_OVERRUN", + "15": "TASK_DONE", + "17": "EXEC_CMD", + "18": "GOT_RX_DATA", + "19": "GOOD_CCSDS", + "20": "EXEC_TIME", + "21": "DUAL_EXPIRED", + "30": "START_TX_PKT", + "32": "RX_CKSUM_ERR", + "36": "CCSDS_RX_ERR", + "37": "CMD_LEN_INVLD", + "38": "CMD_UNKNOWN", + "39": "CMD_RJCT_UNARM", + "40": "CMD_RJCT_ENGINE", + "41": "CMD_RJCT_ARGNUM", + "42": "CMD_RJCT_NULL", + "43": "CMD_RJCT_RANGE", + "44": "CMD_RJCT_MODE", + "45": "CMD_RJCT_BUSY", + "46": "CMD_NO_CMD_YET", + "48": "QBOOT_ST_CHANGE", + "49": "QBOOT_HALTED", + "50": "QBOOT_ALRDY_IDLE", + "51": "QBOOT_MEM_BUSY", + "58": "REGION_OFF_DIE", + "59": "INIT_FLASH_FOUND", + "60": "LOAD_OFF_DIE", + "61": "MEMINIT_OBJ_MISS", + "63": "INIT_CKSUM_MISMT", + "64": "UERR_SCI_DATA", + "65": "LISTED_CATALOGS", + "66": "MAKE_CATALOG_ERR", + "67": "SCI_DATA_DROPPED", + "68": "FEWER_SCI_BLOCKS", + "69": "COPYTO_NO_HALT", + "70": "AUTOSAVE_ERR", + "71": "RECOVR_MODE_RST", + "72": "RECOVR_OPER_RST", + "73": "ANALYZE_ERROR", + "74": "BOTH_MIRROR_BAD", + "75": "FOUND_SCI_DATA", + "76": "MEM_QUEUE_RJCT", + "77": "MEM_COLLAB_START", + "78": "MEM_COLLAB_SUCC", + "79": "MEM_COLLAB_FAIL", + "80": "REBUILD_SUMMARY", + "81": "CKSUM_MISMATCH", + "82": "MISMATCH_REBUILT", + "83": "FLASH_DIE_UNUSED", + "84": "NO_CHANGE_NVFSW3", + "85": "FLASH_DRIVER_ERR", + "86": "OPERATION_FAILED", + "87": "FOUND_BAD_BLOCK", + "88": "FLASH_UERR", + "89": "FLASH_CERR", + "90": "BAD_MEM_CLEANUP", + "91": "FLASH_DRIVER_ERR", + "92": "MEM_OBJ_MISSING", + "93": "BAD_MODE_EXIT", + "94": "BAD_OPER_EXIT", + "95": "SHUFFLE_ERROR", + "96": "MEM_OP_QUEUED", + "97": "MEM_FLASH_FOUND", + "98": "MEM_OP_HALTED", + "99": "MEM_OP_START", + "100": "MEM_OP_DONE", + "101": "MEM_OP_WORKING", + "102": "MEM_OP_SETUP", + "103": "MEM_OP_RUNNING", + "104": "DIR_RD_DONE", + "105": "DIR_WR_DONE", + "106": "MEM_STATE_CHG", + "107": "MEM_ALRDY_IDLE", + "108": "LOAD_SPILLOVER", + "109": "MEM_GOT_PARAM", + "110": "CKSUM_MATCH", + "111": "SHUFFLE_STATE", + "112": "SHUFFLE_DONE", + "113": "FAIL_ADD_FETCH", + "114": "POP_FETCH_TBL", + "115": "RECONCILED_FT", + "116": "DATASET_FOUND", + "117": "DATASET_NOTFOUND", + "128": "IBRAM_WDOG", + "129": "DBRAM_WDOG", + "130": "SRAM_WDOG", + "131": "EXCEPTION_WDOG", + "132": "PROC_RST_WDOG", + "133": "DECON_AUTO_DIS", + "135": "HV_CURRENT_FAULT", + "136": "HV_STATE_CHANGE", + "137": "HV_STATE_TOF_ON", + "138": "HV_VOTING_FAILED", + "139": "HV_MMR_MISMATCH", + "140": "HV_BAD_STPT_MAX", + "141": "ANA_HK_FAULTLO", + "142": "ANA_HK_FAULTHI", + "143": "HV_OSCIL_FAULT", + "144": "BOOT2OPER", + "145": "POR_RST", + "146": "CMD_RST", + "147": "BOOT_HELLO", + "148": "OPER_HELLO", + "152": "MODE_CHANGE", + "153": "TOOK_DWELL_DATA", + "154": "DWELL_COMPLETE", + "155": "STIM_COMPLETE", + "159": "HAPPY_GOODBYE", + "160": "DUBIOUS_GOODBYE", + "161": "UPK_PROC_RST", + "162": "UPK_WDOG_RST", + "163": "UPK_UNKWN_RST", + "164": "UPK_BOOT_ERR", + "192": "SCI_STATE", + "193": "MEM_COLLAB_DONE", + "194": "CATALOG_MATCH", + "196": "SCI_DONE", + "197": "SCI_PEAK_CNT", + "198": "SCI_EVENT_ID", + "199": "SCI_CAT_FULL", + "200": "SCI_PROCESS_EVT", + "203": "SCI_TRANSMIT", + "204": "SCI_DATA", + "206": "SCI_SNDEVT_AID", + "207": "SCI_SPI_READ", + "208": "SCI_CLK_FAIL", + "209": "SCI_TASK_STATE", + "211": "SCI_PARSE_SIZE", + "212": "SCI_PARSE_HDR", + "213": "SCI_PARSE_END", + "214": "SCI_PARSE_EVT", + "215": "SCI_SND_ST_ERR", + "216": "SCI_SND_CH_ERR", + "217": "SCI_PWR_ERR", + "219": "ALLOC_EXHAUSTED", + "220": "SCI_AID_PREV_USE", + "221": "PROCESS_FIRST", + "224": "SEQ_STATE_CHANGE", + "225": "SEQ_RESUME", + "226": "SEQ_TERM_AT_IDLE", + "227": "SEQ_PAUSE_IDLE", + "228": "SEQ_PAUSE_STALE", + "229": "SEQ_BUF_VERIFIED", + "230": "SEQ_ABRT_UNCLEAN", + "232": "SEQ_ERROR_STOP", + "233": "SUBSEQ_CALL_SUB", + "234": "SEQ_BAD_STATE", + "235": "SEQ_ERR_NO_SEQ", + "236": "SEQ_RECURSE_CALL", + "237": "SEQ_BUF_NOT_LOAD", + "238": "SEQ_BAD_CKSUM", + "239": "SEQ_CMD_SUCC", + "240": "FAULT_EXCESS", + "241": "FAULT_RESP_STRT", + "242": "FAULT_INTERRUPT", + "243": "FAULT_FAIL", + "244": "FAULT_IGNORED", + "245": "MODE_RESP_STRT", + "246": "MODE_RESP_FAIL", + "247": "MODE_RESP_BUSY", + "248": "SUSPEND_DONE", + "249": "ALREADY_ERASED", + "255": "ENTRY_ID_INVAL" + }, + "eventMsgDictionary": { + "8": "DES postmortem log initialized", + "10": "DES task execution started", + "11": "DES INVALID DES SLICE, INVALID ID=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "12": "DES PERFMON ASKED TO ADD INVALID ENTRY, TASK ID=0x{p0:02x}{p1:02x}, SLICE=0x{p2:02x}{p3:02x}", + "13": "DES PERFMON SUSPICIOUS DURATION, TASK=0x{p0:02x}{p1:02x}, SLICE=0x{p2:02x}{p3:02x}", + "14": "DES TASK OVERRUN, START:END SLICE=0x{p0:02x}:{p1:02x}, TASK ID={p2:02x}", + "15": "DES task execution completed", + "17": "CMD success (apid=0x{p0:02x}{p1:02x}, {p2+2|opCodeLCDictionary})", + "18": "CMD received itf, byte length=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "19": "CMD rx itf and ccsds pkt good, vc=0x{p0:02x}{p1:02x}, byte length=0x{p2:02x}{p3:02x}", + "20": "CMD processed spacecraft time message", + "21": "CMD engine arm state expired", + "30": "TLM started tlm pkt tx", + "32": "CMD CRC MISMATCH (DISCARDING), P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "36": "CMD ERROR WITH CCSDS HDR IN RX PKT (DISCARDING), CCSDS1=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "37": "CMD OUT OF BOUNDS LENGTH, hdr field=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "38": "CMD UNKNOWN, ENG={p0+2|cmdEngineDictionary}, OPCODE=0x{p2:02x}{p3:02x}", + "39": "CMD RJCT UNARM, ENG={p0+1|cmdEngineDictionary}, {p1+1|idexModeDictionary}, {p2+2|opCodeDictionary}", + "40": "CMD RJCT ENGINE, ENG={p0+1|cmdEngineDictionary}, {p1+1|idexModeDictionary}, {p2+2|opCodeDictionary}", + "41": "CMD RJCT ARG#, ENG={p0+1|cmdEngineDictionary}, {p1+1|idexModeDictionary}, {p2+2|opCodeDictionary}", + "42": "CMD RJCT NULL, ENG={p0+1|cmdEngineDictionary}, {p1+1|idexModeDictionary}, {p2+2|opCodeDictionary}", + "43": "CMD RJCT RANGE, ENG={p0+1|cmdEngineDictionary}, {p1+1|idexModeDictionary}, {p2+2|opCodeDictionary}", + "44": "CMD RJCT MODE, ENG={p0+1|cmdEngineDictionary}, {p1+1|idexModeDictionary}, {p2+2|opCodeDictionary}", + "45": "CMD RJCT BUSY, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "46": "CMD REDUCED VALIDATION CRITERIA, CCSDS=0x{p0:02x}{p1:02x}, CRC=0x{p2:02x}{p3:02x}", + "48": "QBT state change: {p0+2|qbootStateDictionary}==>{p2+2|qbootStateDictionary}", + "49": "QBT quickboot halted", + "50": "QBT quickboot halted, but already idle", + "51": "QBT unexpected memory busy state while quickbooting", + "58": "QBT FT REPORTS OBJECT IN OFF DIE, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "59": "QBT loaded {p0+2|regionLCDictionary} from block 0x{p2:02x}{p3:02x}", + "60": "QBT LOADED {p0+2|regionDictionary} FROM OFF DIE, BLOCK=0x{p2:02x}{p3:02x}", + "61": "QBT OBJECT MISSING INIT! PARAM={p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "63": "MEM CKSUM MISMATCH FOUND DURING INIT, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "64": "MEM UNCORRECTABLE EDAC ERR IN SCI DATA, BLOCK=0x{p0:02x}{p1:02x} PAGE=0x{p2:02x}{p3:02x}", + "65": "MEM listed catalogs done, catalog count=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "66": "MEM ERROR CREATING OR SAVING CATALOG, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "67": "MEM SCI DATA FILLED RESERVED MEMORY, REST DROPPED, ErrStatReg=0x{p0:02x}{p1:02x}{p2:02x}", + "68": "MEM only 0x{p0:02x}{p1:02x} blocks reserved out of 0x{p2:02x}{p3:02x} requested", + "69": "MEM allowing copyto glash operation to complete before halting, param=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "70": "MEM AUTO-SAVE ERROR {p0+1|memOpDictionary} {p1+1|regionDictionary} PARAM=0x{p2:02x} CODE=0x{p3:02x}", + "71": "MEM FOUND RESET DURING CORRUPTION SENSITIVE MODE, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "72": "MEM FOUND RESET DURING CORRUPTION SENSITIVE MEM OPER, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "73": "MEM FLASH BLOCK ANALYSIS FAILURE, Block=0x{p0:02x}{p1:02x} ERROR=0x{p2:02x}{p3:02x}", + "74": "MEM BOTH MIRRORED BLOCKS FOUND BAD AT SAME TIME, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "75": "MEM cleanup found sci data, blocks empty=0x{p0:02x}{p1:02x}, blocks w/data=0x{p2:02x}{p3:02x}", + "76": "MEM QUEUED MEM CMD REJECTED, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "77": "MEM collaboration started, {p0+1|memCollabDictionary}, param=0x{p1:02x}{p2:02x}{p3:02x}", + "78": "MEM collaboration succeeded, {p0+1|memCollabDictionary}, param=0x{p1:02x}{p2:02x}{p3:02x}", + "79": "MEM MEMORY COLLABORATION FAILED, {p0+1|memCollabCAPSDictionary}, PARAM=0x{p1:02x}{p2:02x}{p3:02x}", + "80": "MEM REBUILD ERROR SUMMARY, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "81": "MEM CKSUM MISMATCH FOR OBJECT, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "82": "MEM REBUILT MISMATCHED FT ENTRY, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "83": "MEM FLASH DIE UNPOWERED, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "84": "MEM REJECT MODIFY NVFSW3, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "85": "MEM UNEXPECTED FLASH ERROR, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "86": "MEM OPERATION FAILED, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "87": "MEM FOUND BAD BLOCK, BLOCK=0x{p0:02x}{p1:02x} ERRTYPE={p2:02x} OLDSTATE={p3:02x}", + "88": "MEM FLASH UErr FOUND, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "89": "MEM FLASH CErr FOUND, PARAM=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "90": "MEM BAD CLEANUP STATE P={p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "91": "MEM FLASH DRIVER ERROR P={p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "92": "MEM OBJECT MISSING! REGION={p0+2|regionDictionary}, BLOCK={p2:02x}{p3:02x}", + "93": "MEM FOUND CORRUPTION-SENSITIVE MODE EXITED ABNORMALLY", + "94": "MEM FOUND CORRUPTION-SENSITIVE MEM OPER EXITED ABNORMALLY", + "95": "MEM SHUFFLE OPER ERROR, STATE=0x{p0:02x}{p1:02x} BLOCK=0x{p2:02x}{p3:02x}", + "96": "MEM operation queued, {p0+2|memOpLCDictionary} {p2+2|regionLCDictionary}", + "97": "MEM found {p0+2|regionLCDictionary} in block 0x{p2:02x}{p3:02x}", + "98": "MEM operation halted", + "99": "MEM memory operation started", + "100": "MEM {p0+1|memOpLCDictionary} {p1+1|regionLCDictionary} complete, duration=0x{p2:02x}{p3:02x}", + "101": "MEM operation working P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "102": "MEM operation setup P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "103": "MEM operation running P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "104": "MEM exec raw read, value=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "105": "MEM exec raw write, addr=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "106": "MEM state change: Transition {p0+2|memStateLCDictionary} <== {p2+2|memStateLCDictionary}", + "107": "MEM got halt but already idle", + "108": "MEM load command spillover, Offset8=0x{p0:02x} Len8={p1:02x}", + "109": "MEM got param cmd received and executed, param=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "110": "MEM checksum matched expected", + "111": "MEM shuffle state change: Transition 0x{p0:02x}{p1:02x} <== 0x{p2:02x}{p3:02x}", + "112": "MEM shuffle complete, param=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "113": "MEM FETCH TABLE FAILED TO ADD, param=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "114": "MEM popped fetch table entry, param=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "115": "MEM reconciled Flash Table, number entries fixed=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "116": "MEM Science dataset with AID 0x{p0:02x}{p1:02x}{p2:02x}{p3:02x} found", + "117": "MEM SCIENCE DATASET WITH AID 0x{p0:02x}{p1:02x}{p2:02x}{p3:02x} NOT FOUND", + "128": "AUT IBRAM EDAC MERR DETECTED (WDOG RESET LIKELY), P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "129": "AUT DBRAM EDAC MERR DETECTED (WDOG RESET LIKELY), P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "130": "AUT SRAM EDAC MERR DETECTED (WDOG RESET LIKELY), P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "131": "AUT CAUSING WDOG RESET DUE TO PROCESSOR EXCEPTION, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "132": "AUT CAUSING WDOG RESET DUE TO PROCESSOR-ONLY RESET, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "133": "AUT DECON ENABLED OUTSIDE MODE, DISABLING, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "135": "AUT HVPS DET CURRENT TOO HIGH FAULT I=0x{p0:02x}{p1:02x} Limit=0x{p2:02x}{p3:02x}", + "136": "AUT hvps state changed to {p0+4|hvStateDictionary}", + "137": "AUT TOF ADCS ON BUT HVPS CHANGED {p0+1|hvStateDictionary} TO {p1+1|hvStateDictionary}, ADC0=0x{p2:02x}, ADC1=0x{p3:02x}", + "138": "AUT HVPS TRIPLE-VOTING FAILED, {p0+4|hvMmrMismatchDictionary}", + "139": "AUT HVPS FPGA MMR FAILS LAST WRITTEN VALUE CHECK, P=0x{p0:02x}{p1:02x} {p2+2|hvMmrMismatchDictionary}", + "140": "AUT HVPS SETPOINT (0x{p0:02x}{p1:02x}) GREATER THAN MAX (0x{p2:02x}{p3:02x})", + "141": "AUT ANALOG HK(0x{p0:02x}{p1:02x}) 0x{p2:02x}{p3:02x} IS FAULT LO", + "142": "AUT ANALOG HK(0x{p0:02x}{p1:02x}) 0x{p2:02x}{p3:02x} IS FAULT HI", + "143": "AUT HVPS SENSOR OSCILLATOR FAULT, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "144": "UPK transition from {p0:02x} {p1+1|idexModeLCDictionary} to {p2:02x} {p3+1|idexModeLCDictionary}", + "145": "UPK power-on reset, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "146": "UPK commanded reset, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "147": "UPK boot fsw says hello, version={p0:02x}.{p1:02x}.{p2:02x}{p3:02x}", + "148": "UPK oper fsw says hello, version={p0:02x}.{p1:02x}.{p2:02x}{p3:02x}", + "152": "UPK mode changed from {p0+2|idexModeLCDictionary} to {p2+2|idexModeLCDictionary}", + "153": "UPK analog dwell measurement recorded", + "154": "UPK analog dwell completed", + "155": "UPK stim pulser operation completed, , PulserSel=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "159": "UPK csci change imminent to {p0+4|idexModeLCDictionary} - goodbye", + "160": "UPK RESET IMMINENT TO {p0+4|idexModeDictionary} - DUBIOUS GOODBYE!", + "161": "UPK PROCESSOR ONLY RESET, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "162": "UPK WATCHDOG RESET, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "163": "UPK UNKNOWN RESET, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "164": "UPK BOOT STATUS ERROR, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "192": "SCI state change: {p0+2|sciState16Dictionary} ==> {p2+2|sciState16Dictionary}", + "193": "SCI collab {p0+2|memCollabDictionary} is {p2+2|memCollabStatLCDictionary}", + "194": "SCI event ID 0x{p0:02x}{p1:02x} found matching category 0x{p2:02x}{p3:02x}", + "196": "SCI science activity completed: {p0+4|sciState16Dictionary}", + "197": "SCI process channel: {p0+2|sciChannel16Dictionary}, peak cnt (0x{p2:02x}{p3:02x})", + "198": "SCI event trigger (0x{p0:02x}{p1:02x}) id (0x{p2:02x}{p3:02x})", + "199": "SCI process cat full AID (0x{p0:02x}{p1:02x}) count (0x{p2:02x}{p3:02x})", + "200": "SCI process event id (0x{p0:02x}{p1:02x}) Category (0x{p2:02x}{p3:02x})", + "203": "SCI transmit: id (0x{p0:02x}{p1:02x}) cat (0x{p2:02x}) content (0x{p3:02x})", + "204": "SCI data: (0x{p0:02x}{p1:02x}{p2:02x}{p3:02x})", + "206": "SCI sending event with aid (0x{p0:02x}{p1:02x}) and evt num (0x{p2:02x}{p3:02x})", + "207": "SCI spi read: adc (0x{p0:02x}) addr (0x{p1:02x}) value (0x{p2:02x}{p3:02x})", + "208": "SCI CLOCK TRAINING FAILED: Size (0x{p0:02x}{p1:02x}) retry (0x{p2:02x}{p3:02x})", + "209": "SCI TASK STATE ERROR: {p0+2|sciState16Dictionary} ==> {p2+2|sciState16Dictionary}", + "211": "SCI PARSE SIZE ERROR: channel (0x{p0:02x}{p1:02x}) size (0x{p2:02x}{p3:02x})", + "212": "SCI PARSE HEADER SIZE ERROR: packetlen (0x{p0:02x}{p1:02x}) block size (0x{p2:02x}{p3:02x})", + "213": "SCI PARSE END ERROR: STATE {p0+2|sciState16Dictionary} root (0x{p2:02x}{p3:02x})", + "214": "SCI PARSE EVENT ERROR: page (0x{p0:02x}{p1:02x}) id (0x{p2:02x}{p3:02x})", + "215": "SCI SEND STATE ERROR: STATE (0x{p0:02x}{p1:02x}{p2:02x}{p3:02x})", + "216": "SCI SEND CHANNEL ERROR: CHANNEL (0x{p0:02x}{p1:02x}{p2:02x}{p3:02x})", + "217": "SCI ADC POWER ERROR: exp {p0+1|enaDis32Dictionary} act {p1+1|enaDis32Dictionary} chan {p2+2|sciChannel16Dictionary}", + "219": "SCI BDS ALLOCATION EXHAUSTED: REMAINING={p0:02x}", + "220": "SCI AID ALREADY PRESENT: AID=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "221": "SCI DATASET NEEDS PROCESSING BEFORE TRANSMIT", + "224": "SEQ engine has changed state, eng=seqEngineDictionary(0x{p0:02x}) was={p1+1|seqEngineStateDictionary} is={p2+1|seqEngineStateDictionary} 0x{p3:02x}", + "225": "SEQ got resume command when not paused, eng={p0+2|seqEngineDictionary} state={p2+2|seqEngineStateDictionary}", + "226": "SEQ got terminate command when already idle, eng={p0+2|seqEngineDictionary} state={p2+2|seqEngineStateDictionary}", + "227": "SEQ got pause command when already idle, eng={p0+2|seqEngineDictionary} state={p2+2|seqEngineStateDictionary}", + "228": "SEQ GOT PAUSE COMMAND WHEN STALE, eng={p0+2|seqEngineDictionary} state={p2+2|seqEngineStateDictionary}", + "229": "SEQ buffer successfully verified, buf={p0+4|seqBufferDictionary}", + "230": "SEQ ABORTED BUT CANNOT CLEANUP, ENG={p0+2|seqEngineDictionary} BUF={p2+2|seqBufferDictionary}", + "232": "SEQ ENGINE STOPPED DUE TO ERROR, ENG={p0+1|seqEngineDictionary} STATE={p1+1|seqEngineStateDictionary} STOPCODE={p2+1|seqEngStopCodeDictionary} 0x{p3:02x}", + "233": "SEQ ATTEMPTED TO CALL SUBSEQ WHILE ALREADY IN SUBSEQ, eng={p0+2|seqEngineDictionary} state={p2+2|seqEngineStateDictionary}", + "234": "SEQ STATE IS UNDEFINED, STOPPING AND GOING TO IDLE, ENG={p0+2|seqEngineDictionary} STATE={p2+2|seqEngineStateDictionary}", + "235": "SEQ ATTEMPTING WORK ON SEQUENCE THAT IS NOT LOADED, ENG={p0+2|seqEngineDictionary} STATE={p2+2|seqEngineStateDictionary}", + "236": "SEQ ATTEMPTED SUBSEQ CALL FROM ONE BUF TO SAME BUF, ENG={p0+2|seqEngineDictionary} STATE={p2+2|seqEngineStateDictionary}", + "237": "SEQ ATTEMPTED OPERATION ON UNLOADED BUF, BUF={p0+4|seqBufferDictionary}", + "238": "SEQ BUF'S CALCULATED CKSUM DOES NOT MATCH HDR, BUF={p0+4|seqBufferDictionary}", + "239": "SEQ success (len=0x{p0:02x}{p1:02x}, {p2+2|opCodeLCDictionary})", + "240": "SEQ EXCESS FAULT RESPONSE COUNT: FAULT={p0+1|faultSeqDictionary} STATE={p1+1|seqState3Dictionary} ENG={p2+1|seqEngineStateDictionary} BUFID=0x{p3:02x}", + "241": "SEQ Start Fault Resp: FAULT={p0+1|faultSeqDictionary} STATE={p1+1|seqState3Dictionary} ENG={p2+1|seqEngineStateDictionary} BUFID=0x{p3:02x}", + "242": "SEQ Higher Priority Fault: FAULT={p0+1|faultSeqDictionary} STATE={p1+1|seqState3Dictionary} ENG={p2+1|seqEngineStateDictionary} BUFID=0x{p3:02x}", + "243": "SEQ Fault Verify Fail: FAULT={p0+1|faultSeqDictionary} STATE={p1+1|seqState3Dictionary} ENG={p2+1|seqEngineStateDictionary} BUFID=0x{p3:02x}", + "244": "SEQ Fault Lower Priority Ignored: FAULT={p0+1|faultSeqDictionary} STATE={p1+1|seqState3Dictionary} ENG={p2+1|seqEngineStateDictionary} BUFID=0x{p3:02x}", + "245": "SEQ mode trans started: modetrans={p0+1|modeTransDictionary} state={p1+1|seqEngineStateDictionary} eng={p2+1|seqEngineDictionary} BUFID=0x{p3:02x}", + "246": "SEQ TRANS VERIFY FAIL: MODE={p0+1|modeTransDictionary} STATE={p1+1|seqEngineStateDictionary} ENG={p2+1|seqEngineDictionary} BUFID=0x{p3:02x}", + "247": "SEQ TRANS IGNORED NOT IDLE: MODE={p0+1|modeTransDictionary} STATE={p1+1|seqEngineStateDictionary} ENG={p2+1|seqEngineDictionary} BUFID=0x{p3:02x}", + "248": "SEQ suspend complete, eng={p0+2|seqEngineDictionary}, reason={p2+2|seqSuspendEndDictionary}", + "249": "SEQ attempted to erase seq but already empty, BUF={p0+4|seqBufferDictionary}", + "254": "??? INVALID FE, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}", + "255": "??? INVALID FF, P=0x{p0:02x}{p1:02x}{p2:02x}{p3:02x}" + }, + "busyStateTypeDictionary": { + "1": "BUSY", + "0": "OK" + }, + "idexModeDictionary": { + "0": "NONE", + "1": "BOOT", + "2": "SAFE", + "3": "IDLE", + "4": "DECON", + "5": "SCIENCE", + "6": "TRANSMIT" + }, + "idexModeLCDictionary": { + "0": "none", + "1": "boot", + "2": "safe", + "3": "idle", + "4": "decon", + "5": "science", + "6": "transmit" + }, + "chgModeInputType32Dictionary": { + "2": "SAFE", + "3": "IDLE", + "4": "DECON", + "5": "SCIENCE", + "6": "TRANSMIT" + }, + "ovrflwStateTypeDictionary": { + "1": "ERR", + "0": "OK" + }, + "regionDictionary": { + "0": "SCISTART", + "1": "NVFSW1", + "2": "NVFSW2", + "3": "NVFSW3", + "4": "NVPT", + "5": "SCICONT", + "6": "NVPERST", + "7": "NVFT", + "8": "NVPM", + "9": "NVSCIT", + "10": "SCIRSVP", + "11": "NVFETCHT", + "12": "NVSCS", + "13": "NVCATALOG", + "14": "REG14", + "15": "USER", + "16": "SCRATCH", + "17": "ACTFSW", + "18": "PT", + "19": "FT", + "20": "PERST", + "21": "SCIT", + "22": "SCS", + "24": "CATALOG", + "25": "FETCHT", + "51": "BLOCK", + "63": "NONE" + }, + "regionLCDictionary": { + "0": "scistart", + "1": "nvfsw1", + "2": "nvfsw2", + "3": "nvfsw3", + "4": "nvpt", + "5": "scicont", + "6": "nvperst", + "7": "nvft", + "8": "nvpm", + "9": "nvscit", + "10": "scirsvp", + "11": "nvfetcht", + "12": "nvscs", + "13": "nvcatalog", + "14": "reg14", + "15": "user", + "16": "scratch", + "17": "actfsw", + "18": "pt", + "19": "ft", + "20": "perst", + "21": "scit", + "22": "scs", + "24": "catalog", + "25": "fetcht", + "51": "block", + "63": "none" + }, + "qbootRegion2Dictionary": { + "0": "NONE", + "1": "NVFSW1", + "2": "NVFSW2", + "3": "NVFSW3" + }, + "qbootRegion8Dictionary": { + "0": "NONE", + "1": "NVFSW1", + "2": "NVFSW2", + "3": "NVFSW3", + "63": "NONE" + }, + "memRegionDumpDictionary": { + "1": "NVFSW1", + "2": "NVFSW2", + "3": "NVFSW3", + "4": "NVPT", + "6": "NVPERST", + "7": "NVFT", + "8": "NVPM", + "9": "NVSCIT", + "11": "NVFETCHT", + "12": "NVSCS", + "13": "NVCATALOG", + "16": "SCRATCH", + "17": "ACTFSW", + "18": "PT", + "19": "FT", + "20": "PERST", + "21": "SCIT", + "22": "SCS", + "24": "CATALOG", + "25": "FETCHT", + "51": "BLOCK" + }, + "memRegionCksumDictionary": { + "1": "NVFSW1", + "2": "NVFSW2", + "3": "NVFSW3", + "4": "NVPT", + "6": "NVPERST", + "7": "NVFT", + "9": "NVSCIT", + "11": "NVFETCHT", + "12": "NVSCS", + "13": "NVCATALOG", + "16": "SCRATCH", + "17": "ACTFSW", + "18": "PT", + "19": "FT", + "20": "PERST", + "21": "SCIT", + "22": "SCS", + "24": "CATALOG", + "25": "FETCHT" + }, + "memRegionCopyToDictionary": { + "1": "NVFSW1", + "2": "NVFSW2", + "4": "NVPT", + "6": "NVPERST", + "7": "NVFT", + "9": "NVSCIT", + "11": "NVFETCHT", + "12": "NVSCS", + "13": "NVCATALOG", + "17": "ACTFSW", + "18": "PT", + "19": "FT", + "20": "PERST", + "21": "SCIT", + "22": "SCS", + "24": "CATALOG", + "25": "FETCHT", + "51": "BLOCK" + }, + "memRegionCopyFromDictionary": { + "1": "NVFSW1", + "2": "NVFSW2", + "3": "NVFSW3", + "4": "NVPT", + "6": "NVPERST", + "7": "NVFT", + "8": "NVPM", + "9": "NVSCIT", + "11": "NVFETCHT", + "12": "NVSCS", + "13": "NVCATALOG", + "17": "ACTFSW", + "18": "PT", + "19": "FT", + "20": "PERST", + "21": "SCIT", + "22": "SCS", + "24": "CATALOG", + "25": "FETCHT", + "51": "BLOCK" + }, + "memRegionEraseDictionary": { + "8": "NVPM", + "16": "SCRATCH", + "17": "ACTFSW", + "24": "CATALOG", + "25": "FETCHT", + "51": "BLOCK" + }, + "memRegionRebuildDictionary": { + "51": "BLOCK" + }, + "memRegionShuffleDictionary": { + "51": "BLOCK" + }, + "memRegionSetHdrDictionary": { + "1": "NVFSW1", + "2": "NVFSW2", + "3": "NVFSW3", + "51": "BLOCK" + }, + "memOpDictionary": { + "0": "NONE", + "1": "DUMP", + "2": "CKSUM", + "4": "ERASE", + "8": "CPYTO", + "16": "CPYFROM", + "32": "REBUILD", + "64": "SHUFFLE" + }, + "memOpLCDictionary": { + "0": "none", + "1": "dump", + "2": "cksum", + "4": "erase", + "8": "cpyto", + "16": "cpyfrom", + "32": "rebuild", + "64": "shuffle" + }, + "memStateDictionary": { + "1": "NOTINIT", + "2": "IDLE", + "4": "DUMPSRAM", + "5": "CKSUMSRAM", + "6": "ERASESRAM", + "7": "CPY2SRAM", + "8": "CPYSRAM", + "9": "SETUPSCI", + "10": "CLEANSCI", + "11": "COPYFLASH", + "12": "COPY2FLASH", + "13": "ERASEFLASH", + "14": "DUMPFLASH", + "15": "CKSUMFLASH", + "16": "REBUILD", + "17": "SHUFFLE", + "18": "CLEANUP", + "19": "FETCHSCI", + "20": "ERASESCI" + }, + "memStateLCDictionary": { + "1": "notinit", + "2": "idle", + "4": "dumpsram", + "5": "cksumsram", + "6": "erasesram", + "7": "copy2sram", + "8": "cpysram", + "9": "setupsci", + "10": "cleansci", + "11": "copyflash", + "12": "copy2flash", + "13": "eraseflash", + "14": "dumpflash", + "15": "cksumflash", + "16": "rebuild", + "17": "shuffle", + "18": "cleanup", + "19": "fetchsci", + "20": "erasesci" + }, + "memCollabCAPSDictionary": { + "0": "SAVEPMLOG", + "1": "SCISETUP", + "2": "SCICLEANUP", + "3": "SCIFIND", + "4": "SCICOPY", + "5": "SCIFETCH", + "6": "GETCATALOG", + "7": "SAVECATALOG", + "8": "ERASESCI" + }, + "memCollabDictionary": { + "0": "savepmlog", + "1": "scisetup", + "2": "scicleanup", + "3": "scifind", + "4": "scicopy", + "5": "scifetch", + "6": "getcatalog", + "7": "savecatalog", + "8": "erasesci" + }, + "memCollabStatLCDictionary": { + "0": "busy", + "1": "success", + "2": "FAIL", + "3": "NEVER" + }, + "adpMetaControlDictionary": { + "1": "START", + "2": "END" + }, + "setAllocType32Dictionary": { + "0": "SET", + "1": "ADD" + }, + "deconSelDictionary": { + "0": "THERM0", + "1": "THERM1" + }, + "logSel8Dictionary": { + "0": "EVT", + "1": "PM", + "2": "CMD" + }, + "catalogSelDictionary": { + "0": "ALL", + "1": "HDR", + "2": "PAGE2", + "3": "PAGE3", + "4": "PAGE4", + "5": "PAGE5", + "6": "PAGE6", + "7": "PAGE7", + "8": "PAGE8", + "9": "PAGE9", + "10": "PAGE10", + "11": "PAGE11", + "12": "PAGE12", + "13": "PAGE13", + "14": "PAGE14", + "15": "PAGE15", + "16": "PAGE16", + "17": "PAGE17", + "18": "PAGE18", + "19": "PAGE19", + "20": "PAGE20", + "21": "PAGE21", + "22": "PAGE22", + "23": "PAGE23", + "24": "PAGE24", + "25": "PAGE25", + "26": "PAGE26", + "27": "PAGE27", + "28": "PAGE28", + "29": "PAGE29", + "30": "PAGE30", + "31": "PAGE31", + "32": "PAGE32", + "33": "PAGE33", + "34": "PAGE34", + "35": "PAGE35", + "36": "PAGE36", + "37": "PAGE37", + "38": "PAGE38", + "39": "PAGE39", + "40": "PAGE40", + "41": "PAGE41", + "42": "PAGE42", + "43": "PAGE43", + "44": "PAGE44", + "45": "PAGE45", + "46": "PAGE46", + "47": "PAGE47", + "48": "PAGE48", + "49": "PAGE49", + "50": "PAGE50", + "51": "PAGE51", + "52": "PAGE52", + "53": "PAGE53", + "54": "PAGE54", + "55": "PAGE55", + "56": "PAGE56", + "57": "PAGE57", + "58": "PAGE58", + "59": "PAGE59", + "60": "PAGE60", + "61": "PAGE61", + "62": "PAGE62", + "63": "PAGE63" + }, + "flagSel32Dictionary": { + "1": "PWRCYC", + "2": "PANIC", + "3": "BUSY", + "4": "PWRDOWN", + "5": "SAFE", + "6": "WDOG", + "7": "SPARE0", + "8": "SPARE1", + "9": "SPARE2", + "10": "MODEINTR", + "11": "OPERINTR", + "12": "BDSALLOC" + }, + "panicStateTypeDictionary": { + "1": "PANIC", + "0": "OK" + }, + "resetTypeDictionary": { + "0": "UNKWN", + "1": "POR", + "2": "WDOG", + "3": "CMD", + "4": "PROC", + "5": "BOOT" + }, + "irqOrdinalDictionary": { + "0": "WDOG", + "1": "BRAMINST", + "2": "BRAMDATA", + "3": "SRAM", + "4": "TIMER", + "5": "WISHBONE", + "6": "TIMEMSG", + "7": "PLL", + "8": "FLASHDONE", + "15": "NONE" + }, + "injectingErrorDictionary": { + "0": "OKAY", + "1": "BADBLOCK", + "2": "CERR", + "3": "BBCERR", + "4": "MERR", + "5": "BBMERR", + "6": "INVLD", + "7": "INVLD" + }, + "triggerModeDictionary": { + "0": "None", + "1": "THOLD", + "2": "PULSE1", + "3": "PULSE2" + }, + "triggerPolarityDictionary": { + "0": "ABOVE", + "1": "BELOW" + }, + "externTriggerDictionary": { + "0": "FALL", + "1": "RISE" + }, + "sciState16Dictionary": { + "0": "IDLE", + "1": "ACQCLEANUP", + "2": "ACQSETUP", + "3": "ACQ", + "4": "CAL", + "5": "CHILL", + "6": "CLKPATTERN", + "7": "CLK", + "8": "DUMPADCSPI", + "9": "MEMCOPY", + "10": "FETCHEVT", + "11": "MEMFIND", + "12": "MEMGETCAT", + "13": "MEMSAVCAT", + "14": "PARSE", + "15": "PROCESS", + "16": "SEND", + "17": "READSPI", + "18": "TRANSMIT", + "19": "ADCINIT" + }, + "sciChannel16Dictionary": { + "0": "HS_HIGH_GAIN", + "1": "HS_LOW_GAIN", + "2": "HS_MID_GAIN", + "3": "LS_TLR", + "4": "LS_THR", + "5": "LS_ION", + "6": "MAX_CHANNEL" + }, + "sciSndEvtSt16Dictionary": { + "0": "HEADER_RDY", + "1": "HEADER_SNT", + "2": "CHANNEL_COMP_ZERO", + "3": "CHANNEL_COMP_RDY", + "4": "CHANNEL_COMP_SNT", + "5": "CHANNEL_PACK_RDY", + "6": "CHANNEL_PACK_SNT", + "7": "CHANNEL_RDY", + "8": "CHANNEL_SNT", + "9": "EVT_SEND_DONE", + "10": "EVT_MAX_STATE" + }, + "sciChanOneHotDictionary": { + "0": "NONE", + "1": "EVTHDR", + "2": "TOFHG", + "4": "TOFLG", + "8": "TOFMG", + "16": "TLR", + "32": "THR", + "64": "ION", + "127": "ALL" + }, + "depthSelTypeDictionary": { + "0": "B10", + "1": "B12" + }, + "cmdEngineDictionary": { + "0": "AUTO", + "1": "OPER", + "2": "RT" + }, + "setSeqStateDictionary": { + "1": "PAUSE", + "2": "RESUME", + "3": "TERM" + }, + "seqEngineDictionary": { + "0": "AUTO", + "1": "OPER" + }, + "seqBufferDictionary": { + "0": "BUF0", + "1": "BUF1", + "2": "BUF2", + "3": "BUF3", + "4": "BUF4", + "5": "BUF5", + "6": "BUF6", + "7": "BUF7", + "8": "BUF8", + "9": "BUF9", + "10": "BUF10", + "11": "BUF11", + "12": "BUF12", + "13": "BUF13", + "14": "BUF14", + "15": "BUF15", + "16": "BUF16", + "17": "BUF17", + "18": "BUF18", + "19": "BUF19", + "20": "BUF20", + "21": "BUF21", + "22": "BUF22", + "23": "BUF23", + "24": "BUF24", + "25": "BUF25", + "26": "BUF26", + "27": "BUF27", + "28": "BUF28", + "29": "BUF29", + "30": "BUF30", + "31": "BUF31", + "32": "BUF32", + "33": "NONE" + }, + "seqEngineStateDictionary": { + "0": "IDLE", + "1": "ACTIV", + "2": "SUSPN", + "3": "PAUSE", + "4": "STALE" + }, + "seqEngStopCodeDictionary": { + "0": "NOM", + "1": "CMD", + "2": "VRFY", + "3": "RJCT", + "4": "STALE", + "5": "ZERO" + }, + "seqEngWaitTypeDictionary": { + "0": "None", + "1": "Abs", + "2": "Rel", + "3": "Cond" + }, + "seqSuspendEndDictionary": { + "0": "None", + "1": "Abs", + "2": "Rel", + "3": "Cond", + "4": "SciIdle", + "5": "Timeout" + }, + "seqState3Dictionary": { + "0": "Clear", + "1": "Start", + "2": "Done", + "3": "FAIL", + "4": "Intr" + }, + "cmdExecStatusDictionary": { + "0": "NONE", + "1": "OKAY", + "2": "BUSY", + "3": "LENGTH", + "4": "ID", + "5": "PROT", + "6": "RANGE", + "7": "MODE", + "8": "SRC", + "9": "ARGNUM", + "10": "NULL", + "11": "CRC", + "12": "OKAY2", + "13": "TIMEMSG", + "14": "CCSDS" + }, + "opCodeDictionary": { + "0": "NONE", + "4353": "NOOP", + "34561": "RST", + "34563": "SHUTDWN", + "36352": "SETAIDBIN", + "52416": "SETFLAG", + "52417": "CLRFLAG", + "52418": "LISTCATALOGS", + "52419": "CHGMODE", + "52420": "DUMPLOG", + "52421": "DWELL", + "52422": "CFGHTR", + "52423": "DSHTR", + "52424": "HALTQB", + "52425": "DUALCMD", + "52426": "CLRCMDST", + "52427": "LOADMEM", + "52428": "RAWWRT", + "52429": "RAWREAD", + "52430": "RAWCPY", + "52431": "SETPRM", + "52432": "GETPRM", + "52433": "WRFTBL", + "52434": "DUMPFTBL", + "52436": "SETMEMHDR", + "52437": "ERASEMEM", + "52438": "CKSUMMEM", + "52439": "DUMPMEM", + "52440": "COPYTOMEM", + "52441": "COPYFROMMEM", + "52445": "ACQUIRE", + "52446": "PROCESS_XMIT", + "52447": "WRSPI", + "52448": "ERASESCI", + "52449": "SETSCIPRM", + "52450": "INITSEQ", + "52451": "STRTSEQ", + "52452": "SETSEQST", + "52453": "SUSPABS", + "52454": "SUSPREL", + "52455": "CLSUB", + "52456": "VERSEQ", + "52457": "CLRFAULTCNT", + "52458": "SHUTDWNHV", + "52459": "CLRTLMST", + "52460": "CLRMEM", + "52461": "CLRSCI", + "52462": "REBUILD", + "52463": "SHUFFLE", + "52464": "DUMPADC", + "52465": "HALTSCI", + "52466": "HALTMEM", + "52467": "CLRUK", + "52468": "PTSEQ", + "52469": "STUFFSEQ", + "52470": "ERASESEQ", + "52480": "PWRADC", + "52481": "CFGADCTOF", + "52482": "CFGADCTAR", + "52483": "CFGSCIACQ", + "52484": "CFGTRG", + "52485": "INITADC", + "52486": "CALADC", + "52487": "TRAINADCCLK", + "52488": "SETHVPWR", + "52490": "DSHVOSC", + "52491": "SETHVSETPT", + "52492": "SETHVMAX", + "52493": "CLRATN", + "52494": "CLRSEQ", + "52495": "READSPI", + "52496": "FETCHONE", + "52506": "FETCH", + "52507": "TRANSMIT", + "52508": "SENDCATALOG", + "52509": "SUSPIDLESCI", + "52510": "SETALLOC", + "52511": "ADDTOFETCH", + "52512": "CFGSTIM", + "52513": "ENSTIM", + "52514": "HALTSTIM", + "48059": "DEPLOYDOOR", + "61166": "ENAHVOSC" + }, + "opCodeLCDictionary": { + "0": "none", + "4353": "noop", + "34561": "rst", + "34563": "shutdwn", + "36352": "setaidbin", + "52416": "setflag", + "52417": "clrflag", + "52418": "listcatalogs", + "52419": "chgmode", + "52420": "dumplog", + "52421": "dwell", + "52422": "cfghtr", + "52423": "dshtr", + "52424": "haltqb", + "52425": "dualcmd", + "52426": "clrcmdst", + "52427": "loadmem", + "52428": "rawwrt", + "52429": "rawread", + "52430": "rawcpy", + "52431": "setprm", + "52432": "getprm", + "52433": "wrftbl", + "52434": "dumpftbl", + "52436": "setmemhdr", + "52437": "erasemem", + "52438": "cksummem", + "52439": "dumpmem", + "52440": "copytomem", + "52441": "copyfrommem", + "52445": "acquire", + "52446": "process_xmit", + "52447": "wrspi", + "52448": "erasesci", + "52449": "setsciprm", + "52450": "initseq", + "52451": "strtseq", + "52452": "setseqst", + "52453": "suspabs", + "52454": "susprel", + "52455": "clsub", + "52456": "verseq", + "52457": "clrfaultcnt", + "52458": "shutdwnhv", + "52459": "clrtlmst", + "52460": "clrmem", + "52461": "clrsci", + "52462": "rebuild", + "52463": "shuffle", + "52464": "dumpadc", + "52465": "haltsci", + "52466": "haltmem", + "52467": "clruk", + "52468": "ptseq", + "52469": "stuffseq", + "52470": "eraseseq", + "52480": "pwradc", + "52481": "cfgadctof", + "52482": "cfgadctar", + "52483": "cfgsciacq", + "52484": "cfgtrg", + "52485": "initadc", + "52486": "caladc", + "52487": "trainadcclk", + "52488": "sethvpwr", + "52490": "dshvosc", + "52491": "sethvsetpt", + "52492": "sethvmax", + "52493": "clratn", + "52494": "clrseq", + "52495": "readspi", + "52496": "fetchone", + "52506": "fetch", + "52507": "transmit", + "52508": "sendcatalog", + "52509": "suspidlesci", + "52510": "setalloc", + "52511": "addtofetch", + "52512": "cfgstim", + "52513": "enstim", + "52514": "haltstim", + "48059": "deploydoor", + "61166": "enahvosc" + }, + "tlmApIdLsbDictionary": { + "128": "EVTMSG", + "129": "ALIVE", + "130": "EVTLOG", + "131": "PMLOG", + "132": "CMDLOG", + "133": "HWPKT", + "134": "SWPKT", + "135": "DUMP", + "136": "DWELL" + }, + "qbootStateDictionary": { + "0": "NOATTEMPT", + "1": "UNINIT", + "2": "STARTED", + "6": "STOPPED", + "7": "WAITING", + "8": "PENDING" + }, + "qbootStateLCDictionary": { + "0": "noattempt", + "1": "uninit", + "2": "started", + "6": "stopped", + "7": "waiting", + "8": "pending" + }, + "qbootReason8Dictionary": { + "0": "NO_STOP", + "1": "FT_FAIL", + "2": "PERST_FAIL", + "3": "PT_FAIL", + "4": "NVFSW_FAIL", + "5": "SAFE_ENTRY", + "6": "PANICKING", + "7": "REBOOT_RST", + "8": "MEM_FAIL", + "9": "BYCMD", + "11": "NO_TIME", + "12": "WDOGCNT", + "13": "NONE" + }, + "blockState8Dictionary": { + "0": "UNKWN", + "16": "BAD", + "32": "EMPTY", + "48": "SCISTRT", + "49": "NVFSW1", + "50": "NVFSW2", + "51": "NVFSW3", + "52": "NVPT", + "53": "SCICONT", + "54": "NVPERST", + "55": "NVFT", + "56": "NVPMLOG", + "57": "NVSCIT", + "58": "SCIRSVD", + "59": "NVFETCHT", + "60": "NVSCS", + "61": "NVCATALOG", + "62": "SPAREE", + "63": "USER" + }, + "blockState32Dictionary": { + "0": "UNKWN", + "16": "BAD", + "32": "EMPTY", + "48": "SCISTRT", + "49": "NVFSW1", + "50": "NVFSW2", + "51": "NVFSW3", + "52": "NVPT", + "53": "SCICONT", + "54": "NVPERST", + "55": "NVFT", + "56": "NVPMLOG", + "57": "NVSCIT", + "58": "SCIRSVD", + "59": "NVFETCHT", + "60": "NVSCS", + "61": "NVCATALOG", + "62": "REG14", + "63": "USER" + }, + "hvOscillatorDictionary": { + "1": "DETECT", + "0": "SENSOR" + }, + "hvPolarityDictionary": { + "1": "NEG", + "0": "POS" + }, + "hvOutputDictionary": { + "0": "SENSOR", + "1": "RJCTN", + "2": "TARGET", + "3": "DETECT" + }, + "hvOutputOnlyDSDictionary": { + "0": "SENSOR", + "3": "DETECT" + }, + "hvOutputOnlyTRDictionary": { + "1": "RJCTN", + "2": "TARGET" + }, + "hvStateDictionary": { + "0": "OFF", + "1": "STANDBY", + "2": "RAMPUP", + "3": "ACTIVE", + "4": "RAMPDOWN" + }, + "hvMmrMismatchDictionary": { + "0": "POW_ENA", + "1": "SEN_ENA", + "2": "DET_ENA", + "3": "POL_ENA", + "4": "DET_SPT", + "5": "SEN_SPT", + "6": "TAR_SPT", + "7": "REF_SPT", + "8": "DET_MAX", + "9": "SEN_MAX", + "10": "TAR_MAX", + "11": "REF_MAX" + }, + "faultDictionary": { + "1": "ANAHKFLAG", + "4": "HVPSOSCERR", + "8": "HVPSCURR", + "16": "ANAHKLIMIT", + "64": "SPARE", + "128": "DECON0", + "256": "DECON1", + "512": "REPOINT", + "1023": "ALLFAULTS" + }, + "faultSeqDictionary": { + "0": "ABORTED_SEQ_FAULT", + "1": "HV_SEN_OSC_FAULT", + "2": "HV_DET_CUR_FAULT", + "3": "ANA_HK_FAULT", + "4": "COMM_LOSS_FAULT", + "5": "SPARE_FAULT", + "6": "DECON0_FAULT", + "7": "DECON1_FAULT", + "8": "REPOINT_FAULT", + "9": "FPGA_CLK_FAULT", + "10": "SHUTDOWN_RESET" + }, + "disEnaDictionary": { + "1": "DIS", + "0": "ENA" + }, + "enaDisDictionary": { + "1": "ENA", + "0": "DIS" + }, + "enaDis3Dictionary": { + "7": "ENA", + "0": "DIS" + }, + "enaDis8Dictionary": { + "1": "ENA", + "0": "DIS" + }, + "enaDis32Dictionary": { + "1": "ENA", + "0": "DIS" + }, + "busyIdleDictionary": { + "1": "BUSY", + "0": "IDLE" + }, + "onOffDictionary": { + "1": "ON", + "0": "OFF" + }, + "onOff32Dictionary": { + "1": "ON", + "0": "OFF" + }, + "errOkayDictionary": { + "1": "ERR", + "0": "OK" + }, + "okayErrDictionary": { + "1": "OK", + "0": "ERR" + }, + "yesNoDictionary": { + "1": "YES", + "0": "NO" + }, + "noYesDictionary": { + "1": "NO", + "0": "YES" + }, + "inOutDictionary": { + "1": "IN", + "0": "OUT" + }, + "openClosedDictionary": { + "1": "OPEN", + "0": "CLOSED" + }, + "closedOpenDictionary": { + "1": "CLOSED", + "0": "OPEN" + }, + "highLowDictionary": { + "1": "HI", + "0": "LO" + }, + "redPriDictionary": { + "1": "RED", + "0": "PRI" + }, + "deconHtrStateDictionary": { + "0": "DIS", + "1": "THERM0", + "2": "THERM1", + "3": "BOTH" + }, + "boardIdDictionary": { + "1": "EM", + "4": "EMULATOR", + "8": "FM", + "9": "SP" + }, + "nandOwnDictionary": { + "0": "FSW", + "1": "FPGA" + }, + "hvpsBoardPwrDictionary": { + "0": "DIS", + "1": "ERR", + "2": "ERR", + "3": "ERR", + "4": "ERR", + "5": "ERR", + "6": "ERR", + "7": "ENA" + }, + "modeTransDictionary": { + "0": "BOOT_TO_IDLE", + "1": "IDLE_TO_DECON", + "2": "IDLE_TO_SCIENCE", + "3": "IDLE_TO_TRANSMIT", + "4": "DECON_TO_IDLE", + "5": "SCIENCE_TO_IDLE", + "6": "TRANSMIT_TO_IDLE", + "7": "ANY_TO_SAFE", + "8": "SAFE_TO_IDLE" + } +} diff --git a/imap_processing/idex/idex_l1a.py b/imap_processing/idex/idex_l1a.py index 7057365ef4..4d6b067906 100644 --- a/imap_processing/idex/idex_l1a.py +++ b/imap_processing/idex/idex_l1a.py @@ -14,6 +14,7 @@ l1a_data.write_l1a_cdf() """ +import json import logging from enum import IntEnum from pathlib import Path @@ -24,7 +25,9 @@ import xarray as xr from xarray import Dataset +from imap_processing import imap_module_directory from imap_processing.idex.decode import rice_decode +from imap_processing.idex.evt_msg_decode_utils import render_event_template from imap_processing.idex.idex_constants import IDEXAPID from imap_processing.idex.idex_l0 import decom_packets from imap_processing.idex.idex_utils import get_idex_attrs @@ -86,23 +89,19 @@ def __init__(self, packet_file: str | Path) -> None: if science_packets: logger.info("Processing IDEX L1A Science data.") self.data.append(self._create_science_dataset(science_packets)) - datasets_by_level = {"l1a": raw_datset_by_apid, "l1b": derived_datasets_by_apid} for level, dataset in datasets_by_level.items(): - if IDEXAPID.IDEX_EVT in dataset: - logger.info(f"Processing IDEX {level} Event Message data") + # Only produce l1a products for event messages. L1b will be processed in a + # another job. + if IDEXAPID.IDEX_EVT in dataset and level == "l1a": + logger.info("Processing IDEX L1A Event Message data") data = dataset[IDEXAPID.IDEX_EVT] - data.attrs = self.idex_attrs.get_global_attributes( - f"imap_idex_{level}_evt" - ) - data["epoch"] = calculate_idex_event_time( - data["shcoarse"].data, data["shfine"].data - ) - data["epoch"].attrs = epoch_attrs - self.data.append(data) + processed_data = self._create_evt_msg_data(data) + processed_data["epoch"].attrs = epoch_attrs + self.data.append(processed_data) if IDEXAPID.IDEX_CATLST in dataset: - logger.info(f"Processing IDEX {level} Catalog List Summary data.") + logger.info(f"Processing IDEX {level} CATLST data") data = dataset[IDEXAPID.IDEX_CATLST] data.attrs = self.idex_attrs.get_global_attributes( f"imap_idex_{level}_catlst" @@ -115,6 +114,110 @@ def __init__(self, packet_file: str | Path) -> None: logger.info("IDEX L1A data processing completed.") + def _create_evt_msg_data(self, data: xr.Dataset) -> xr.Dataset: + """ + Process IDEX message data into a more usable format. + + Parameters + ---------- + data : xarray.Dataset + The raw message data to process. + + Returns + ------- + xarray.Dataset + The processed message data. + """ + # Convert the time to epoch time in nanoseconds since J2000 in the TT timescale + epoch = calculate_idex_event_time(data["shcoarse"].data, data["shfine"].data) + # initialize dataset with time variables + l1a_msg_ds = xr.Dataset( + data_vars={ + "epoch": xr.DataArray(epoch, name="epoch", dims=["epoch"]), + "shfine": xr.DataArray( + data["shfine"].data, dims=["epoch"], attrs=data["shfine"].attrs + ), + "shcoarse": xr.DataArray( + data["shcoarse"].data, + dims=["epoch"], + attrs=data["shcoarse"].attrs, + ), + }, + attrs=self.idex_attrs.get_global_attributes("imap_idex_l1a_msg"), + ) + # Load the event decoding dictionaries + with open( + f"{imap_module_directory}/idex/idex_evt_msg_parsing_dictionaries.json" + ) as f: + msg_dicts = json.load(f) + + # restore integer keys since JSON stringifies them + msg_json_data = { + dict_name: {int(k): v for k, v in pairs.items()} + for dict_name, pairs in msg_dicts.items() + } + # Get the event message templates and log entry name dictionaries + # These are used to decode the raw event messages into human-readable formats + # during rendering. + event_description_templates = msg_json_data.get("eventMsgDictionary", {}) + log_entry_names = msg_json_data.get("logEntryIdDictionary", {}) + + # Get the event id - this will tell us what event happened. + # The following parameter values will tell us additional details about the event + # For example the event may be a science state change and the parameters will + # tell us what state it changed to (e.g. on or off). + event_ids = data["elid_evtpkt"].data + # Stack the parameter bytes into a single array of shape (num_events, 4) for + # easier access during rendering. + params_bytes = np.stack( + [ + data["el1par_evtpkt"].data, + data["el2par_evtpkt"].data, + data["el3par_evtpkt"].data, + data["el4par_evtpkt"].data, + ], + axis=-1, + ) + + # initialize an empty list for messages + messages = [] + for idx in range(len(event_ids)): + # Look up the string format using the event_id. + event_id = event_ids[idx] + current_desc_template = event_description_templates.get(event_id) + current_param_bytes = params_bytes[idx].tolist() + event_name = log_entry_names.get(event_id, f"EVENT_0x{event_id:02X}") + # Render the event message using the template if available. + if current_desc_template: + try: + message = render_event_template( + current_desc_template, current_param_bytes, msg_json_data + ) + except Exception as exc: + message = ( + f"{event_name} [template_render_error={exc}] " + f"params=" + f"({', '.join(f'0x{x:02X}' for x in current_param_bytes)})" + ) + else: + # If no template exists for an event ID, fall back to a message + # that still preserves the event name and raw parameter bytes. + phex = ", ".join(f"0x{x:02X}" for x in current_param_bytes) + message = f"{event_name} ({phex})" + + messages.append(message) + + l1a_msg_ds["messages"] = xr.DataArray( + messages, + name="messages", + dims=["epoch"], + attrs=self.idex_attrs.get_variable_attributes( + "messages", check_schema=False + ), + ) + l1a_msg_ds.attrs = self.idex_attrs.get_global_attributes("imap_idex_l1a_msg") + return l1a_msg_ds + def _create_science_dataset(self, science_decom_packet_list: list) -> xr.Dataset: """ Process IDEX science packets into an xarray Dataset. diff --git a/imap_processing/tests/idex/conftest.py b/imap_processing/tests/idex/conftest.py index 35bee8c542..96f5c98b85 100644 --- a/imap_processing/tests/idex/conftest.py +++ b/imap_processing/tests/idex/conftest.py @@ -13,14 +13,14 @@ TEST_DATA_PATH = imap_module_directory / "tests" / "idex" / "test_data" TEST_L0_FILE_SCI = TEST_DATA_PATH / "imap_idex_l0_raw_20231218_v001.pkts" -TEST_L0_FILE_EVT = TEST_DATA_PATH / "imap_idex_l0_raw_20250108_v001.pkts" # 1418 +TEST_L0_FILE_MSG = TEST_DATA_PATH / "imap_idex_l0_raw_20250108_v001.pkts" # 1418 TEST_L0_FILE_CATLST = TEST_DATA_PATH / "imap_idex_l0_raw_20241206_v001.pkts" # 1419 L1A_EXAMPLE_FILE = TEST_DATA_PATH / "idex_l1a_validation_file.h5" L1B_EXAMPLE_FILE = TEST_DATA_PATH / "imap_idex_l1b_sci_20231218_v001.h5" L2A_CDF = TEST_DATA_PATH / "imap_idex_l2a_sci-1week_20251017_v001.cdf" -L1B_EVT_CDF = TEST_DATA_PATH / "imap_idex_l1b_evt_20250108_v001.cdf" +L1B_MSG_CDF = TEST_DATA_PATH / "imap_idex_l1b_evt_20250108_v001.cdf" pytestmark = pytest.mark.external_test_data @@ -50,15 +50,15 @@ def decom_test_data_catlst() -> xr.Dataset: @pytest.fixture -def decom_test_data_evt() -> xr.Dataset: - """List of ``xarray`` datasets containing the raw and derived event log data. +def decom_test_data_msg() -> xr.Dataset: + """``xarray`` dataset containing the raw and derived event log data. Returns ------- - dataset : list[xarray.Dataset] - A list of ``xarray`` datasets containing the event log datasets. + dataset : xarray.Dataset + ``xarray`` dataset containing the event log data. """ - return PacketParser(TEST_L0_FILE_EVT).data + return PacketParser(TEST_L0_FILE_MSG).data[0] @pytest.fixture diff --git a/imap_processing/tests/idex/test_data/idex_event_messages.csv b/imap_processing/tests/idex/test_data/idex_event_messages.csv new file mode 100644 index 0000000000..07e30e1246 --- /dev/null +++ b/imap_processing/tests/idex/test_data/idex_event_messages.csv @@ -0,0 +1,29 @@ +timestamp,message +2025-01-08 20:40:25.222800 UTC,"MEM FLASH UErr FOUND, PARAM=0x000000fe" +2025-01-08 20:40:51.222740 UTC,"UPK oper fsw says hello, version=02.00.0000" +2025-01-08 20:40:56.222700 UTC,"SEQ success (len=0x0580, opCodeLCDictionary(dualcmd))" +2025-01-08 20:40:57.222700 UTC,"SEQ success (len=0x0580, opCodeLCDictionary(rawwrt))" +2025-01-08 20:41:00.222680 UTC,"SEQ engine has changed state, eng=seqEngineDictionary(0x00) was=seqEngineStateDictionary(ACTIV) is=seqEngineStateDictionary(IDLE) 0x00" +2025-01-08 20:48:39.220040 UTC,AUT hvps state changed to hvStateDictionary(STANDBY) +2025-01-08 20:50:27.219540 UTC,AUT hvps state changed to hvStateDictionary(ACTIVE) +2025-01-08 20:56:32.218180 UTC,"SEQ success (len=0x0580, opCodeLCDictionary(noop))" +2025-01-08 20:56:33.218160 UTC,"SEQ engine has changed state, eng=seqEngineDictionary(0x00) was=seqEngineStateDictionary(ACTIV) is=seqEngineStateDictionary(IDLE) 0x00" +2025-01-08 20:58:15.217920 UTC,SCI state change: sciState16Dictionary(IDLE) ==> sciState16Dictionary(ACQSETUP) +2025-01-08 20:58:20.217900 UTC,SCI state change: sciState16Dictionary(ACQSETUP) ==> sciState16Dictionary(ACQ) +2025-01-08 20:59:15.217800 UTC,SCI state change: sciState16Dictionary(ACQ) ==> sciState16Dictionary(CHILL) +2025-01-08 20:59:20.217800 UTC,SCI state change: sciState16Dictionary(CHILL) ==> sciState16Dictionary(ACQCLEANUP) +2025-01-08 20:59:21.217780 UTC,"MEM cleanup found sci data, blocks empty=0x0000, blocks w/data=0x0001" +2025-01-08 20:59:26.217780 UTC,SCI science activity completed: sciState16Dictionary(ACQ) +2025-01-08 20:59:27.217760 UTC,SCI state change: sciState16Dictionary(ACQCLEANUP) ==> sciState16Dictionary(IDLE) +2025-01-08 21:00:12.217700 UTC,"SEQ success (len=0x0580, opCodeLCDictionary(haltstim))" +2025-01-08 21:00:14.217680 UTC,"SEQ success (len=0x0580, opCodeLCDictionary(haltsci))" +2025-01-08 21:00:15.217680 UTC,"SEQ engine has changed state, eng=seqEngineDictionary(0x00) was=seqEngineStateDictionary(ACTIV) is=seqEngineStateDictionary(IDLE) 0x00" +2025-01-08 21:02:48.217480 UTC,AUT hvps state changed to hvStateDictionary(STANDBY) +2025-01-08 21:04:42.217340 UTC,AUT hvps state changed to hvStateDictionary(OFF) +2025-01-08 21:05:30.217280 UTC,"SEQ success (len=0x0580, opCodeLCDictionary(dualcmd))" +2025-01-08 21:05:33.217280 UTC,"SEQ success (len=0x0580, opCodeLCDictionary(rawwrt))" +2025-01-08 21:05:36.217280 UTC,"SEQ engine has changed state, eng=seqEngineDictionary(0x00) was=seqEngineStateDictionary(ACTIV) is=seqEngineStateDictionary(IDLE) 0x00" +2025-01-08 21:06:36.217180 UTC,"SEQ success (len=0x0580, opCodeLCDictionary(dshtr))" +2025-01-08 21:06:38.217180 UTC,"SEQ success (len=0x0580, opCodeLCDictionary(dualcmd))" +2025-01-08 21:06:39.217180 UTC,"SEQ success (len=0x0580, opCodeLCDictionary(rawwrt))" +2025-01-08 21:06:42.217180 UTC,"SEQ engine has changed state, eng=seqEngineDictionary(0x00) was=seqEngineStateDictionary(ACTIV) is=seqEngineStateDictionary(IDLE) 0x00" diff --git a/imap_processing/tests/idex/test_idex_l0.py b/imap_processing/tests/idex/test_idex_l0.py index ea4ebf12a7..425168c74c 100644 --- a/imap_processing/tests/idex/test_idex_l0.py +++ b/imap_processing/tests/idex/test_idex_l0.py @@ -61,13 +61,12 @@ def test_catlst_event_num(decom_test_data_catlst: list[xr.Dataset]): assert len(ds["epoch"]) == 1 -def test_evt_event_num(decom_test_data_evt: list[xr.Dataset]): +def test_msg_event_num(decom_test_data_msg: xr.Dataset): """Verify that a sample of the data is correct. Parameters ---------- - decom_test_data_evt : list[xarray.Dataset] - The raw and derived (l1a and l1b) datasets to test with. + decom_test_data_msg : xarray.Dataset + Event message data. """ - for ds in decom_test_data_evt: - assert len(ds["epoch"]) == 28 + assert len(decom_test_data_msg["epoch"]) == 28 diff --git a/imap_processing/tests/idex/test_idex_l1a.py b/imap_processing/tests/idex/test_idex_l1a.py index 2ef70be8e1..7c038c10cb 100644 --- a/imap_processing/tests/idex/test_idex_l1a.py +++ b/imap_processing/tests/idex/test_idex_l1a.py @@ -4,6 +4,7 @@ from unittest import mock import numpy as np +import pandas as pd import pytest import xarray as xr from cdflib.xarray.xarray_to_cdf import ISTPError @@ -16,6 +17,8 @@ from imap_processing.tests.idex.conftest import TEST_L0_FILE_SCI from imap_processing.utils import packet_generator +TEST_DATA_DIR = f"{imap_module_directory}/tests/idex/test_data" + def test_idex_cdf_file(decom_test_data_sci: xr.Dataset): """Verify the CDF file can be created with no errors. @@ -191,10 +194,9 @@ def test_compressed_packet(): """ Test compressed data decompression against known non-compressed data. """ - test_data_dir = f"{imap_module_directory}/tests/idex/test_data" - compressed = Path(f"{test_data_dir}/compressed_2023_102_14_24_55.pkts") - non_compressed = Path(f"{test_data_dir}/non_compressed_2023_102_14_22_26.pkts") + compressed = Path(f"{TEST_DATA_DIR}/compressed_2023_102_14_24_55.pkts") + non_compressed = Path(f"{TEST_DATA_DIR}/non_compressed_2023_102_14_22_26.pkts") decompressed = PacketParser(compressed).data[0] expected = PacketParser(non_compressed).data[0] @@ -352,25 +354,29 @@ def test_catlst_dataset(decom_test_data_catlst: list[xr.Dataset]): assert filename_l1b.name == "imap_idex_l1b_catlst_20241206_v999.cdf" -def test_evt_dataset(decom_test_data_evt: list[xr.Dataset]): +def test_msg_dataset(decom_test_data_msg: xr.Dataset): """Verify that the dataset contains what we expect and can be written to a cdf. Parameters ---------- - decom_test_data_evt : list[xarray.Dataset] - The raw and derived (l1a and l1b) datasets to test with. + decom_test_data_msg : xarray.Dataset + The raw l1a dataset to test with. """ - for ds in decom_test_data_evt: - assert "shcoarse" in ds - assert "shfine" in ds - # Assert epoch is calculated using fine grained clock ticks - expected_epoch = met_to_ttj2000ns(ds["shcoarse"] + ds["shfine"] * 20e-6) - np.testing.assert_array_equal(ds.epoch, expected_epoch) - assert decom_test_data_evt[0]["elid_evtpkt"][9] == 192 - assert decom_test_data_evt[1]["elid_evtpkt"][9] == "SCI_STE" + assert "shcoarse" in decom_test_data_msg + assert "shfine" in decom_test_data_msg + # Assert epoch is calculated using fine grained clock ticks + expected_epoch = met_to_ttj2000ns( + decom_test_data_msg["shcoarse"] + decom_test_data_msg["shfine"] * 20e-6 + ) + np.testing.assert_array_equal(decom_test_data_msg.epoch, expected_epoch) # Assert that the dataset can be written to a CDF file - filename_l1a = write_cdf(decom_test_data_evt[0]) - assert filename_l1a.name == "imap_idex_l1a_evt_20250108_v999.cdf" + filename_l1a = write_cdf(decom_test_data_msg) + assert filename_l1a.name == "imap_idex_l1a_msg_20250108_v999.cdf" + + # Validate the messages with the IDEX team example data + example_data = pd.read_csv( + f"{TEST_DATA_DIR}/idex_event_messages.csv", skiprows=1, header=None + ) - filename_l1b = write_cdf(decom_test_data_evt[1]) - assert filename_l1b.name == "imap_idex_l1b_evt_20250108_v999.cdf" + messages = example_data.iloc[:, 1].tolist() + np.testing.assert_array_equal(decom_test_data_msg["messages"].data, messages) diff --git a/imap_processing/tests/idex/test_idex_l2b.py b/imap_processing/tests/idex/test_idex_l2b.py index 0d4692e042..3a9605aa02 100644 --- a/imap_processing/tests/idex/test_idex_l2b.py +++ b/imap_processing/tests/idex/test_idex_l2b.py @@ -23,10 +23,9 @@ compute_counts_by_charge_and_mass, compute_rates_by_charge_and_mass, get_science_acquisition_on_percentage, - get_science_acquisition_timestamps, idex_l2b, ) -from imap_processing.tests.idex.conftest import L1B_EVT_CDF +from imap_processing.tests.idex.conftest import L1B_MSG_CDF @pytest.fixture @@ -38,17 +37,17 @@ def l2b_and_l2c_datasets(l2a_dataset: xr.Dataset) -> list[xr.Dataset]: datasets : list[xr.Dataset] A list of ``xarray`` datasets containing the test data for L2B and L2C. """ - l1b_evt_dataset = load_cdf(L1B_EVT_CDF) - l1b_evt_dataset2 = ( - l1b_evt_dataset.copy() + l1b_msg_dataset = load_cdf(L1B_MSG_CDF) + l1b_msg_dataset2 = ( + l1b_msg_dataset.copy() ) # Add a second dataset with different epoch values for testing l2a_dataset2 = ( l2a_dataset.copy() ) # Add a second dataset with different epoch values for testing - l1b_evt_dataset2["epoch"] = l1b_evt_dataset2["epoch"] + NANOSECONDS_IN_DAY + l1b_msg_dataset2["epoch"] = l1b_msg_dataset2["epoch"] + NANOSECONDS_IN_DAY l2a_dataset2["epoch"] = l2a_dataset2["epoch"] + NANOSECONDS_IN_DAY datasets = idex_l2b( - [l2a_dataset, l2a_dataset2], [l1b_evt_dataset, l1b_evt_dataset2] + [l2a_dataset, l2a_dataset2], [l1b_msg_dataset, l1b_msg_dataset2] ) return datasets @@ -177,49 +176,51 @@ def test_bin_spin_phases_warning(caplog): ) in caplog.text -def test_science_acquisition_times(decom_test_data_evt: list[xr.Dataset]): - """Tests that the expected science acquisition times and messages are present. - - Parameters - ---------- - decom_test_data_evt : list[xr.Dataset] - A ``xarray`` dataset containing the test data - """ - logs, times, vals = get_science_acquisition_timestamps(decom_test_data_evt[1]) - # For this example event message dataset we expect science acquisition events. - assert len(logs) == 2 - assert len(times) == 2 - assert len(vals) == 2 - # The first event message is the start of the science acquisition. - assert logs[0] == "SCI state change: ACQSETUP to ACQ" - # The second event message is the end of the science acquisition. - assert logs[1] == "SCI state change: ACQ to CHILL" - - # assert the values are correct - np.testing.assert_array_equal(vals, [1, 0]) - - -def test_get_science_acquisition_on_percentage(decom_test_data_evt: list[xr.Dataset]): - """Test the function that calculates the percentage of uptime.""" - _, evt_time, evt_event = get_science_acquisition_timestamps(decom_test_data_evt[1]) - on_percentages = get_science_acquisition_on_percentage(evt_time, evt_event) - # We expect 1 DOY and ~87% uptime for the science acquisition. - assert len(on_percentages) == 1 - # The DOY should be 8 for this test dataset. - assert on_percentages[8] < 1 - - evt_ds = decom_test_data_evt[1].copy() - evt_ds_shifted = evt_ds.copy() - evt_ds_shifted["epoch"] = evt_ds["epoch"] + NANOSECONDS_IN_DAY - combined_ds = xr.concat([evt_ds, evt_ds_shifted], dim="epoch") - # expect a second DOY. - _, evt_time, evt_event = get_science_acquisition_timestamps(combined_ds) - on_percentages = get_science_acquisition_on_percentage(evt_time, evt_event) - # We expect 2 DOYs - assert len(on_percentages) == 2 - # The uptime should be less than 1% for both - assert on_percentages[8] < 1 - assert on_percentages[9] < 1 # The uptime should be less than 1% +# TODO uncomment tests below when the event message l1b products are ready +# def test_science_acquisition_times(decom_test_data_msg: xr.Dataset): +# """Tests that the expected science acquisition times and messages are present. +# +# Parameters +# ---------- +# decom_test_data_msg : xr.Dataset +# A ``xarray`` dataset containing the test data +# """ +# logs, times, vals = get_science_acquisition_timestamps(decom_test_data_msg) +# # For this example event message dataset we expect science acquisition events. +# assert len(logs) == 2 +# assert len(times) == 2 +# assert len(vals) == 2 +# # The first event message is the start of the science acquisition. +# assert logs[0] == "SCI state change: ACQSETUP to ACQ" +# # The second event message is the end of the science acquisition. +# assert logs[1] == "SCI state change: ACQ to CHILL" +# +# # assert the values are correct +# np.testing.assert_array_equal(vals, [1, 0]) +# +# +# def test_get_science_acquisition_on_percentage(decom_test_data_msg: xr.Dataset): +# """Test the function that calculates the percentage of uptime.""" +# _, msg_time, msg_event = get_science_acquisition_timestamps(decom_test_data_msg) +# on_percentages = get_science_acquisition_on_percentage(msg_time, msg_event) +# # We expect 1 DOY and ~87% uptime for the science acquisition. +# assert len(on_percentages) == 1 +# # The DOY should be 8 for this test dataset. +# assert on_percentages[8] < 1 +# +# msg_ds = decom_test_data_msg[1].copy() +# msg_ds_shifted = msg_ds.copy() +# msg_ds_shifted["epoch"] = msg_ds["epoch"] + NANOSECONDS_IN_DAY +# combined_ds = xr.concat([msg_ds, msg_ds_shifted], dim="epoch") +# # expect a second DOY. +# _, msg_time, msg_event = get_science_acquisition_timestamps(combined_ds) +# on_percentages = get_science_acquisition_on_percentage(msg_time, msg_event) +# # We expect 2 DOYs +# assert len(on_percentages) == 2 +# # The uptime should be less than 1% for both +# assert on_percentages[8] < 1 +# assert on_percentages[9] < 1 # The uptime should be less than 1% +# def test_get_science_acquisition_on_percentage_no_acquisition(caplog):