From 57edfd68a2f9d1da46c3d4a1752d616589940153 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Fri, 29 Sep 2023 10:22:50 -0600 Subject: [PATCH 01/21] adding ialirt --- .../tests/plugins => ialirt}/__init__.py | 0 .../ialirt/l0/IALiRT Raw Packet Telemetry.txt | 33 ++ imap_processing/ialirt/l0/__init__.py | 0 imap_processing/ialirt/l0/decom_ialirt.py | 54 +++ imap_processing/ialirt/l0/ialirt.xml | 404 ++++++++++++++++++ .../ialirt/packet_definitions/__init__.py | 0 imap_processing/ialirt/tests/__init__.py | 0 imap_processing/ialirt/tests/unit/__init__.py | 0 8 files changed, 491 insertions(+) rename imap_processing/{ultra/tests/plugins => ialirt}/__init__.py (100%) create mode 100644 imap_processing/ialirt/l0/IALiRT Raw Packet Telemetry.txt create mode 100644 imap_processing/ialirt/l0/__init__.py create mode 100644 imap_processing/ialirt/l0/decom_ialirt.py create mode 100644 imap_processing/ialirt/l0/ialirt.xml create mode 100644 imap_processing/ialirt/packet_definitions/__init__.py create mode 100644 imap_processing/ialirt/tests/__init__.py create mode 100644 imap_processing/ialirt/tests/unit/__init__.py diff --git a/imap_processing/ultra/tests/plugins/__init__.py b/imap_processing/ialirt/__init__.py similarity index 100% rename from imap_processing/ultra/tests/plugins/__init__.py rename to imap_processing/ialirt/__init__.py diff --git a/imap_processing/ialirt/l0/IALiRT Raw Packet Telemetry.txt b/imap_processing/ialirt/l0/IALiRT Raw Packet Telemetry.txt new file mode 100644 index 000000000..9030e6aa5 --- /dev/null +++ b/imap_processing/ialirt/l0/IALiRT Raw Packet Telemetry.txt @@ -0,0 +1,33 @@ +#;0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30;31;32;33;34;35;36;37;38;39;40;41;42;43;44;45;46;47;48;49;50;51;52;53;54;55;56;57;58;59;60;61;62;63;64;65;66;67;68;69;70;71;72;73;74;75;76;77;78;79;80;81;82;83;84;85;86;87;88;89;90;91;92;93;94;95;96;97;98;99;100;101;102;103;104;105;106;107;108;109;110;111;112;113;114;115;116;117;118;119;120;121;122;123;124;125;126;127;128;129;130;131;132;133;134;135;136;137;138;139;140;141;142;143;144;145;146;147;148;149;150;151;152;153;154;155;156;157;158;159;160;161;162;163;164;165;166;167;168;169;170;171;172;173;174;175;176;177;178;179;180;181;182 +01;09;DE;C4;EB;00;B0;00;04;EA;78;F9;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +02;09;DE;C4;EC;00;B0;00;04;EA;79;F9;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +03;09;DE;C4;ED;00;B0;00;04;EA;7A;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +04;09;DE;C4;EE;00;B0;00;04;EA;7B;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +05;09;DE;C4;EF;00;B0;00;04;EA;7C;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +06;09;DE;C4;F0;00;B0;00;04;EA;7D;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +07;09;DE;C4;F1;00;B0;00;04;EA;7E;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +08;09;DE;C4;F2;00;B0;00;04;EA;7F;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +09;09;DE;C4;F3;00;B0;00;04;EA;80;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +10;09;DE;C4;F4;00;B0;00;04;EA;81;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +11;09;DE;C4;F5;00;B0;00;04;EA;82;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +12;09;DE;C4;F6;00;B0;00;04;EA;83;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +13;09;DE;C4;F7;00;B0;00;04;EA;84;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +14;09;DE;C4;F8;00;B0;00;04;EA;85;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +15;09;DE;C4;F9;00;B0;00;04;EA;86;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +16;09;DE;C4;DA;00;B0;00;04;EA;67;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +17;09;DE;C4;DB;00;B0;00;04;EA;68;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +18;09;DE;C4;DC;00;B0;00;04;EA;69;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +19;09;DE;C4;DD;00;B0;00;04;EA;6A;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +20;09;DE;C4;DE;00;B0;00;04;EA;6B;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +21;09;DE;C4;DF;00;B0;00;04;EA;6C;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +22;09;DE;C4;E0;00;B0;00;04;EA;6D;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +23;09;DE;C4;E1;00;B0;00;04;EA;6E;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +24;09;DE;C4;E2;00;B0;00;04;EA;6F;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +25;09;DE;C4;E3;00;B0;00;04;EA;70;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +26;09;DE;C4;E4;00;B0;00;04;EA;71;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +27;09;DE;C4;E5;00;B0;00;04;EA;72;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +28;09;DE;C4;E6;00;B0;00;04;EA;73;F7;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +29;09;DE;C4;E7;00;B0;00;04;EA;74;F8;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +30;09;DE;C4;E8;00;B0;00;04;EA;75;F8;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +31;09;DE;C4;E9;00;B0;00;04;EA;76;F9;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 +32;09;DE;C4;EA;00;B0;00;04;EA;77;F9;40;00;00;00;00;00;B7;1B;00;00;00;00;00;00;38;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00 diff --git a/imap_processing/ialirt/l0/__init__.py b/imap_processing/ialirt/l0/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py new file mode 100644 index 000000000..9aa284932 --- /dev/null +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -0,0 +1,54 @@ +from space_packet_parser import parser, xtcedef +import bitstring + +def decom_packets(packet_file, xtce_packet_definition): + """Unpack data packet. In this function, we unpack and return data + as it is. Data modification will not be done at this step. + + Parameters + ---------- + packet_file : str + Path to data packet path with filename + xtce_packet_definition : str + Path to XTCE file with filename + + Returns + ------- + List + List of all the unpacked data + """ + + packet_definition = xtcedef.XtcePacketDefinition(xtce_packet_definition) + packet_parser = parser.PacketParser(packet_definition) + + packets = [] + + with open(packet_file, "r") as file: + for line in file: + if not line.startswith("#"): + + hex_values = line.strip().split(";") # Split the line by semicolons + + binary_values = "" + for h in hex_values: + # Convert hex to integer + # 16 is the base of hexadecimal + int_value = int(h, 16) + + # Convert integer to binary and remove the '0b' prefix + bin_value = bin(int_value)[2:] + + # Make sure each binary string is 8 bits long + bin_value_padded = bin_value.zfill(8) + + # Append the padded binary string to the final string + binary_values += bin_value_padded + + packet = next(packet_parser.generator(bitstring.ConstBitStream(bin=binary_values)), None) + print('hi') + #if packet: + # packets.append(packet) + + return packets + +decom_packets("IALiRT Raw Packet Telemetry.txt", "ialirt.xml") diff --git a/imap_processing/ialirt/l0/ialirt.xml b/imap_processing/ialirt/l0/ialirt.xml new file mode 100644 index 000000000..1d141dbeb --- /dev/null +++ b/imap_processing/ialirt/l0/ialirt.xml @@ -0,0 +1,404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 176 + + + + + + + + 96 + + + + + + + + 160 + + + + + + + + 432 + + + + + + + + 432 + + + + + + + + 96 + + + + + + + + + + CCSDS Packet Version Number (always 0) + + + CCSDS Packet Type Indicator (0=telemetry) + + + CCSDS Packet Secondary Header Flag (always 1) + + + CCSDS Packet Application Process ID + + + CCSDS Packet Grouping Flags (3=not part of group) + + + CCSDS Packet Sequence Count (increments with each new packet) + + + CCSDS Packet Length (number of bytes after Packet length minus 1) + + + + CCSDS Packet Time Stamp (coarse time) + + + Spin Start Seconds + + + Spin Start Subseconds + + + Spin Duration + + + Spin Number + + + Spin DataTime + + + Spin Period + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + Spin Phase + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/imap_processing/ialirt/packet_definitions/__init__.py b/imap_processing/ialirt/packet_definitions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/imap_processing/ialirt/tests/__init__.py b/imap_processing/ialirt/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/imap_processing/ialirt/tests/unit/__init__.py b/imap_processing/ialirt/tests/unit/__init__.py new file mode 100644 index 000000000..e69de29bb From 1676ba519a44512c23ce8a7788aeedd71e1bfa9d Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Fri, 29 Sep 2023 14:01:04 -0600 Subject: [PATCH 02/21] updates --- imap_processing/ialirt/l0/decom_ialirt.py | 14 +- imap_processing/ialirt/l0/ialirt.xml | 299 +++++++++++++--------- 2 files changed, 180 insertions(+), 133 deletions(-) diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py index 9aa284932..c8360c7a9 100644 --- a/imap_processing/ialirt/l0/decom_ialirt.py +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -26,8 +26,9 @@ def decom_packets(packet_file, xtce_packet_definition): with open(packet_file, "r") as file: for line in file: if not line.startswith("#"): - - hex_values = line.strip().split(";") # Split the line by semicolons + # Split the line by semicolons + # Discard the first value since it is only a counter + hex_values = line.strip().split(";")[1::] binary_values = "" for h in hex_values: @@ -44,10 +45,11 @@ def decom_packets(packet_file, xtce_packet_definition): # Append the padded binary string to the final string binary_values += bin_value_padded - packet = next(packet_parser.generator(bitstring.ConstBitStream(bin=binary_values)), None) - print('hi') - #if packet: - # packets.append(packet) + packet_generator = packet_parser.generator(bitstring.ConstBitStream(bin=binary_values)) + + for packet in packet_generator: + print('hi') + packets.append(packet) return packets diff --git a/imap_processing/ialirt/l0/ialirt.xml b/imap_processing/ialirt/l0/ialirt.xml index 1d141dbeb..9039859a3 100644 --- a/imap_processing/ialirt/l0/ialirt.xml +++ b/imap_processing/ialirt/l0/ialirt.xml @@ -164,54 +164,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - 176 - - - + + + + 176 + + + - - - - 96 - - - + + + + 96 + + + - - - - 160 - - - + + + + 160 + + + - - - - 432 - - - + + + + 432 + + + - - - - 432 - - - + + + + 288 + + + - - - - 96 - - - + + + + 96 + + + - CCSDS Packet Time Stamp (coarse time) + CCSDS Packet SCLK (sec) - Spin Start Seconds + CCSDS Packet SCLK (subsec) + - Spin Start Subseconds + SBC Physical ID + + + Spare 1 - Spin Duration + Autonomy Rule Fire Count - Spin Number + First Autonomy Fault Rule Fired - Spin DataTime + Last Autonomy Fault Rule Fired - - Spin Period + + SWAPI Status - - Spin Phase + + MAG Status - - Spin Phase + + HIT Status - - Spin Phase + + CoDICE Status - - Spin Phase + + IMAP_LO Status - - Spin Phase + + IMAP_HI_45 Status - - Spin Phase + + IMAP_HI_90 Status - - Spin Phase + + IMAP_ULTRA_45 Status - - Spin Phase + + IMAP_ULTRA_90 - - Spin Phase + + SWE Status - - Spin Phase + + IDEX Status - - Spin Phase + + GLOWS Status - - Spin Phase + + Spare 2 - Spin Phase + Spin Period Spin Phase - Spin Phase + Inertial Right Ascension of system angular momentum vector - Spin Phase + Inertial Declination of system angular momentum vector - - Spin Phase + + + Spin period valid bit: + '1' -- valid, + '0' -- invalid + - - Spin Phase + + + Spin phase valid bit: + '1' -- valid, + '0' -- invalid + - - Spin Phase + + Attitude Estimation Data Source - - Spin Phase + + Catbed Heater Flag - - Spin Phase + + Autonomy Application Data Validity Flag - - Spin Phase + + Spare 3 - - Spin Phase + + CODICE L0 - - Spin Phase + + CODICE HI - - Spin Phase + + SWAPI - - Spin Phase + + HIT - - Spin Phase + + SWE - - Spin Phase + + MAG @@ -358,45 +402,46 @@ + + - - + - - - - - - - - - - - - - + + + + + + + + + + + + + - - + + - + - - - - - - - + + + + + + + From 711a4c0070603bb3b95c7f0c44ab764b82d23586 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Fri, 29 Sep 2023 16:55:56 -0600 Subject: [PATCH 03/21] adding hit decom --- imap_processing/ialirt/l0/decom_hit.py | 190 ++++++++++++++++++ imap_processing/ialirt/l0/decom_ialirt.py | 3 - .../{l0 => packet_definitions}/ialirt.xml | 34 +++- .../l0/IALiRT Raw Packet Telemetry.txt | 0 .../ialirt/tests/unit/data_path_fixtures.py | 23 +++ .../ialirt/tests/unit/test_decom_hit.py | 22 ++ .../ialirt/tests/unit/test_decom_ialirt.py | 42 ++++ 7 files changed, 302 insertions(+), 12 deletions(-) create mode 100644 imap_processing/ialirt/l0/decom_hit.py rename imap_processing/ialirt/{l0 => packet_definitions}/ialirt.xml (95%) rename imap_processing/ialirt/{ => tests/test_data}/l0/IALiRT Raw Packet Telemetry.txt (100%) create mode 100644 imap_processing/ialirt/tests/unit/data_path_fixtures.py create mode 100644 imap_processing/ialirt/tests/unit/test_decom_hit.py create mode 100644 imap_processing/ialirt/tests/unit/test_decom_ialirt.py diff --git a/imap_processing/ialirt/l0/decom_hit.py b/imap_processing/ialirt/l0/decom_hit.py new file mode 100644 index 000000000..2496caf07 --- /dev/null +++ b/imap_processing/ialirt/l0/decom_hit.py @@ -0,0 +1,190 @@ +import logging +from enum import Enum +from typing import NamedTuple + +import numpy as np +import xarray as xr + +from imap_processing.ialirt.l0 import decom_ialirt + +logging.basicConfig(level=logging.INFO) + + +class PacketProperties(NamedTuple): + """Class that represents properties of the ULTRA packet type.""" + apid: int + width: int + block: int + len_array: int + + +class UltraParams(Enum): + ULTRA_AUX = PacketProperties(apid=880, width=None, block=None, + len_array=None) + ULTRA_IMG_RATES = PacketProperties(apid=881, width=5, block=16, + len_array = 48) + + +def read_n_bits(binary: str, n: int, current_position: int): + """ + Extract a specified number of bits from a binary string, + starting from a given position. This is used twice. + The first time it reads the first 5 bits to determine the width. + The second time it uses the width to determine the value of the bitstring. + + Parameters + ---------- + binary : str + The string of binary data from which bits will be read. + This is a string of 0's and 1's. + n : int + Number of bits to read from the binary string. + current_position : int + The starting position in the binary string from which bits will be read. + + Returns + ------- + value : int + The integer representation of the read bits or None if the end of the + string is reached before reading 'n' bits. + current_position + n + - The updated position in the binary string after reading the bits. + """ + + # Ensure we don't read past the end + if current_position + n > len(binary): + raise IndexError(f"Attempted to read past the end of binary string. " + f"Current position: {current_position}, " + f"Requested bits: {n}, String length: {len(binary)}") + + value = int(binary[current_position:current_position + n], 2) + return value, current_position + n + + +def log_decompression(value: int) -> int: + """ + Perform logarithmic decompression on a 16-bit integer. + + Parameters + ---------- + value : int + A 16-bit integer comprised of a 4-bit exponent followed by a 12-bit mantissa. + + Returns + ------- + int + The decompressed integer value. + + Note: Equations from Section 1.2.1.1 Data Compression and Decompression Algorithms + in Ultra_algorithm_doc_rev2.pdf. + """ + # The exponent e, and mantissa, m are 4-bit and 12-bit unsigned integers + # respectively + e = value >> 12 # Extract the 4 most significant bits for the exponent + m = value & 0xFFF # Extract the 12 least significant bits for the mantissa + + if e == 0: + return m + else: + return (4096 + m) << (e - 1) + + +def decompress_binary(binary: str, width_bit: int, block: int) -> list: + """ + Decompress a binary string based on block-width encoding and + logarithmic compression. + + This function interprets a binary string where the first 'width_bit' bits + specifies the width of the following values. Each value is then extracted and + subjected to logarithmic decompression. + + Parameters + ---------- + binary : str + A binary string containing the compressed data. + width_bit : int + The bit width that describes the width of data in the block + block : int + Number of values in each block + + Returns + ------- + list + A list of decompressed values. + + Note: Equations from Section 1.2.1.1 Data Compression and Decompression Algorithms + in Ultra_algorithm_doc_rev2.pdf. + """ + current_position = 0 + decompressed_values = [] + + while current_position < len(binary): + # Read the width of the block + width, current_position = read_n_bits(binary, width_bit, current_position) + # If width is 0 or None, we don't have enough bits left + if width is None or len(decompressed_values) >= \ + UltraParams.ULTRA_IMG_RATES.value.len_array: + print('hi') + break + + # For each block, read 16 values of the given width + for _ in range(block): + # Ensure there are enough bits left to read the width + if len(binary) - current_position < width: + break + + value, current_position = read_n_bits(binary, width, current_position) + + # Log decompression + decompressed_values.append(log_decompression(value)) + + return decompressed_values + + +def decom_hit_packets(packet_file: str, xtce: str): + """ + Unpack and decode hit packets using CCSDS format and XTCE packet definitions. + + Parameters + ---------- + packet_file : str + Path to the CCSDS data packet file. + xtce : str + Path to the XTCE packet definition file. + + Returns + ------- + xr.Dataset + A dataset containing the decoded data fields with 'time' as the coordinating + dimension. + """ + + packets = decom_ialirt.decom_packets(packet_file, xtce) + + met_data, science_id, spin_data, abortflag_data, startdelay_data, fastdata_00 = \ + [], [], [], [], [], [] + + for packet in packets: + met_data.append(packet.data['HIT'].derived_value) + science_id.append(packet.data['SID'].derived_value) + spin_data.append(packet.data['SPIN'].derived_value) + abortflag_data.append(packet.data['ABORTFLAG'].derived_value) + startdelay_data.append(packet.data['STARTDELAY'].derived_value) + decompressed_data = decompress_binary(packet.data['FASTDATA_00'].raw_value, + UltraParams.ULTRA_IMG_RATES.value.width, + UltraParams.ULTRA_IMG_RATES.value.block) + fastdata_00.append(decompressed_data) + + array_data = np.array(fastdata_00) + + ds = xr.Dataset({ + 'science_id': ('epoch', science_id), + 'spin_data': ('epoch', spin_data), + 'abortflag_data': ('epoch', abortflag_data), + 'startdelay_data': ('epoch', startdelay_data), + 'fastdata_00': (('epoch', 'index'), array_data) + }, coords={ + 'epoch': met_data, + }) + + return ds diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py index c8360c7a9..bf1843a98 100644 --- a/imap_processing/ialirt/l0/decom_ialirt.py +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -48,9 +48,6 @@ def decom_packets(packet_file, xtce_packet_definition): packet_generator = packet_parser.generator(bitstring.ConstBitStream(bin=binary_values)) for packet in packet_generator: - print('hi') packets.append(packet) return packets - -decom_packets("IALiRT Raw Packet Telemetry.txt", "ialirt.xml") diff --git a/imap_processing/ialirt/l0/ialirt.xml b/imap_processing/ialirt/packet_definitions/ialirt.xml similarity index 95% rename from imap_processing/ialirt/l0/ialirt.xml rename to imap_processing/ialirt/packet_definitions/ialirt.xml index 9039859a3..986cb61eb 100644 --- a/imap_processing/ialirt/l0/ialirt.xml +++ b/imap_processing/ialirt/packet_definitions/ialirt.xml @@ -272,13 +272,13 @@ CCSDS Packet Length (number of bytes after Packet length minus 1) + CCSDS Packet SCLK (sec) CCSDS Packet SCLK (subsec) - SBC Physical ID @@ -303,10 +303,10 @@ HIT Status - + CoDICE Status - + IMAP_LO Status @@ -380,9 +380,11 @@ SWAPI + HIT + SWE @@ -402,12 +404,17 @@ - - - + + + + + + + + @@ -416,8 +423,8 @@ - - + + @@ -439,7 +446,16 @@ - + + + + + + + + + + diff --git a/imap_processing/ialirt/l0/IALiRT Raw Packet Telemetry.txt b/imap_processing/ialirt/tests/test_data/l0/IALiRT Raw Packet Telemetry.txt similarity index 100% rename from imap_processing/ialirt/l0/IALiRT Raw Packet Telemetry.txt rename to imap_processing/ialirt/tests/test_data/l0/IALiRT Raw Packet Telemetry.txt diff --git a/imap_processing/ialirt/tests/unit/data_path_fixtures.py b/imap_processing/ialirt/tests/unit/data_path_fixtures.py new file mode 100644 index 000000000..f10956baa --- /dev/null +++ b/imap_processing/ialirt/tests/unit/data_path_fixtures.py @@ -0,0 +1,23 @@ +"""Pytest plugin module for test data paths""" +import sys +from pathlib import Path + +import pytest + + +@pytest.fixture() +def packet_path(): + """Returns the raw packet directory. + """ + return Path(sys.modules[__name__.split( + '.')[0]].__file__).parent / 'ialirt' / 'tests' / 'test_data' / 'l0' / \ + 'IALiRT Raw Packet Telemetry.txt' + + +@pytest.fixture() +def xtce_ialirt_path(): + """Returns the xtce auxilliary directory. + """ + return Path(sys.modules[__name__.split( + '.')[0]].__file__).parent / 'ialirt' / 'packet_definitions' \ + / "ialirt.xml" diff --git a/imap_processing/ialirt/tests/unit/test_decom_hit.py b/imap_processing/ialirt/tests/unit/test_decom_hit.py new file mode 100644 index 000000000..f53558abc --- /dev/null +++ b/imap_processing/ialirt/tests/unit/test_decom_hit.py @@ -0,0 +1,22 @@ +import pytest + +from imap_processing.ialirt.l0.decom_ialirt import decom_packets +from imap_processing.ialirt.tests.unit.data_path_fixtures import \ + packet_path, xtce_ialirt_path +from imap_processing.ialirt.l0.decom_hit import decom_hit_packets + + +@pytest.fixture() +def decom_hit(packet_path, xtce_ialirt_path): + """Data for decom_ultra""" + data_packet_list = decom_hit_packets(packet_path, xtce_ialirt_path) + return data_packet_list + + +def test_decom_hit(decom_hit): + """This function reads validation data and checks that + decom data matches validation data for auxiliary packet""" + + print('hi') + + diff --git a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py new file mode 100644 index 000000000..4d98cfcea --- /dev/null +++ b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py @@ -0,0 +1,42 @@ +import pytest + +from imap_processing.ialirt.l0.decom_ialirt import decom_packets +from imap_processing.ialirt.tests.unit.data_path_fixtures import \ + packet_path, xtce_ialirt_path + + +@pytest.fixture() +def decom_test_data(packet_path, xtce_ialirt_path): + """Read test data from file""" + data_packet_list = decom_packets(packet_path, xtce_ialirt_path) + return data_packet_list + + +def test_length(decom_test_data): + """Test if total packets in data file is correct""" + total_packets = 32 + assert len(decom_test_data) == total_packets + + +def test_enumerated(decom_test_data): + """Test if enumerated values derived correctly""" + + for packet in decom_test_data: + + assert packet.data["SWAPI_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["MAG_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["HIT_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["CODICE_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["LO_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["HI_45_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["HI_90_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["ULTRA_45_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["ULTRA_90_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SWE_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["IDEX_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["GLOWS_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SPINPERIODVALID"].derived_value == 'INVALID' + assert packet.data["SPINPHASEVALID"].derived_value == 'INVALID' + assert packet.data["ATTITUDE"].derived_value == 'SUNSENSOR' + assert packet.data["CATBEDHEATERFLAG"].derived_value == 'ON' + assert packet.data["AUTONOMY"].derived_value == 'OPERATIONAL' From 01482f62f1b3b3016b9f51b651626cafac5443e2 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Thu, 5 Oct 2023 16:58:26 -0600 Subject: [PATCH 04/21] adding other instruments --- .../l0/{decom_hit.py => decom_instruments.py} | 50 +- .../ialirt/packet_definitions/ialirt.xml | 611 ++++++++++++++---- .../ialirt/tests/unit/test_decom_hit.py | 12 +- 3 files changed, 521 insertions(+), 152 deletions(-) rename imap_processing/ialirt/l0/{decom_hit.py => decom_instruments.py} (77%) diff --git a/imap_processing/ialirt/l0/decom_hit.py b/imap_processing/ialirt/l0/decom_instruments.py similarity index 77% rename from imap_processing/ialirt/l0/decom_hit.py rename to imap_processing/ialirt/l0/decom_instruments.py index 2496caf07..49df4cff3 100644 --- a/imap_processing/ialirt/l0/decom_hit.py +++ b/imap_processing/ialirt/l0/decom_instruments.py @@ -141,7 +141,7 @@ def decompress_binary(binary: str, width_bit: int, block: int) -> list: return decompressed_values -def decom_hit_packets(packet_file: str, xtce: str): +def decom_instrument_packets(packet_file: str, xtce: str): """ Unpack and decode hit packets using CCSDS format and XTCE packet definitions. @@ -161,30 +161,34 @@ def decom_hit_packets(packet_file: str, xtce: str): packets = decom_ialirt.decom_packets(packet_file, xtce) - met_data, science_id, spin_data, abortflag_data, startdelay_data, fastdata_00 = \ - [], [], [], [], [], [] + hit_storage = {} for packet in packets: - met_data.append(packet.data['HIT'].derived_value) - science_id.append(packet.data['SID'].derived_value) - spin_data.append(packet.data['SPIN'].derived_value) - abortflag_data.append(packet.data['ABORTFLAG'].derived_value) - startdelay_data.append(packet.data['STARTDELAY'].derived_value) - decompressed_data = decompress_binary(packet.data['FASTDATA_00'].raw_value, - UltraParams.ULTRA_IMG_RATES.value.width, - UltraParams.ULTRA_IMG_RATES.value.block) - fastdata_00.append(decompressed_data) - - array_data = np.array(fastdata_00) - - ds = xr.Dataset({ - 'science_id': ('epoch', science_id), - 'spin_data': ('epoch', spin_data), - 'abortflag_data': ('epoch', abortflag_data), - 'startdelay_data': ('epoch', startdelay_data), - 'fastdata_00': (('epoch', 'index'), array_data) + for key, value in packet.data.items(): + if key.startswith('HIT'): + if key not in hit_storage: + hit_storage[key] = [] + hit_storage[key].append(value.derived_value) + + hit_ds = xr.Dataset({ + 'status': ('met', hit_storage['HIT_STATUS']), + 'reserved': ('met', hit_storage['HIT_RESERVED']), + 'counter': ('met', hit_storage['HIT_COUNTER']), + 'fast_rate_1': ('met', hit_storage['HIT_FAST_RATE_1']), + 'fast_rate_2': ('met', hit_storage['HIT_FAST_RATE_2']), + 'slow_rate': ('met', hit_storage['HIT_SLOW_RATE']), + 'event_data_01': ('met', hit_storage['HIT_EVENT_DATA_01']), + 'event_data_02': ('met', hit_storage['HIT_EVENT_DATA_02']), + 'event_data_03': ('met', hit_storage['HIT_EVENT_DATA_03']), + 'event_data_04': ('met', hit_storage['HIT_EVENT_DATA_04']), + 'event_data_05': ('met', hit_storage['HIT_EVENT_DATA_05']), + 'event_data_06': ('met', hit_storage['HIT_EVENT_DATA_06']), + 'event_data_07': ('met', hit_storage['HIT_EVENT_DATA_07']), + 'event_data_08': ('met', hit_storage['HIT_EVENT_DATA_08']), + 'event_data_09': ('met', hit_storage['HIT_EVENT_DATA_09']), + 'event_data_10': ('met', hit_storage['HIT_EVENT_DATA_10']), }, coords={ - 'epoch': met_data, + 'met': hit_storage['HIT_MET'], }) - return ds + return hit_ds diff --git a/imap_processing/ialirt/packet_definitions/ialirt.xml b/imap_processing/ialirt/packet_definitions/ialirt.xml index 986cb61eb..0a81c183b 100644 --- a/imap_processing/ialirt/packet_definitions/ialirt.xml +++ b/imap_processing/ialirt/packet_definitions/ialirt.xml @@ -197,54 +197,44 @@ - - - - - 176 - - - - - - - - 96 - - - - - - - - 160 - - - - - - - - 432 - - - - - - - - 288 - - - - - - - - 96 - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + CCSDS Packet SCLK (sec) - + CCSDS Packet SCLK (subsec) - + SBC Physical ID - + Spare 1 - + Autonomy Rule Fire Count - + First Autonomy Fault Rule Fired - + Last Autonomy Fault Rule Fired - + SWAPI Status - + MAG Status - + HIT Status - + CoDICE Status - + IMAP_LO Status - + IMAP_HI_45 Status - + IMAP_HI_90 Status - + IMAP_ULTRA_45 Status - + IMAP_ULTRA_90 - + SWE Status - + IDEX Status - + GLOWS Status - + Spare 2 - + Spin Period - + Spin Phase - + Inertial Right Ascension of system angular momentum vector - + Inertial Declination of system angular momentum vector - + Spin period valid bit: '1' -- valid, '0' -- invalid - + Spin phase valid bit: '1' -- valid, '0' -- invalid - + Attitude Estimation Data Source - + Catbed Heater Flag - + Autonomy Application Data Validity Flag - + Spare 3 - - CODICE L0 + + + SWE Acquisition Time (sec) + + + SWE Acquisition Time (sub sec) + + + 1 = nominal, 0 = off-nominal + + + 1 = HVSCI mode, 0 = not HVSCI mode + + + Sequence Number corresponds to 15 2-spin sectors times 4 sets. + + + Electron counts for CEM1 energy 1. + + + Electron counts for CEM1 energy 2. + + + Electron counts for CEM1 energy 3. + + + Electron counts for CEM1 energy 4. + + + Electron counts for CEM2 energy 1. + + + Electron counts for CEM2 energy 2. + + + Electron counts for CEM2 energy 3. + + + Electron counts for CEM2 energy 4. + + + Electron counts for CEM3 energy 1. + + + Electron counts for CEM3 energy 2. + + + Electron counts for CEM3 energy 3. + + + Electron counts for CEM3 energy 4. + + + Electron counts for CEM4 energy 1. + + + Electron counts for CEM4 energy 2. + + + Electron counts for CEM4 energy 3. + + + Electron counts for CEM4 energy 4. + + + Electron counts for CEM5 energy 1. + + + Electron counts for CEM5 energy 2. + + + Electron counts for CEM5 energy 3. + + + Electron counts for CEM5 energy 4. + + + Electron counts for CEM6 energy 1. + + + Electron counts for CEM6 energy 2. + + + Electron counts for CEM6 energy 3. + + + Electron counts for CEM6 energy 4. + + + Electron counts for CEM7 energy 1. + + + Electron counts for CEM7 energy 2. + + + Electron counts for CEM7 energy 3. + + + Electron counts for CEM7 energy 4. + + + + + MAG Acquisition Time + + + MAG Status + + + MAG Data + + + + + SWAPI Acquisition Time + + + 1 = nominal, 0 = off-nominal + + + SWAPI Instrument Reserved + + + Sequence Number in Table + + + Sweep Table Version Number + + + Coincidence Counts Step 1 + + + Coincidence Counts Step 2 + + + Coincidence Counts Step 3 + + + Coincidence Counts Step 4 + + + Coincidence Counts Step 5 + + + Coincidence Counts Step 6 + + + Spare + + + + + CODICE HI Acquisition Time + + + CODICE HI Status + + + CODICE HI Status + + + CODICE HI Data_00 + + + CODICE HI Data_01 + + + CODICE HI Data_02 + + + CODICE HI Data_03 + + + CODICE HI Data_04 + + + CODICE HI Spare 0 + + + + + CODICE LO Acquisition Time + + + CODICE LO Status + + + CODICE LO Counter + + + CODICE LO Data_00 + + + CODICE LO Data_01 + + + CODICE LO Data_02 + + + CODICE LO Data_03 - - CODICE HI + + CODICE LO Data_04 - - SWAPI + + CODICE LO Data_05 + + CODICE LO Data_06 + + + CODICE LO Data_07 + + + CODICE LO Data_08 + + + CODICE LO Data_09 + + + CODICE LO Data_10 + + + CODICE LO Data_11 + + + CODICE LO Data_12 + + + CODICE LO Data_13 + + + CODICE LO Data_14 + + + CODICE LO Spare 0 + + - - HIT + + Mission Elapsed Time in Seconds + + + 1 = nominal, 0 = off-nominal + + + Reserved + + + Seconds counter + + + 4 second cadence + + + 4 second cadence + + + 1 minute cadence + + + event data 00 + + + event data 01 + + + event data 02 + + + event data 03 + + + event data 04 + + + event data 05 + + + event data 06 + + + event data 07 + + + event data 08 + + + event data 09 + + + event data 10 @@ -413,51 +683,144 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/imap_processing/ialirt/tests/unit/test_decom_hit.py b/imap_processing/ialirt/tests/unit/test_decom_hit.py index f53558abc..8012539e8 100644 --- a/imap_processing/ialirt/tests/unit/test_decom_hit.py +++ b/imap_processing/ialirt/tests/unit/test_decom_hit.py @@ -3,19 +3,21 @@ from imap_processing.ialirt.l0.decom_ialirt import decom_packets from imap_processing.ialirt.tests.unit.data_path_fixtures import \ packet_path, xtce_ialirt_path -from imap_processing.ialirt.l0.decom_hit import decom_hit_packets +from imap_processing.ialirt.l0.decom_instruments import decom_instrument_packets @pytest.fixture() -def decom_hit(packet_path, xtce_ialirt_path): +def decom_data(packet_path, xtce_ialirt_path): """Data for decom_ultra""" - data_packet_list = decom_hit_packets(packet_path, xtce_ialirt_path) + data_packet_list = decom_instrument_packets(packet_path, xtce_ialirt_path) return data_packet_list -def test_decom_hit(decom_hit): +def test_decom_hit(decom_data): """This function reads validation data and checks that - decom data matches validation data for auxiliary packet""" + decom data matches validation data""" + + print('hi') From 7d0ca70136e581084cf75107f3e6f08068fd9599 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Tue, 10 Oct 2023 09:49:04 -0600 Subject: [PATCH 05/21] update --- .../ialirt/l0/decom_instruments.py | 51 ++++++++-------- .../ialirt/packet_definitions/ialirt.xml | 58 +++++++++---------- 2 files changed, 51 insertions(+), 58 deletions(-) diff --git a/imap_processing/ialirt/l0/decom_instruments.py b/imap_processing/ialirt/l0/decom_instruments.py index 49df4cff3..c30cd905c 100644 --- a/imap_processing/ialirt/l0/decom_instruments.py +++ b/imap_processing/ialirt/l0/decom_instruments.py @@ -161,34 +161,29 @@ def decom_instrument_packets(packet_file: str, xtce: str): packets = decom_ialirt.decom_packets(packet_file, xtce) - hit_storage = {} + # List of instruments and their corresponding MET keys + instruments = ['HIT', 'MAG', 'COD_LO', 'COD_HI', 'SWE', 'SWAPI'] + instrument_coords = ['HIT_SC_TICK', 'MAG_ACQ', 'COD_LO_ACQ', 'COD_HI_ACQ', 'SWE_ACQ_SEC', 'SWAPI_ACQ'] + + # Create a dictionary mapping each instrument to its MET key + met_keys = dict(zip(instruments, instrument_coords)) + + # Initialize storage dictionary + data_storage = {inst: {} for inst in instruments} for packet in packets: for key, value in packet.data.items(): - if key.startswith('HIT'): - if key not in hit_storage: - hit_storage[key] = [] - hit_storage[key].append(value.derived_value) - - hit_ds = xr.Dataset({ - 'status': ('met', hit_storage['HIT_STATUS']), - 'reserved': ('met', hit_storage['HIT_RESERVED']), - 'counter': ('met', hit_storage['HIT_COUNTER']), - 'fast_rate_1': ('met', hit_storage['HIT_FAST_RATE_1']), - 'fast_rate_2': ('met', hit_storage['HIT_FAST_RATE_2']), - 'slow_rate': ('met', hit_storage['HIT_SLOW_RATE']), - 'event_data_01': ('met', hit_storage['HIT_EVENT_DATA_01']), - 'event_data_02': ('met', hit_storage['HIT_EVENT_DATA_02']), - 'event_data_03': ('met', hit_storage['HIT_EVENT_DATA_03']), - 'event_data_04': ('met', hit_storage['HIT_EVENT_DATA_04']), - 'event_data_05': ('met', hit_storage['HIT_EVENT_DATA_05']), - 'event_data_06': ('met', hit_storage['HIT_EVENT_DATA_06']), - 'event_data_07': ('met', hit_storage['HIT_EVENT_DATA_07']), - 'event_data_08': ('met', hit_storage['HIT_EVENT_DATA_08']), - 'event_data_09': ('met', hit_storage['HIT_EVENT_DATA_09']), - 'event_data_10': ('met', hit_storage['HIT_EVENT_DATA_10']), - }, coords={ - 'met': hit_storage['HIT_MET'], - }) - - return hit_ds + for inst in instruments: + if key.startswith(inst): + if key not in data_storage[inst]: + data_storage[inst][key] = [] + data_storage[inst][key].append(value.derived_value) + break # Break once a matching instrument is found + + # Generate datasets + datasets = {} + for inst in instruments: + dataset_dict = {key: ('ACQ', value) for key, value in data_storage[inst].items() if key != met_keys[inst]} + datasets[inst] = xr.Dataset(dataset_dict, coords={'ACQ': data_storage[inst][met_keys[inst]]}) + + return datasets diff --git a/imap_processing/ialirt/packet_definitions/ialirt.xml b/imap_processing/ialirt/packet_definitions/ialirt.xml index 0a81c183b..152acbf26 100644 --- a/imap_processing/ialirt/packet_definitions/ialirt.xml +++ b/imap_processing/ialirt/packet_definitions/ialirt.xml @@ -163,6 +163,10 @@ + + + + @@ -515,10 +519,10 @@ CODICE HI Acquisition Time - + CODICE HI Status - + CODICE HI Status @@ -544,63 +548,63 @@ CODICE LO Acquisition Time - + CODICE LO Status - + CODICE LO Counter - + CODICE LO Data_00 - + CODICE LO Data_01 - + CODICE LO Data_02 - + CODICE LO Data_03 - + CODICE LO Data_04 - + CODICE LO Data_05 - + CODICE LO Data_06 - + CODICE LO Data_07 - + CODICE LO Data_08 - + CODICE LO Data_09 - + CODICE LO Data_10 - + CODICE LO Data_11 - + CODICE LO Data_12 - + CODICE LO Data_13 - + CODICE LO Data_14 - + CODICE LO Spare 0 - + Mission Elapsed Time in Seconds @@ -655,12 +659,6 @@ event data 10 - - SWE - - - MAG - @@ -736,8 +734,8 @@ - - + + @@ -767,7 +765,7 @@ - + From 193595a89e079dd48fde8764d40459a75536d40f Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Tue, 10 Oct 2023 12:04:15 -0600 Subject: [PATCH 06/21] formatting --- imap_processing/ialirt/l0/decom_ialirt.py | 101 +++++++++- .../ialirt/l0/decom_instruments.py | 189 ------------------ .../ialirt/packet_definitions/ialirt.xml | 35 +--- .../ialirt/tests/unit/data_path_fixtures.py | 23 --- .../ialirt/tests/unit/test_decom_hit.py | 24 --- .../ialirt/tests/unit/test_decom_ialirt.py | 91 +++++++-- 6 files changed, 173 insertions(+), 290 deletions(-) delete mode 100644 imap_processing/ialirt/l0/decom_instruments.py delete mode 100644 imap_processing/ialirt/tests/unit/data_path_fixtures.py delete mode 100644 imap_processing/ialirt/tests/unit/test_decom_hit.py diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py index bf1843a98..a96c423e9 100644 --- a/imap_processing/ialirt/l0/decom_ialirt.py +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -1,8 +1,21 @@ -from space_packet_parser import parser, xtcedef +import logging +from enum import Enum + import bitstring +import xarray as xr +from space_packet_parser import parser, xtcedef + +logging.basicConfig(level=logging.ERROR) +logger = logging.getLogger(__name__) + + +class PacketLength(Enum): + EXPECTED_LENGTH = 1464 + def decom_packets(packet_file, xtce_packet_definition): - """Unpack data packet. In this function, we unpack and return data + """ + Unpack data packet. In this function, we unpack and return data as it is. Data modification will not be done at this step. Parameters @@ -23,8 +36,8 @@ def decom_packets(packet_file, xtce_packet_definition): packets = [] - with open(packet_file, "r") as file: - for line in file: + with open(packet_file) as file: + for line_number, line in enumerate(file, 1): if not line.startswith("#"): # Split the line by semicolons # Discard the first value since it is only a counter @@ -45,9 +58,87 @@ def decom_packets(packet_file, xtce_packet_definition): # Append the padded binary string to the final string binary_values += bin_value_padded - packet_generator = packet_parser.generator(bitstring.ConstBitStream(bin=binary_values)) + # Check the length of binary_values + if len(binary_values) != PacketLength.EXPECTED_LENGTH.value: + error_message = f"Error on line {line_number}: " \ + f"Length of binary_values (" \ + f"{len(binary_values)}) does not equal " \ + f"{PacketLength.EXPECTED_LENGTH.value}." + logger.error(error_message) + raise ValueError(error_message) + + packet_generator = packet_parser.generator( + bitstring.ConstBitStream(bin=binary_values)) for packet in packet_generator: packets.append(packet) return packets + + +def generate_xarray(packet_file: str, xtce: str): + """ + Generate xarray from unpacked data. + + Parameters + ---------- + packet_file : str + Path to the CCSDS data packet file. + xtce : str + Path to the XTCE packet definition file. + + Returns + ------- + xr.Dataset + A dataset containing the decoded data fields with 'time' as the coordinating + dimension. + """ + + try: + packets = decom_packets(packet_file, xtce) + except Exception as e: + logger.error(f"Error during packet decomposition: {str(e)}") + return + + if not packets: + logger.warning(f"No packets found in {packet_file}.") + return + + logger.info(f"Decomposed {len(packets)} packets from {packet_file}.") + + # List of instruments and their corresponding MET keys + instruments = ['SC', 'HIT', 'MAG', 'COD_LO', 'COD_HI', 'SWE', 'SWAPI'] + instrument_coords = ['SC_SCLK_SEC', 'HIT_SC_TICK', 'MAG_ACQ', 'COD_LO_ACQ', + 'COD_HI_ACQ', 'SWE_ACQ_SEC', 'SWAPI_ACQ'] + + # Create a dictionary mapping each instrument to its time-dimension key + time_keys = dict(zip(instruments, instrument_coords)) + + # Initialize storage dictionary + data_storage = {inst: {} for inst in instruments} + + for packet in packets: + for key, value in packet.data.items(): + for inst in instruments: + if key.startswith(inst): + if key not in data_storage[inst]: + data_storage[inst][key] = [] + data_storage[inst][key].append(value.derived_value) + break + else: + logger.warning(f"Unexpected key '{key}' found in packet data.") + + logger.info("Generating datasets for each instrument.") + + # Generate xarray dataset for each instrument and spacecraft + datasets = {} + for inst in instruments: + dataset_dict = {key: (time_keys[inst], value) + for key, value in data_storage[inst].items() if + key != time_keys[inst]} + datasets[inst] = xr.Dataset(dataset_dict, coords={ + time_keys[inst]: data_storage[inst][time_keys[inst]]}) + + logger.info(f"Generated datasets for {len(datasets)} instruments.") + + return datasets diff --git a/imap_processing/ialirt/l0/decom_instruments.py b/imap_processing/ialirt/l0/decom_instruments.py deleted file mode 100644 index c30cd905c..000000000 --- a/imap_processing/ialirt/l0/decom_instruments.py +++ /dev/null @@ -1,189 +0,0 @@ -import logging -from enum import Enum -from typing import NamedTuple - -import numpy as np -import xarray as xr - -from imap_processing.ialirt.l0 import decom_ialirt - -logging.basicConfig(level=logging.INFO) - - -class PacketProperties(NamedTuple): - """Class that represents properties of the ULTRA packet type.""" - apid: int - width: int - block: int - len_array: int - - -class UltraParams(Enum): - ULTRA_AUX = PacketProperties(apid=880, width=None, block=None, - len_array=None) - ULTRA_IMG_RATES = PacketProperties(apid=881, width=5, block=16, - len_array = 48) - - -def read_n_bits(binary: str, n: int, current_position: int): - """ - Extract a specified number of bits from a binary string, - starting from a given position. This is used twice. - The first time it reads the first 5 bits to determine the width. - The second time it uses the width to determine the value of the bitstring. - - Parameters - ---------- - binary : str - The string of binary data from which bits will be read. - This is a string of 0's and 1's. - n : int - Number of bits to read from the binary string. - current_position : int - The starting position in the binary string from which bits will be read. - - Returns - ------- - value : int - The integer representation of the read bits or None if the end of the - string is reached before reading 'n' bits. - current_position + n - - The updated position in the binary string after reading the bits. - """ - - # Ensure we don't read past the end - if current_position + n > len(binary): - raise IndexError(f"Attempted to read past the end of binary string. " - f"Current position: {current_position}, " - f"Requested bits: {n}, String length: {len(binary)}") - - value = int(binary[current_position:current_position + n], 2) - return value, current_position + n - - -def log_decompression(value: int) -> int: - """ - Perform logarithmic decompression on a 16-bit integer. - - Parameters - ---------- - value : int - A 16-bit integer comprised of a 4-bit exponent followed by a 12-bit mantissa. - - Returns - ------- - int - The decompressed integer value. - - Note: Equations from Section 1.2.1.1 Data Compression and Decompression Algorithms - in Ultra_algorithm_doc_rev2.pdf. - """ - # The exponent e, and mantissa, m are 4-bit and 12-bit unsigned integers - # respectively - e = value >> 12 # Extract the 4 most significant bits for the exponent - m = value & 0xFFF # Extract the 12 least significant bits for the mantissa - - if e == 0: - return m - else: - return (4096 + m) << (e - 1) - - -def decompress_binary(binary: str, width_bit: int, block: int) -> list: - """ - Decompress a binary string based on block-width encoding and - logarithmic compression. - - This function interprets a binary string where the first 'width_bit' bits - specifies the width of the following values. Each value is then extracted and - subjected to logarithmic decompression. - - Parameters - ---------- - binary : str - A binary string containing the compressed data. - width_bit : int - The bit width that describes the width of data in the block - block : int - Number of values in each block - - Returns - ------- - list - A list of decompressed values. - - Note: Equations from Section 1.2.1.1 Data Compression and Decompression Algorithms - in Ultra_algorithm_doc_rev2.pdf. - """ - current_position = 0 - decompressed_values = [] - - while current_position < len(binary): - # Read the width of the block - width, current_position = read_n_bits(binary, width_bit, current_position) - # If width is 0 or None, we don't have enough bits left - if width is None or len(decompressed_values) >= \ - UltraParams.ULTRA_IMG_RATES.value.len_array: - print('hi') - break - - # For each block, read 16 values of the given width - for _ in range(block): - # Ensure there are enough bits left to read the width - if len(binary) - current_position < width: - break - - value, current_position = read_n_bits(binary, width, current_position) - - # Log decompression - decompressed_values.append(log_decompression(value)) - - return decompressed_values - - -def decom_instrument_packets(packet_file: str, xtce: str): - """ - Unpack and decode hit packets using CCSDS format and XTCE packet definitions. - - Parameters - ---------- - packet_file : str - Path to the CCSDS data packet file. - xtce : str - Path to the XTCE packet definition file. - - Returns - ------- - xr.Dataset - A dataset containing the decoded data fields with 'time' as the coordinating - dimension. - """ - - packets = decom_ialirt.decom_packets(packet_file, xtce) - - # List of instruments and their corresponding MET keys - instruments = ['HIT', 'MAG', 'COD_LO', 'COD_HI', 'SWE', 'SWAPI'] - instrument_coords = ['HIT_SC_TICK', 'MAG_ACQ', 'COD_LO_ACQ', 'COD_HI_ACQ', 'SWE_ACQ_SEC', 'SWAPI_ACQ'] - - # Create a dictionary mapping each instrument to its MET key - met_keys = dict(zip(instruments, instrument_coords)) - - # Initialize storage dictionary - data_storage = {inst: {} for inst in instruments} - - for packet in packets: - for key, value in packet.data.items(): - for inst in instruments: - if key.startswith(inst): - if key not in data_storage[inst]: - data_storage[inst][key] = [] - data_storage[inst][key].append(value.derived_value) - break # Break once a matching instrument is found - - # Generate datasets - datasets = {} - for inst in instruments: - dataset_dict = {key: ('ACQ', value) for key, value in data_storage[inst].items() if key != met_keys[inst]} - datasets[inst] = xr.Dataset(dataset_dict, coords={'ACQ': data_storage[inst][met_keys[inst]]}) - - return datasets diff --git a/imap_processing/ialirt/packet_definitions/ialirt.xml b/imap_processing/ialirt/packet_definitions/ialirt.xml index 152acbf26..da156687d 100644 --- a/imap_processing/ialirt/packet_definitions/ialirt.xml +++ b/imap_processing/ialirt/packet_definitions/ialirt.xml @@ -201,18 +201,7 @@ - - - - - - - - - - - - + @@ -228,17 +217,6 @@ - - - - - - - - - - - + CCSDS Packet SCLK (sec) @@ -365,6 +343,7 @@ Spare 3 + SWE Acquisition Time (sec) @@ -372,7 +351,7 @@ SWE Acquisition Time (sub sec) - + 1 = nominal, 0 = off-nominal @@ -481,7 +460,7 @@ SWAPI Acquisition Time - + 1 = nominal, 0 = off-nominal @@ -605,9 +584,9 @@ - Mission Elapsed Time in Seconds + Spacecraft tick - + 1 = nominal, 0 = off-nominal diff --git a/imap_processing/ialirt/tests/unit/data_path_fixtures.py b/imap_processing/ialirt/tests/unit/data_path_fixtures.py deleted file mode 100644 index f10956baa..000000000 --- a/imap_processing/ialirt/tests/unit/data_path_fixtures.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Pytest plugin module for test data paths""" -import sys -from pathlib import Path - -import pytest - - -@pytest.fixture() -def packet_path(): - """Returns the raw packet directory. - """ - return Path(sys.modules[__name__.split( - '.')[0]].__file__).parent / 'ialirt' / 'tests' / 'test_data' / 'l0' / \ - 'IALiRT Raw Packet Telemetry.txt' - - -@pytest.fixture() -def xtce_ialirt_path(): - """Returns the xtce auxilliary directory. - """ - return Path(sys.modules[__name__.split( - '.')[0]].__file__).parent / 'ialirt' / 'packet_definitions' \ - / "ialirt.xml" diff --git a/imap_processing/ialirt/tests/unit/test_decom_hit.py b/imap_processing/ialirt/tests/unit/test_decom_hit.py deleted file mode 100644 index 8012539e8..000000000 --- a/imap_processing/ialirt/tests/unit/test_decom_hit.py +++ /dev/null @@ -1,24 +0,0 @@ -import pytest - -from imap_processing.ialirt.l0.decom_ialirt import decom_packets -from imap_processing.ialirt.tests.unit.data_path_fixtures import \ - packet_path, xtce_ialirt_path -from imap_processing.ialirt.l0.decom_instruments import decom_instrument_packets - - -@pytest.fixture() -def decom_data(packet_path, xtce_ialirt_path): - """Data for decom_ultra""" - data_packet_list = decom_instrument_packets(packet_path, xtce_ialirt_path) - return data_packet_list - - -def test_decom_hit(decom_data): - """This function reads validation data and checks that - decom data matches validation data""" - - - - print('hi') - - diff --git a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py index 4d98cfcea..288b55647 100644 --- a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py +++ b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py @@ -1,11 +1,35 @@ +import sys +from pathlib import Path + import pytest -from imap_processing.ialirt.l0.decom_ialirt import decom_packets -from imap_processing.ialirt.tests.unit.data_path_fixtures import \ - packet_path, xtce_ialirt_path +from imap_processing.ialirt.l0.decom_ialirt import decom_packets, generate_xarray + + +@pytest.fixture(scope="session") +def packet_path(): + """Returns the raw packet directory.""" + return Path(sys.modules[__name__.split( + '.')[0]].__file__).parent / 'ialirt' / 'tests' / 'test_data' / 'l0' / \ + 'IALiRT Raw Packet Telemetry.txt' + + +@pytest.fixture(scope="session") +def xtce_ialirt_path(): + """Returns the xtce auxiliary directory.""" + return Path(sys.modules[__name__.split( + '.')[0]].__file__).parent / 'ialirt' / 'packet_definitions' \ + / "ialirt.xml" + + +@pytest.fixture(scope="session") +def decom_data(packet_path, xtce_ialirt_path): + """Data for decom_ultra""" + data_packet_list = generate_xarray(packet_path, xtce_ialirt_path) + return data_packet_list -@pytest.fixture() +@pytest.fixture(scope="session") def decom_test_data(packet_path, xtce_ialirt_path): """Read test data from file""" data_packet_list = decom_packets(packet_path, xtce_ialirt_path) @@ -23,20 +47,45 @@ def test_enumerated(decom_test_data): for packet in decom_test_data: - assert packet.data["SWAPI_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["MAG_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["HIT_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["CODICE_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["LO_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["HI_45_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["HI_90_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["ULTRA_45_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["ULTRA_90_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SWE_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["IDEX_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["GLOWS_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SPINPERIODVALID"].derived_value == 'INVALID' - assert packet.data["SPINPHASEVALID"].derived_value == 'INVALID' - assert packet.data["ATTITUDE"].derived_value == 'SUNSENSOR' - assert packet.data["CATBEDHEATERFLAG"].derived_value == 'ON' - assert packet.data["AUTONOMY"].derived_value == 'OPERATIONAL' + assert packet.data["SC_SWAPI_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_MAG_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_HIT_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_CODICE_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_LO_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_HI_45_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_HI_90_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_ULTRA_45_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_ULTRA_90_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_SWE_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_IDEX_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_GLOWS_STATUS"].derived_value == 'NOT_OPERATIONAL' + assert packet.data["SC_SPINPERIODVALID"].derived_value == 'INVALID' + assert packet.data["SC_SPINPHASEVALID"].derived_value == 'INVALID' + assert packet.data["SC_ATTITUDE"].derived_value == 'SUNSENSOR' + assert packet.data["SC_CATBEDHEATERFLAG"].derived_value == 'ON' + assert packet.data["SC_AUTONOMY"].derived_value == 'OPERATIONAL' + assert packet.data["HIT_STATUS"].derived_value == 'OFF-NOMINAL' + assert packet.data["SWE_NOM_FLAG"].derived_value == 'OFF-NOMINAL' + assert packet.data["SWE_OPS_FLAG"].derived_value == 'NON-HVSCI' + + +def test_decom_instruments(decom_data, decom_test_data): + """This function checks that all instrument parameters are accounted for.""" + + instrument_lengths = {} + instruments = ['SC', 'HIT', 'MAG', 'COD_LO', 'COD_HI', 'SWE', 'SWAPI'] + + # Assert that all parameters are the same + # between packet data and generated xarray + for instrument in instruments: + instrument_list = list(decom_data[instrument].coords) + instrument_list.extend(list(decom_data[instrument].data_vars)) + + instrument_lengths[instrument] = len(instrument_list) + + assert all(param in list(decom_test_data[0].data.keys()) + for param in instrument_list) + + # Assert that the length of parameters is the same + # between packet data and generated xarray + assert sum(instrument_lengths.values()) == len(list(decom_test_data[0].data.keys())) From 374fa0598876ef3003bd410338a00faec891136d Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Tue, 10 Oct 2023 12:09:01 -0600 Subject: [PATCH 07/21] mistaken changes --- imap_processing/ultra/tests/unit/test_decom_apid_880.py | 2 ++ imap_processing/ultra/tests/unit/test_decom_apid_881.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/imap_processing/ultra/tests/unit/test_decom_apid_880.py b/imap_processing/ultra/tests/unit/test_decom_apid_880.py index 8cb88e09b..5b3e0545b 100644 --- a/imap_processing/ultra/tests/unit/test_decom_apid_880.py +++ b/imap_processing/ultra/tests/unit/test_decom_apid_880.py @@ -2,6 +2,8 @@ import pytest from imap_processing import decom +from imap_processing.ultra.tests.unit.data_path_fixtures import \ + xtce_aux_test_path, ccsds_path, xtce_aux_path @pytest.fixture() diff --git a/imap_processing/ultra/tests/unit/test_decom_apid_881.py b/imap_processing/ultra/tests/unit/test_decom_apid_881.py index aaa6c1613..21c7220fa 100644 --- a/imap_processing/ultra/tests/unit/test_decom_apid_881.py +++ b/imap_processing/ultra/tests/unit/test_decom_apid_881.py @@ -7,6 +7,9 @@ from imap_processing import decom from imap_processing.ultra.l0.decom_ultra import decom_ultra_packets +from imap_processing.ultra.tests.unit.data_path_fixtures import \ + ccsds_path, xtce_image_rates_path, xtce_image_rates_test_path + @pytest.fixture() def decom_test_data(ccsds_path, xtce_image_rates_path): From 4b947a605f94d94da0e557d2748aa3a769b8bcf8 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Tue, 10 Oct 2023 12:42:34 -0600 Subject: [PATCH 08/21] minor updates --- imap_processing/ultra/tests/unit/test_decom_apid_880.py | 2 -- imap_processing/ultra/tests/unit/test_decom_apid_881.py | 3 --- 2 files changed, 5 deletions(-) diff --git a/imap_processing/ultra/tests/unit/test_decom_apid_880.py b/imap_processing/ultra/tests/unit/test_decom_apid_880.py index 5b3e0545b..8cb88e09b 100644 --- a/imap_processing/ultra/tests/unit/test_decom_apid_880.py +++ b/imap_processing/ultra/tests/unit/test_decom_apid_880.py @@ -2,8 +2,6 @@ import pytest from imap_processing import decom -from imap_processing.ultra.tests.unit.data_path_fixtures import \ - xtce_aux_test_path, ccsds_path, xtce_aux_path @pytest.fixture() diff --git a/imap_processing/ultra/tests/unit/test_decom_apid_881.py b/imap_processing/ultra/tests/unit/test_decom_apid_881.py index 21c7220fa..aaa6c1613 100644 --- a/imap_processing/ultra/tests/unit/test_decom_apid_881.py +++ b/imap_processing/ultra/tests/unit/test_decom_apid_881.py @@ -7,9 +7,6 @@ from imap_processing import decom from imap_processing.ultra.l0.decom_ultra import decom_ultra_packets -from imap_processing.ultra.tests.unit.data_path_fixtures import \ - ccsds_path, xtce_image_rates_path, xtce_image_rates_test_path - @pytest.fixture() def decom_test_data(ccsds_path, xtce_image_rates_path): From 369cf3fd680d41e39b2d9a14be3dbea09a451406 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Tue, 10 Oct 2023 14:51:01 -0600 Subject: [PATCH 09/21] ruff fixes --- imap_processing/ialirt/l0/decom_ialirt.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py index a96c423e9..01681e1e7 100644 --- a/imap_processing/ialirt/l0/decom_ialirt.py +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -10,13 +10,13 @@ class PacketLength(Enum): - EXPECTED_LENGTH = 1464 + """Class that represents properties of the IALiRT packet.""" + EXPECTED_LENGTH = 1464 def decom_packets(packet_file, xtce_packet_definition): """ - Unpack data packet. In this function, we unpack and return data - as it is. Data modification will not be done at this step. + Unpack data packet. In this function, we unpack and return data. Parameters ---------- @@ -27,10 +27,9 @@ def decom_packets(packet_file, xtce_packet_definition): Returns ------- - List + packets : list List of all the unpacked data """ - packet_definition = xtcedef.XtcePacketDefinition(xtce_packet_definition) packet_parser = parser.PacketParser(packet_definition) @@ -93,7 +92,6 @@ def generate_xarray(packet_file: str, xtce: str): A dataset containing the decoded data fields with 'time' as the coordinating dimension. """ - try: packets = decom_packets(packet_file, xtce) except Exception as e: From 06b035a0999fbb5fbeb79808407221482298385a Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Thu, 2 Nov 2023 17:27:31 -0600 Subject: [PATCH 10/21] response to PR --- imap_processing/ialirt/l0/decom_ialirt.py | 120 ++++----------- .../l0/Empty IALiRT Raw Packet Telemetry.txt | 0 .../ialirt/tests/unit/test_decom_ialirt.py | 145 ++++++++++++++---- 3 files changed, 144 insertions(+), 121 deletions(-) create mode 100644 imap_processing/ialirt/tests/test_data/l0/Empty IALiRT Raw Packet Telemetry.txt diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py index 01681e1e7..a8b1f99e2 100644 --- a/imap_processing/ialirt/l0/decom_ialirt.py +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -1,80 +1,12 @@ import logging -from enum import Enum - -import bitstring import xarray as xr -from space_packet_parser import parser, xtcedef +import collections +from imap_processing.decom import decom_packets logging.basicConfig(level=logging.ERROR) logger = logging.getLogger(__name__) -class PacketLength(Enum): - """Class that represents properties of the IALiRT packet.""" - - EXPECTED_LENGTH = 1464 - -def decom_packets(packet_file, xtce_packet_definition): - """ - Unpack data packet. In this function, we unpack and return data. - - Parameters - ---------- - packet_file : str - Path to data packet path with filename - xtce_packet_definition : str - Path to XTCE file with filename - - Returns - ------- - packets : list - List of all the unpacked data - """ - packet_definition = xtcedef.XtcePacketDefinition(xtce_packet_definition) - packet_parser = parser.PacketParser(packet_definition) - - packets = [] - - with open(packet_file) as file: - for line_number, line in enumerate(file, 1): - if not line.startswith("#"): - # Split the line by semicolons - # Discard the first value since it is only a counter - hex_values = line.strip().split(";")[1::] - - binary_values = "" - for h in hex_values: - # Convert hex to integer - # 16 is the base of hexadecimal - int_value = int(h, 16) - - # Convert integer to binary and remove the '0b' prefix - bin_value = bin(int_value)[2:] - - # Make sure each binary string is 8 bits long - bin_value_padded = bin_value.zfill(8) - - # Append the padded binary string to the final string - binary_values += bin_value_padded - - # Check the length of binary_values - if len(binary_values) != PacketLength.EXPECTED_LENGTH.value: - error_message = f"Error on line {line_number}: " \ - f"Length of binary_values (" \ - f"{len(binary_values)}) does not equal " \ - f"{PacketLength.EXPECTED_LENGTH.value}." - logger.error(error_message) - raise ValueError(error_message) - - packet_generator = packet_parser.generator( - bitstring.ConstBitStream(bin=binary_values)) - - for packet in packet_generator: - packets.append(packet) - - return packets - - def generate_xarray(packet_file: str, xtce: str): """ Generate xarray from unpacked data. @@ -98,45 +30,45 @@ def generate_xarray(packet_file: str, xtce: str): logger.error(f"Error during packet decomposition: {str(e)}") return - if not packets: - logger.warning(f"No packets found in {packet_file}.") - return + logger.info(f"Decommutated {len(packets)} packets from {packet_file}.") - logger.info(f"Decomposed {len(packets)} packets from {packet_file}.") + time_keys = { + "SC": "SC_SCLK_SEC", + "HIT": "HIT_SC_TICK", + "MAG": "MAG_ACQ", + "COD_LO": "COD_LO_ACQ", + "COD_HI": "COD_HI_ACQ", + "SWE": "SWE_ACQ_SEC", + "SWAPI": "SWAPI_ACQ" + } - # List of instruments and their corresponding MET keys - instruments = ['SC', 'HIT', 'MAG', 'COD_LO', 'COD_HI', 'SWE', 'SWAPI'] - instrument_coords = ['SC_SCLK_SEC', 'HIT_SC_TICK', 'MAG_ACQ', 'COD_LO_ACQ', - 'COD_HI_ACQ', 'SWE_ACQ_SEC', 'SWAPI_ACQ'] + instruments = list(time_keys.keys()) - # Create a dictionary mapping each instrument to its time-dimension key - time_keys = dict(zip(instruments, instrument_coords)) - - # Initialize storage dictionary - data_storage = {inst: {} for inst in instruments} + # Initialize storage dictionary using defaultdict + data_storage = {inst: collections.defaultdict(list) for inst in instruments} for packet in packets: for key, value in packet.data.items(): + key_matched = False for inst in instruments: if key.startswith(inst): - if key not in data_storage[inst]: - data_storage[inst][key] = [] + # Directly append to the list without checking if the key exists data_storage[inst][key].append(value.derived_value) + key_matched = True break - else: - logger.warning(f"Unexpected key '{key}' found in packet data.") - logger.info("Generating datasets for each instrument.") + if not key_matched: + # If after checking all instruments, none match, then log a warning + logger.warning(f"Unexpected key '{key}' found in packet data.") + + logger.debug("Generating datasets for each instrument.") # Generate xarray dataset for each instrument and spacecraft datasets = {} for inst in instruments: - dataset_dict = {key: (time_keys[inst], value) - for key, value in data_storage[inst].items() if - key != time_keys[inst]} + dataset_dict = {key: (time_keys[inst], data_storage[inst][key]) + for key in data_storage[inst] if key != time_keys[inst]} datasets[inst] = xr.Dataset(dataset_dict, coords={ time_keys[inst]: data_storage[inst][time_keys[inst]]}) - logger.info(f"Generated datasets for {len(datasets)} instruments.") - - return datasets + return datasets \ No newline at end of file diff --git a/imap_processing/ialirt/tests/test_data/l0/Empty IALiRT Raw Packet Telemetry.txt b/imap_processing/ialirt/tests/test_data/l0/Empty IALiRT Raw Packet Telemetry.txt new file mode 100644 index 000000000..e69de29bb diff --git a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py index 288b55647..eda2fd740 100644 --- a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py +++ b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py @@ -1,51 +1,127 @@ -import sys from pathlib import Path import pytest +import tempfile -from imap_processing.ialirt.l0.decom_ialirt import decom_packets, generate_xarray +from imap_processing.ialirt.l0.decom_ialirt import generate_xarray +from imap_processing.decom import decom_packets +from imap_processing import imap_module_directory -@pytest.fixture(scope="session") -def packet_path(): - """Returns the raw packet directory.""" - return Path(sys.modules[__name__.split( - '.')[0]].__file__).parent / 'ialirt' / 'tests' / 'test_data' / 'l0' / \ - 'IALiRT Raw Packet Telemetry.txt' +IALIRT_PACKET_LENGTH = 1464 @pytest.fixture(scope="session") def xtce_ialirt_path(): """Returns the xtce auxiliary directory.""" - return Path(sys.modules[__name__.split( - '.')[0]].__file__).parent / 'ialirt' / 'packet_definitions' \ + return imap_module_directory / 'ialirt' / 'packet_definitions' \ / "ialirt.xml" @pytest.fixture(scope="session") -def decom_data(packet_path, xtce_ialirt_path): - """Data for decom_ultra""" - data_packet_list = generate_xarray(packet_path, xtce_ialirt_path) - return data_packet_list +def binary_packet_path(): + """ + Creates a binary file from the text packet data, which is more representative + of the actual operational environment. The binary file is deleted after the + test session. + """ + packet_path = imap_module_directory / 'ialirt' / 'tests' / 'test_data' / 'l0' / \ + 'IALiRT Raw Packet Telemetry.txt' + + with tempfile.NamedTemporaryFile(delete=False) as tmp_file: + binary_file_path = Path(tmp_file.name) + + with open(packet_path, 'r') as text_file, open(binary_file_path, 'wb') as binary_file: + for line in text_file: + if not line.startswith("#"): + # Split the line by semicolons + # Discard the first value since it is only a counter + hex_values = line.strip().split(";")[1:] + # Convert hex to binary + binary_data = bytearray.fromhex(''.join(hex_values)) + binary_file.write(binary_data) + + yield binary_file_path + + binary_file_path.unlink() + +@pytest.fixture(scope="session") +def empty_binary_packet_path(): + """ + Creates a empty binary file from the text packet data, which is more representative + of the actual operational environment. The binary file is deleted after the + test session. + """ + empty_packet_path = imap_module_directory / 'ialirt' / 'tests' / 'test_data' / 'l0' / \ + 'Empty IALiRT Raw Packet Telemetry.txt' + + with tempfile.NamedTemporaryFile(delete=False) as tmp_file: + binary_file_path = Path(tmp_file.name) + + with open(empty_packet_path, 'r') as text_file, open(binary_file_path, 'wb') as binary_file: + for line in text_file: + if not line.startswith("#"): + # Split the line by semicolons + # Discard the first value since it is only a counter + hex_values = line.strip().split(";")[1:] + # Convert hex to binary + binary_data = bytearray.fromhex(''.join(hex_values)) + binary_file.write(binary_data) + + yield binary_file_path + + binary_file_path.unlink() @pytest.fixture(scope="session") -def decom_test_data(packet_path, xtce_ialirt_path): - """Read test data from file""" - data_packet_list = decom_packets(packet_path, xtce_ialirt_path) +def decom_packets_data(binary_packet_path, xtce_ialirt_path): + """Read packet data from file using decom_packets""" + data_packet_list = decom_packets(binary_packet_path, xtce_ialirt_path) return data_packet_list -def test_length(decom_test_data): +def test_length(decom_packets_data): """Test if total packets in data file is correct""" total_packets = 32 - assert len(decom_test_data) == total_packets + assert len(decom_packets_data) == total_packets -def test_enumerated(decom_test_data): +def test_binary_value_length(): + """ + Creates a binary file from the text packet data, which is more representative + of the actual operational environment. The binary file is deleted after the + test session. + """ + packet_path = imap_module_directory / 'ialirt' / 'tests' / 'test_data' / 'l0' / \ + 'IALiRT Raw Packet Telemetry.txt' + + with tempfile.NamedTemporaryFile(delete=False) as tmp_file: + binary_file_path = Path(tmp_file.name) + + with open(packet_path, 'r') as text_file, open(binary_file_path, 'wb') as binary_file: + for line in text_file: + if not line.startswith("#"): + # Split the line by semicolons + # Discard the first value since it is only a counter + hex_values = line.strip().split(";")[1:] + # Convert hex to binary + binary_data = bytearray.fromhex(''.join(hex_values)) + assert len(binary_data) * 8 == IALIRT_PACKET_LENGTH + + +def test_generate_xarray_empty_file(empty_binary_packet_path, xtce_ialirt_path, caplog): + """Test that an error is logged if an empty file is passed to generate_xarray.""" + + result = generate_xarray(empty_binary_packet_path, xtce_ialirt_path) + + assert "Error during packet decomposition" in caplog.text + assert result is None + + +def test_enumerated(decom_packets_data): """Test if enumerated values derived correctly""" - for packet in decom_test_data: + for packet in decom_packets_data: assert packet.data["SC_SWAPI_STATUS"].derived_value == 'NOT_OPERATIONAL' assert packet.data["SC_MAG_STATUS"].derived_value == 'NOT_OPERATIONAL' @@ -69,23 +145,38 @@ def test_enumerated(decom_test_data): assert packet.data["SWE_OPS_FLAG"].derived_value == 'NON-HVSCI' -def test_decom_instruments(decom_data, decom_test_data): +def test_generate_xarray(binary_packet_path, xtce_ialirt_path, decom_packets_data): """This function checks that all instrument parameters are accounted for.""" instrument_lengths = {} instruments = ['SC', 'HIT', 'MAG', 'COD_LO', 'COD_HI', 'SWE', 'SWAPI'] + xarray_data = generate_xarray(binary_packet_path, xtce_ialirt_path) + # Assert that all parameters are the same # between packet data and generated xarray for instrument in instruments: - instrument_list = list(decom_data[instrument].coords) - instrument_list.extend(list(decom_data[instrument].data_vars)) + instrument_list = list(xarray_data[instrument].coords) + instrument_list.extend(list(xarray_data[instrument].data_vars)) + # Create a dictionary of the number of parameters for each instrument instrument_lengths[instrument] = len(instrument_list) - assert all(param in list(decom_test_data[0].data.keys()) - for param in instrument_list) + packet_data_keys_set = set(decom_packets_data[0].data.keys()) + instrument_list_set = set(instrument_list) + + # Assert that the instrument parameters from the xarray are + # a subset of the packet data + assert instrument_list_set.issubset(packet_data_keys_set) == True # Assert that the length of parameters is the same # between packet data and generated xarray - assert sum(instrument_lengths.values()) == len(list(decom_test_data[0].data.keys())) + assert sum(instrument_lengths.values()) == len( + list(decom_packets_data[0].data.keys())) + + # Check that all the dimensions are the correct length + # example:len(xarray_data['HIT'].coords['HIT_SC_TICK'].values) == 32 + for instrument in instruments: + dimension_name = next(iter(xarray_data[instrument].dims)) + assert len( + xarray_data[instrument].coords[dimension_name].values) == 32 From 5e68e3fe323b891bf95cecc99fabbbee49e7343e Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Thu, 2 Nov 2023 17:32:52 -0600 Subject: [PATCH 11/21] response to pr --- imap_processing/ialirt/l0/decom_ialirt.py | 20 ++-- .../ialirt/tests/unit/test_decom_ialirt.py | 106 ++++++++++-------- 2 files changed, 75 insertions(+), 51 deletions(-) diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py index a8b1f99e2..b8167d61c 100644 --- a/imap_processing/ialirt/l0/decom_ialirt.py +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -1,6 +1,8 @@ +import collections import logging + import xarray as xr -import collections + from imap_processing.decom import decom_packets logging.basicConfig(level=logging.ERROR) @@ -39,7 +41,7 @@ def generate_xarray(packet_file: str, xtce: str): "COD_LO": "COD_LO_ACQ", "COD_HI": "COD_HI_ACQ", "SWE": "SWE_ACQ_SEC", - "SWAPI": "SWAPI_ACQ" + "SWAPI": "SWAPI_ACQ", } instruments = list(time_keys.keys()) @@ -66,9 +68,13 @@ def generate_xarray(packet_file: str, xtce: str): # Generate xarray dataset for each instrument and spacecraft datasets = {} for inst in instruments: - dataset_dict = {key: (time_keys[inst], data_storage[inst][key]) - for key in data_storage[inst] if key != time_keys[inst]} - datasets[inst] = xr.Dataset(dataset_dict, coords={ - time_keys[inst]: data_storage[inst][time_keys[inst]]}) + dataset_dict = { + key: (time_keys[inst], data_storage[inst][key]) + for key in data_storage[inst] + if key != time_keys[inst] + } + datasets[inst] = xr.Dataset( + dataset_dict, coords={time_keys[inst]: data_storage[inst][time_keys[inst]]} + ) - return datasets \ No newline at end of file + return datasets diff --git a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py index eda2fd740..f7345da7b 100644 --- a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py +++ b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py @@ -1,12 +1,11 @@ +import tempfile from pathlib import Path import pytest -import tempfile -from imap_processing.ialirt.l0.decom_ialirt import generate_xarray -from imap_processing.decom import decom_packets from imap_processing import imap_module_directory - +from imap_processing.decom import decom_packets +from imap_processing.ialirt.l0.decom_ialirt import generate_xarray IALIRT_PACKET_LENGTH = 1464 @@ -14,8 +13,7 @@ @pytest.fixture(scope="session") def xtce_ialirt_path(): """Returns the xtce auxiliary directory.""" - return imap_module_directory / 'ialirt' / 'packet_definitions' \ - / "ialirt.xml" + return imap_module_directory / "ialirt" / "packet_definitions" / "ialirt.xml" @pytest.fixture(scope="session") @@ -25,26 +23,33 @@ def binary_packet_path(): of the actual operational environment. The binary file is deleted after the test session. """ - packet_path = imap_module_directory / 'ialirt' / 'tests' / 'test_data' / 'l0' / \ - 'IALiRT Raw Packet Telemetry.txt' + packet_path = ( + imap_module_directory + / "ialirt" + / "tests" + / "test_data" + / "l0" + / "IALiRT Raw Packet Telemetry.txt" + ) with tempfile.NamedTemporaryFile(delete=False) as tmp_file: binary_file_path = Path(tmp_file.name) - with open(packet_path, 'r') as text_file, open(binary_file_path, 'wb') as binary_file: + with open(packet_path) as text_file, open(binary_file_path, "wb") as binary_file: for line in text_file: if not line.startswith("#"): # Split the line by semicolons # Discard the first value since it is only a counter hex_values = line.strip().split(";")[1:] # Convert hex to binary - binary_data = bytearray.fromhex(''.join(hex_values)) + binary_data = bytearray.fromhex("".join(hex_values)) binary_file.write(binary_data) yield binary_file_path binary_file_path.unlink() + @pytest.fixture(scope="session") def empty_binary_packet_path(): """ @@ -52,20 +57,28 @@ def empty_binary_packet_path(): of the actual operational environment. The binary file is deleted after the test session. """ - empty_packet_path = imap_module_directory / 'ialirt' / 'tests' / 'test_data' / 'l0' / \ - 'Empty IALiRT Raw Packet Telemetry.txt' + empty_packet_path = ( + imap_module_directory + / "ialirt" + / "tests" + / "test_data" + / "l0" + / "Empty IALiRT Raw Packet Telemetry.txt" + ) with tempfile.NamedTemporaryFile(delete=False) as tmp_file: binary_file_path = Path(tmp_file.name) - with open(empty_packet_path, 'r') as text_file, open(binary_file_path, 'wb') as binary_file: + with open(empty_packet_path) as text_file, open( + binary_file_path, "wb" + ) as binary_file: for line in text_file: if not line.startswith("#"): # Split the line by semicolons # Discard the first value since it is only a counter hex_values = line.strip().split(";")[1:] # Convert hex to binary - binary_data = bytearray.fromhex(''.join(hex_values)) + binary_data = bytearray.fromhex("".join(hex_values)) binary_file.write(binary_data) yield binary_file_path @@ -92,20 +105,26 @@ def test_binary_value_length(): of the actual operational environment. The binary file is deleted after the test session. """ - packet_path = imap_module_directory / 'ialirt' / 'tests' / 'test_data' / 'l0' / \ - 'IALiRT Raw Packet Telemetry.txt' + packet_path = ( + imap_module_directory + / "ialirt" + / "tests" + / "test_data" + / "l0" + / "IALiRT Raw Packet Telemetry.txt" + ) with tempfile.NamedTemporaryFile(delete=False) as tmp_file: binary_file_path = Path(tmp_file.name) - with open(packet_path, 'r') as text_file, open(binary_file_path, 'wb') as binary_file: + with open(packet_path) as text_file, open(binary_file_path, "wb"): for line in text_file: if not line.startswith("#"): # Split the line by semicolons # Discard the first value since it is only a counter hex_values = line.strip().split(";")[1:] # Convert hex to binary - binary_data = bytearray.fromhex(''.join(hex_values)) + binary_data = bytearray.fromhex("".join(hex_values)) assert len(binary_data) * 8 == IALIRT_PACKET_LENGTH @@ -122,34 +141,33 @@ def test_enumerated(decom_packets_data): """Test if enumerated values derived correctly""" for packet in decom_packets_data: - - assert packet.data["SC_SWAPI_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_MAG_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_HIT_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_CODICE_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_LO_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_HI_45_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_HI_90_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_ULTRA_45_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_ULTRA_90_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_SWE_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_IDEX_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_GLOWS_STATUS"].derived_value == 'NOT_OPERATIONAL' - assert packet.data["SC_SPINPERIODVALID"].derived_value == 'INVALID' - assert packet.data["SC_SPINPHASEVALID"].derived_value == 'INVALID' - assert packet.data["SC_ATTITUDE"].derived_value == 'SUNSENSOR' - assert packet.data["SC_CATBEDHEATERFLAG"].derived_value == 'ON' - assert packet.data["SC_AUTONOMY"].derived_value == 'OPERATIONAL' - assert packet.data["HIT_STATUS"].derived_value == 'OFF-NOMINAL' - assert packet.data["SWE_NOM_FLAG"].derived_value == 'OFF-NOMINAL' - assert packet.data["SWE_OPS_FLAG"].derived_value == 'NON-HVSCI' + assert packet.data["SC_SWAPI_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_MAG_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_HIT_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_CODICE_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_LO_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_HI_45_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_HI_90_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_ULTRA_45_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_ULTRA_90_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_SWE_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_IDEX_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_GLOWS_STATUS"].derived_value == "NOT_OPERATIONAL" + assert packet.data["SC_SPINPERIODVALID"].derived_value == "INVALID" + assert packet.data["SC_SPINPHASEVALID"].derived_value == "INVALID" + assert packet.data["SC_ATTITUDE"].derived_value == "SUNSENSOR" + assert packet.data["SC_CATBEDHEATERFLAG"].derived_value == "ON" + assert packet.data["SC_AUTONOMY"].derived_value == "OPERATIONAL" + assert packet.data["HIT_STATUS"].derived_value == "OFF-NOMINAL" + assert packet.data["SWE_NOM_FLAG"].derived_value == "OFF-NOMINAL" + assert packet.data["SWE_OPS_FLAG"].derived_value == "NON-HVSCI" def test_generate_xarray(binary_packet_path, xtce_ialirt_path, decom_packets_data): """This function checks that all instrument parameters are accounted for.""" instrument_lengths = {} - instruments = ['SC', 'HIT', 'MAG', 'COD_LO', 'COD_HI', 'SWE', 'SWAPI'] + instruments = ["SC", "HIT", "MAG", "COD_LO", "COD_HI", "SWE", "SWAPI"] xarray_data = generate_xarray(binary_packet_path, xtce_ialirt_path) @@ -167,16 +185,16 @@ def test_generate_xarray(binary_packet_path, xtce_ialirt_path, decom_packets_dat # Assert that the instrument parameters from the xarray are # a subset of the packet data - assert instrument_list_set.issubset(packet_data_keys_set) == True + assert instrument_list_set.issubset(packet_data_keys_set) is True # Assert that the length of parameters is the same # between packet data and generated xarray assert sum(instrument_lengths.values()) == len( - list(decom_packets_data[0].data.keys())) + list(decom_packets_data[0].data.keys()) + ) # Check that all the dimensions are the correct length # example:len(xarray_data['HIT'].coords['HIT_SC_TICK'].values) == 32 for instrument in instruments: dimension_name = next(iter(xarray_data[instrument].dims)) - assert len( - xarray_data[instrument].coords[dimension_name].values) == 32 + assert len(xarray_data[instrument].coords[dimension_name].values) == 32 From 82f355bf9baeceabc320c336201ff7b8771065db Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Thu, 2 Nov 2023 17:43:43 -0600 Subject: [PATCH 12/21] xml update --- imap_processing/ialirt/packet_definitions/ialirt.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imap_processing/ialirt/packet_definitions/ialirt.xml b/imap_processing/ialirt/packet_definitions/ialirt.xml index da156687d..87ceed20e 100644 --- a/imap_processing/ialirt/packet_definitions/ialirt.xml +++ b/imap_processing/ialirt/packet_definitions/ialirt.xml @@ -235,7 +235,7 @@ CCSDS Packet Application Process ID - + CCSDS Packet Grouping Flags (3=not part of group) @@ -648,7 +648,7 @@ - + From f7ba8ce506b1aad0fd561d70615a254dde5e82a2 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Thu, 2 Nov 2023 18:16:33 -0600 Subject: [PATCH 13/21] update to xml --- imap_processing/ialirt/packet_definitions/ialirt.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/imap_processing/ialirt/packet_definitions/ialirt.xml b/imap_processing/ialirt/packet_definitions/ialirt.xml index 87ceed20e..f326710b0 100644 --- a/imap_processing/ialirt/packet_definitions/ialirt.xml +++ b/imap_processing/ialirt/packet_definitions/ialirt.xml @@ -641,9 +641,8 @@ - + - From 89543d56023585b96f0b0a4b4f3aba183e080a34 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 16:01:25 +0000 Subject: [PATCH 14/21] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- imap_processing/ialirt/l0/decom_ialirt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py index b8167d61c..679c18e2f 100644 --- a/imap_processing/ialirt/l0/decom_ialirt.py +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -29,7 +29,7 @@ def generate_xarray(packet_file: str, xtce: str): try: packets = decom_packets(packet_file, xtce) except Exception as e: - logger.error(f"Error during packet decomposition: {str(e)}") + logger.error(f"Error during packet decomposition: {e!s}") return logger.info(f"Decommutated {len(packets)} packets from {packet_file}.") From 11c064e6b86d7c553d0884855754175c6c2cba03 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Mon, 6 Nov 2023 10:11:11 -0700 Subject: [PATCH 15/21] response to pr --- imap_processing/ialirt/l0/decom_ialirt.py | 26 +++++++++++++++---- .../ialirt/tests/unit/test_decom_ialirt.py | 5 ++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py index 679c18e2f..e4f4b9d8c 100644 --- a/imap_processing/ialirt/l0/decom_ialirt.py +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -25,6 +25,22 @@ def generate_xarray(packet_file: str, xtce: str): xr.Dataset A dataset containing the decoded data fields with 'time' as the coordinating dimension. + + Example Output: + --------------- + # This is an example of what the xarray dataset might look like + # after being processed by this function. + + + Dimensions: (SC_SCLK_SEC: 5) + Coordinates: + * SC_SCLK_SEC (SC_SCLK_SEC) int64 322168 322169 322170 322171 322172 + Data variables: + SC_MAG_STATUS (SC_SCLK_SEC) int64 0 1 0 1 0 + SC_HIT_STATUS (SC_SCLK_SEC) int64 1 0 1 0 1 + + This example shows a dataset with 'SC_SCLK_SEC' as the coordinate + and two data variables 'SC_MAG_STATUS' and 'SC_HIT_STATUS'. """ try: packets = decom_packets(packet_file, xtce) @@ -54,16 +70,16 @@ def generate_xarray(packet_file: str, xtce: str): key_matched = False for inst in instruments: if key.startswith(inst): - # Directly append to the list without checking if the key exists + # Directly append to the list data_storage[inst][key].append(value.derived_value) key_matched = True break - if not key_matched: - # If after checking all instruments, none match, then log a warning - logger.warning(f"Unexpected key '{key}' found in packet data.") + if not key_matched: + # If after checking all instruments, none match, raise an error. + raise ValueError(f"Unexpected key '{key}' found in packet data.") - logger.debug("Generating datasets for each instrument.") + logger.info("Generating datasets for each instrument.") # Generate xarray dataset for each instrument and spacecraft datasets = {} diff --git a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py index f7345da7b..d149aed57 100644 --- a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py +++ b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py @@ -101,9 +101,8 @@ def test_length(decom_packets_data): def test_binary_value_length(): """ - Creates a binary file from the text packet data, which is more representative - of the actual operational environment. The binary file is deleted after the - test session. + Validates the length of binary data converted + from a text file containing hexadecimal packet data. """ packet_path = ( imap_module_directory From e5e43ccd6b56e50007d1fe3a199b26bde8d9d0d1 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Mon, 6 Nov 2023 10:18:26 -0700 Subject: [PATCH 16/21] update to xml comments --- .../ialirt/packet_definitions/ialirt.xml | 30 ++----------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/imap_processing/ialirt/packet_definitions/ialirt.xml b/imap_processing/ialirt/packet_definitions/ialirt.xml index f326710b0..ddca26663 100644 --- a/imap_processing/ialirt/packet_definitions/ialirt.xml +++ b/imap_processing/ialirt/packet_definitions/ialirt.xml @@ -3,34 +3,8 @@ - From ce5d5a6a083f4d72540bc1f4329cae6935245475 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Mon, 6 Nov 2023 13:02:33 -0700 Subject: [PATCH 17/21] added additional test --- imap_processing/ialirt/l0/decom_ialirt.py | 23 +++++++++++-------- .../ialirt/tests/unit/test_decom_ialirt.py | 20 ++++++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py index e4f4b9d8c..e1432e43d 100644 --- a/imap_processing/ialirt/l0/decom_ialirt.py +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -9,7 +9,7 @@ logger = logging.getLogger(__name__) -def generate_xarray(packet_file: str, xtce: str): +def generate_xarray(packet_file: str, xtce: str, time_keys=None): """ Generate xarray from unpacked data. @@ -19,6 +19,8 @@ def generate_xarray(packet_file: str, xtce: str): Path to the CCSDS data packet file. xtce : str Path to the XTCE packet definition file. + time_keys : dict + Keys used for creating xarray dataset Returns ------- @@ -50,15 +52,16 @@ def generate_xarray(packet_file: str, xtce: str): logger.info(f"Decommutated {len(packets)} packets from {packet_file}.") - time_keys = { - "SC": "SC_SCLK_SEC", - "HIT": "HIT_SC_TICK", - "MAG": "MAG_ACQ", - "COD_LO": "COD_LO_ACQ", - "COD_HI": "COD_HI_ACQ", - "SWE": "SWE_ACQ_SEC", - "SWAPI": "SWAPI_ACQ", - } + if time_keys is None: + time_keys = { + "SC": "SC_SCLK_SEC", + "HIT": "HIT_SC_TICK", + "MAG": "MAG_ACQ", + "COD_LO": "COD_LO_ACQ", + "COD_HI": "COD_HI_ACQ", + "SWE": "SWE_ACQ_SEC", + "SWAPI": "SWAPI_ACQ", + } instruments = list(time_keys.keys()) diff --git a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py index d149aed57..6d5bd952c 100644 --- a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py +++ b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py @@ -197,3 +197,23 @@ def test_generate_xarray(binary_packet_path, xtce_ialirt_path, decom_packets_dat for instrument in instruments: dimension_name = next(iter(xarray_data[instrument].dims)) assert len(xarray_data[instrument].coords[dimension_name].values) == 32 + + +def test_unexpected_key(binary_packet_path, xtce_ialirt_path, decom_packets_data): + """ + This function tests that a ValueError is raised when an unexpected + key is encountered. + """ + + time_keys = { + "UNEXPECTED": "SC_SCLK_SEC", + "HIT": "HIT_SC_TICK", + "MAG": "MAG_ACQ", + "COD_LO": "COD_LO_ACQ", + "COD_HI": "COD_HI_ACQ", + "SWE": "SWE_ACQ_SEC", + "SWAPI": "SWAPI_ACQ", + } + + with pytest.raises(ValueError, match=r"Unexpected key '.*' found in packet data."): + generate_xarray(binary_packet_path, xtce_ialirt_path, time_keys=time_keys) From 8f6d69aca5e72384d48d1391f61e871ac8d260b6 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Mon, 6 Nov 2023 13:20:20 -0700 Subject: [PATCH 18/21] appease codecov --- .../ialirt/tests/unit/test_decom_ialirt.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py index 6d5bd952c..5b65da292 100644 --- a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py +++ b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py @@ -73,13 +73,12 @@ def empty_binary_packet_path(): binary_file_path, "wb" ) as binary_file: for line in text_file: - if not line.startswith("#"): - # Split the line by semicolons - # Discard the first value since it is only a counter - hex_values = line.strip().split(";")[1:] - # Convert hex to binary - binary_data = bytearray.fromhex("".join(hex_values)) - binary_file.write(binary_data) + # Split the line by semicolons + # Discard the first value since it is only a counter + hex_values = line.strip().split(";")[1:] + # Convert hex to binary + binary_data = bytearray.fromhex("".join(hex_values)) + binary_file.write(binary_data) yield binary_file_path From e74bfb4e76a3335b3f264fb5ce846ccd3d211380 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Mon, 6 Nov 2023 13:24:58 -0700 Subject: [PATCH 19/21] appease codecov --- .../ialirt/tests/unit/test_decom_ialirt.py | 25 ++----------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py index 5b65da292..940462f0e 100644 --- a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py +++ b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py @@ -53,33 +53,12 @@ def binary_packet_path(): @pytest.fixture(scope="session") def empty_binary_packet_path(): """ - Creates a empty binary file from the text packet data, which is more representative - of the actual operational environment. The binary file is deleted after the - test session. + Creates an empty binary file, representative of a scenario + in which no packet data is available. """ - empty_packet_path = ( - imap_module_directory - / "ialirt" - / "tests" - / "test_data" - / "l0" - / "Empty IALiRT Raw Packet Telemetry.txt" - ) - with tempfile.NamedTemporaryFile(delete=False) as tmp_file: binary_file_path = Path(tmp_file.name) - with open(empty_packet_path) as text_file, open( - binary_file_path, "wb" - ) as binary_file: - for line in text_file: - # Split the line by semicolons - # Discard the first value since it is only a counter - hex_values = line.strip().split(";")[1:] - # Convert hex to binary - binary_data = bytearray.fromhex("".join(hex_values)) - binary_file.write(binary_data) - yield binary_file_path binary_file_path.unlink() From 2778c49c62ef2121925db21c535ec35f59ee9d43 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Mon, 6 Nov 2023 13:25:33 -0700 Subject: [PATCH 20/21] appease codecov --- .../tests/test_data/l0/Empty IALiRT Raw Packet Telemetry.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 imap_processing/ialirt/tests/test_data/l0/Empty IALiRT Raw Packet Telemetry.txt diff --git a/imap_processing/ialirt/tests/test_data/l0/Empty IALiRT Raw Packet Telemetry.txt b/imap_processing/ialirt/tests/test_data/l0/Empty IALiRT Raw Packet Telemetry.txt deleted file mode 100644 index e69de29bb..000000000 From 9d61fccd542207b2ea6ca7316e052e795666cb26 Mon Sep 17 00:00:00 2001 From: Laura Sandoval Date: Wed, 8 Nov 2023 08:41:25 -0700 Subject: [PATCH 21/21] pr response --- imap_processing/ialirt/l0/decom_ialirt.py | 6 +- .../ialirt/tests/unit/test_decom_ialirt.py | 76 +++++-------------- 2 files changed, 19 insertions(+), 63 deletions(-) diff --git a/imap_processing/ialirt/l0/decom_ialirt.py b/imap_processing/ialirt/l0/decom_ialirt.py index e1432e43d..5861c3586 100644 --- a/imap_processing/ialirt/l0/decom_ialirt.py +++ b/imap_processing/ialirt/l0/decom_ialirt.py @@ -44,11 +44,7 @@ def generate_xarray(packet_file: str, xtce: str, time_keys=None): This example shows a dataset with 'SC_SCLK_SEC' as the coordinate and two data variables 'SC_MAG_STATUS' and 'SC_HIT_STATUS'. """ - try: - packets = decom_packets(packet_file, xtce) - except Exception as e: - logger.error(f"Error during packet decomposition: {e!s}") - return + packets = decom_packets(packet_file, xtce) logger.info(f"Decommutated {len(packets)} packets from {packet_file}.") diff --git a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py index 940462f0e..d20dc0033 100644 --- a/imap_processing/ialirt/tests/unit/test_decom_ialirt.py +++ b/imap_processing/ialirt/tests/unit/test_decom_ialirt.py @@ -1,6 +1,3 @@ -import tempfile -from pathlib import Path - import pytest from imap_processing import imap_module_directory @@ -16,8 +13,8 @@ def xtce_ialirt_path(): return imap_module_directory / "ialirt" / "packet_definitions" / "ialirt.xml" -@pytest.fixture(scope="session") -def binary_packet_path(): +@pytest.fixture() +def binary_packet_path(tmp_path): """ Creates a binary file from the text packet data, which is more representative of the actual operational environment. The binary file is deleted after the @@ -32,8 +29,7 @@ def binary_packet_path(): / "IALiRT Raw Packet Telemetry.txt" ) - with tempfile.NamedTemporaryFile(delete=False) as tmp_file: - binary_file_path = Path(tmp_file.name) + binary_file_path = tmp_path / "file.ccsds" with open(packet_path) as text_file, open(binary_file_path, "wb") as binary_file: for line in text_file: @@ -44,27 +40,14 @@ def binary_packet_path(): # Convert hex to binary binary_data = bytearray.fromhex("".join(hex_values)) binary_file.write(binary_data) + assert len(binary_data) * 8 == IALIRT_PACKET_LENGTH yield binary_file_path - binary_file_path.unlink() - - -@pytest.fixture(scope="session") -def empty_binary_packet_path(): - """ - Creates an empty binary file, representative of a scenario - in which no packet data is available. - """ - with tempfile.NamedTemporaryFile(delete=False) as tmp_file: - binary_file_path = Path(tmp_file.name) - - yield binary_file_path - - binary_file_path.unlink() + return binary_file_path -@pytest.fixture(scope="session") +@pytest.fixture() def decom_packets_data(binary_packet_path, xtce_ialirt_path): """Read packet data from file using decom_packets""" data_packet_list = decom_packets(binary_packet_path, xtce_ialirt_path) @@ -77,41 +60,18 @@ def test_length(decom_packets_data): assert len(decom_packets_data) == total_packets -def test_binary_value_length(): - """ - Validates the length of binary data converted - from a text file containing hexadecimal packet data. - """ - packet_path = ( - imap_module_directory - / "ialirt" - / "tests" - / "test_data" - / "l0" - / "IALiRT Raw Packet Telemetry.txt" - ) +def test_generate_xarray_empty_file(tmp_path, xtce_ialirt_path): + """Test that an error is raised if an empty file is passed to generate_xarray.""" - with tempfile.NamedTemporaryFile(delete=False) as tmp_file: - binary_file_path = Path(tmp_file.name) + binary_file_path = tmp_path / "empty.ccsds" + binary_file_path.touch() - with open(packet_path) as text_file, open(binary_file_path, "wb"): - for line in text_file: - if not line.startswith("#"): - # Split the line by semicolons - # Discard the first value since it is only a counter - hex_values = line.strip().split(";")[1:] - # Convert hex to binary - binary_data = bytearray.fromhex("".join(hex_values)) - assert len(binary_data) * 8 == IALIRT_PACKET_LENGTH - - -def test_generate_xarray_empty_file(empty_binary_packet_path, xtce_ialirt_path, caplog): - """Test that an error is logged if an empty file is passed to generate_xarray.""" - - result = generate_xarray(empty_binary_packet_path, xtce_ialirt_path) - - assert "Error during packet decomposition" in caplog.text - assert result is None + expected_error_msg = ( + "Reading off the end of the data. " + "Tried to read .* bits when only 0 available." + ) + with pytest.raises(Exception, match=expected_error_msg): + generate_xarray(binary_file_path, xtce_ialirt_path) def test_enumerated(decom_packets_data): @@ -173,8 +133,8 @@ def test_generate_xarray(binary_packet_path, xtce_ialirt_path, decom_packets_dat # Check that all the dimensions are the correct length # example:len(xarray_data['HIT'].coords['HIT_SC_TICK'].values) == 32 for instrument in instruments: - dimension_name = next(iter(xarray_data[instrument].dims)) - assert len(xarray_data[instrument].coords[dimension_name].values) == 32 + for dimension_name in xarray_data[instrument].dims: + assert len(xarray_data[instrument].coords[dimension_name].values) == 32 def test_unexpected_key(binary_packet_path, xtce_ialirt_path, decom_packets_data):