mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
- Fix crash in MSG decoder on Windows - Add abort button to official products downloader - Move ui-scale to style, where it belongs - Fix a pile of compiler warnings
379 lines
No EOL
16 KiB
C++
379 lines
No EOL
16 KiB
C++
#include "modis_reader.h"
|
|
|
|
#include <map>
|
|
#include "common/ccsds/ccsds_time.h"
|
|
#include "common/repack.h"
|
|
|
|
#include "logger.h"
|
|
|
|
namespace eos
|
|
{
|
|
namespace modis
|
|
{
|
|
MODISReader::MODISReader()
|
|
{
|
|
for (int i = 0; i < 31; i++)
|
|
channels1000m[i].resize(1354 * 10);
|
|
for (int i = 0; i < 5; i++)
|
|
channels500m[i].resize(1354 * 2 * 20);
|
|
for (int i = 0; i < 2; i++)
|
|
channels250m[i].resize(1354 * 4 * 40);
|
|
lines = 0;
|
|
day_count = 0;
|
|
night_count = 0;
|
|
}
|
|
|
|
MODISReader::~MODISReader()
|
|
{
|
|
for (int i = 0; i < 31; i++)
|
|
channels1000m[i].clear();
|
|
for (int i = 0; i < 5; i++)
|
|
channels500m[i].clear();
|
|
for (int i = 0; i < 2; i++)
|
|
channels250m[i].clear();
|
|
}
|
|
|
|
/*
|
|
The official MODIS User Guide states this is an "exclusive-or checksum",
|
|
but that did not lead to any useful results.
|
|
|
|
Looking online, I was however able to find a working and proper
|
|
implementation :
|
|
https://oceancolor.gsfc.nasa.gov/docs/ocssw/check__checksum_8c_source.html
|
|
|
|
In the code linked above, the proper specification is :
|
|
-------------------------------------------------
|
|
82 FYI, The checksum is computed as follows:
|
|
83 1: Within each packet, the 12-bit science data (or test data)
|
|
84 is summed into a 16-bit register, with overflows ignored.
|
|
85 2: After all the data is summed, the 16-bit result is right
|
|
86 shifted four bits, with zeros inserted into the leading
|
|
87 four bits.
|
|
88 3: The 12 bits left in the lower end of the word becomes the
|
|
89 checksum.
|
|
-------------------------------------------------
|
|
|
|
The documentation is hence... Not so helpful with this :-)
|
|
*/
|
|
uint16_t MODISReader::compute_crc(uint16_t *data, int size)
|
|
{
|
|
uint16_t crc = 0;
|
|
for (int i = 0; i < size; i++)
|
|
crc += data[i];
|
|
crc >>= 4;
|
|
return crc;
|
|
}
|
|
|
|
void MODISReader::processDayPacket(ccsds::CCSDSPacket &packet, MODISHeader &header)
|
|
{
|
|
repackBytesTo12bits(&packet.payload[12], 624, modis_ifov);
|
|
|
|
// Check CRC
|
|
if (compute_crc(modis_ifov, 415) != modis_ifov[415])
|
|
return;
|
|
|
|
// Filter out calibration packets, and process them
|
|
if (header.type_flag == 1)
|
|
{
|
|
for (int i = 0; i < 415; i++)
|
|
{
|
|
int i_off = (packet.header.sequence_flag == 2 ? 415 : 0) + i;
|
|
if (header.calib_type == MODISHeader::SOLAR_DIFFUSER_SOURCE)
|
|
d_calib[lines / 10]["solar_diffuser_source"][header.calib_frame_count][i_off] = modis_ifov[i];
|
|
else if (header.calib_type == MODISHeader::SRCA_CALIB_SOURCE)
|
|
d_calib[lines / 10]["srca_diffuser_source"][header.calib_frame_count][i_off] = modis_ifov[i];
|
|
else if (header.calib_type == MODISHeader::BLACKBODY_SOURCE)
|
|
d_calib[lines / 10]["blackbody_source"][header.calib_frame_count][i_off] = modis_ifov[i];
|
|
else if (header.calib_type == MODISHeader::SPACE_SOURCE)
|
|
d_calib[lines / 10]["space_source"][header.calib_frame_count][i_off] = modis_ifov[i];
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Filter out bad packets
|
|
if (header.earth_frame_data_count > 1354 /*|| header.mirror_side > 1*/)
|
|
return;
|
|
|
|
// std::cout << (int)packet.header.sequence_flag << " " << (int)header.earth_frame_data_count << std::endl;
|
|
|
|
int position = header.earth_frame_data_count - 1;
|
|
|
|
if (position == 0 && packet.header.sequence_flag == 1 && lastScanCount != header.scan_count)
|
|
{
|
|
lines += 10;
|
|
|
|
for (int i = 0; i < 31; i++)
|
|
channels1000m[i].resize((lines + 10) * 1354);
|
|
for (int i = 0; i < 5; i++)
|
|
channels500m[i].resize((lines * 2 + 20) * 1354 * 2);
|
|
for (int i = 0; i < 2; i++)
|
|
channels250m[i].resize((lines * 4 + 40) * 1354 * 4);
|
|
|
|
double timestamp = ccsds::parseCCSDSTimeFull(packet, -4383);
|
|
for (int i = -5; i < 5; i++)
|
|
timestamps_1000.push_back(timestamp + i * 0.162); // 1000m timestamps
|
|
for (int i = -10; i < 10; i++)
|
|
timestamps_500.push_back(timestamp + i * 0.081); // 500m timestamps
|
|
for (int i = -20; i < 20; i++)
|
|
timestamps_250.push_back(timestamp + i * 0.0405); // 250m timestamps
|
|
}
|
|
|
|
lastScanCount = header.scan_count;
|
|
|
|
if (packet.header.sequence_flag == 1) // Contains IFOVs 1-5
|
|
{
|
|
// Channel 1-2 (250m)
|
|
for (int c = 0; c < 2; c++)
|
|
for (int i = 0; i < 4; i++)
|
|
for (int y = 0; y < 4; y++)
|
|
for (int f = 0; f < 5; f++)
|
|
channels250m[c][((lines + 5 + f) * 4 + (3 - y)) * (1354 * 4) + position * 4 + i] = modis_ifov[(4 - f) * 83 + (c * 16) + (i * 4) + y] << 4;
|
|
|
|
// Channel 3-7 (500m)
|
|
for (int c = 0; c < 5; c++)
|
|
for (int i = 0; i < 2; i++)
|
|
for (int y = 0; y < 2; y++)
|
|
for (int f = 0; f < 5; f++)
|
|
channels500m[c][((lines + 5 + f) * 2 + (1 - y)) * (1354 * 2) + position * 2 + i] = modis_ifov[(4 - f) * 83 + 32 + (c * 4) + (i * 2) + y] << 4;
|
|
|
|
// 8-38 1000m channels
|
|
for (int i = 0; i < 31; i++)
|
|
for (int f = 0; f < 5; f++)
|
|
channels1000m[i][(lines + 5 + f) * 1354 + position] = modis_ifov[(4 - f) * 83 + 52 + i] << 4;
|
|
}
|
|
else if (packet.header.sequence_flag == 2) // Contains IFOVs 6-10
|
|
{
|
|
// Channel 1-2 (250m)
|
|
for (int c = 0; c < 2; c++)
|
|
for (int i = 0; i < 4; i++)
|
|
for (int y = 0; y < 4; y++)
|
|
for (int f = 0; f < 5; f++)
|
|
channels250m[c][((lines + f) * 4 + (3 - y)) * (1354 * 4) + position * 4 + i] = modis_ifov[(4 - f) * 83 + (c * 16) + (i * 4) + y] << 4;
|
|
|
|
// Channel 3-7 (500m)
|
|
for (int c = 0; c < 5; c++)
|
|
for (int i = 0; i < 2; i++)
|
|
for (int y = 0; y < 2; y++)
|
|
for (int f = 0; f < 5; f++)
|
|
channels500m[c][((lines + f) * 2 + (1 - y)) * (1354 * 2) + position * 2 + i] = modis_ifov[(4 - f) * 83 + 32 + (c * 4) + (i * 2) + y] << 4;
|
|
|
|
// 8-38 1000m channels
|
|
for (int i = 0; i < 31; i++)
|
|
for (int f = 0; f < 5; f++)
|
|
channels1000m[i][(lines + f) * 1354 + position] = modis_ifov[(4 - f) * 83 + 52 + i] << 4;
|
|
}
|
|
|
|
fillCalib(header);
|
|
}
|
|
|
|
void MODISReader::processNightPacket(ccsds::CCSDSPacket &packet, MODISHeader &header)
|
|
{
|
|
repackBytesTo12bits(&packet.payload[12], 258, modis_ifov);
|
|
|
|
// Check CRC
|
|
if (compute_crc(modis_ifov, 171) != modis_ifov[171])
|
|
return;
|
|
|
|
// Filter out calibration packets. They're always day!
|
|
if (header.type_flag == 1)
|
|
return;
|
|
|
|
// Filter out bad packets
|
|
if (header.earth_frame_data_count > 1354 /*|| header.mirror_side > 1*/)
|
|
return;
|
|
|
|
// std::cout << (int)packet.header.sequence_flag << " " << (int)header.earth_frame_data_count << std::endl;
|
|
|
|
int position = header.earth_frame_data_count - 1;
|
|
|
|
if (position == 0 && lastScanCount != header.scan_count)
|
|
{
|
|
lines += 10;
|
|
|
|
for (int i = 0; i < 31; i++)
|
|
channels1000m[i].resize((lines + 10) * 1354);
|
|
for (int i = 0; i < 5; i++)
|
|
channels500m[i].resize((lines * 2 + 20) * 1354 * 2);
|
|
for (int i = 0; i < 2; i++)
|
|
channels250m[i].resize((lines * 4 + 40) * 1354 * 4);
|
|
|
|
double timestamp = ccsds::parseCCSDSTimeFull(packet, -4383);
|
|
for (int i = -5; i < 5; i++)
|
|
timestamps_1000.push_back(timestamp + i * 0.162); // 1000m timestamps
|
|
for (int i = -10; i < 10; i++)
|
|
timestamps_500.push_back(timestamp + i * 0.081); // 500m timestamps
|
|
for (int i = -20; i < 20; i++)
|
|
timestamps_250.push_back(timestamp + i * 0.0405); // 250m timestamps
|
|
}
|
|
|
|
lastScanCount = header.scan_count;
|
|
|
|
// 28 1000m channels
|
|
for (int i = 0; i < 17; i++)
|
|
for (int f = 0; f < 10; f++)
|
|
channels1000m[14 + i][(lines + f) * 1354 + position] = modis_ifov[(9 - f) * 17 + i] << 4;
|
|
|
|
fillCalib(header);
|
|
}
|
|
|
|
void MODISReader::fillCalib(MODISHeader &header)
|
|
{
|
|
d_calib[lines / 10]["night_group"] = header.packet_type == MODISHeader::NIGHT_GROUP;
|
|
d_calib[lines / 10]["mirror_side"] = header.mirror_side;
|
|
for (int i = 0; i < 12; i++)
|
|
d_calib[lines / 10]["bb_temp"][i] = last_obc_bb_temp[i];
|
|
for (int i = 0; i < 2; i++)
|
|
d_calib[lines / 10]["mir_temp"][i] = last_rct_mir_temp[i];
|
|
for (int i = 0; i < 4; i++)
|
|
d_calib[lines / 10]["cav_temp"][i] = last_cav_temp[i];
|
|
for (int i = 0; i < 4; i++)
|
|
d_calib[lines / 10]["inst_temp"][i] = last_ao_inst_temp[i];
|
|
for (int i = 0; i < 4; i++)
|
|
d_calib[lines / 10]["fp_temp"][i] = last_fp_temp[i];
|
|
for (int i = 0; i < 4; i++)
|
|
d_calib[lines / 10]["fp_temp_info"][i] = last_cr_rc_info[i];
|
|
}
|
|
|
|
void MODISReader::work(ccsds::CCSDSPacket &packet)
|
|
{
|
|
// Filter out bad packets
|
|
if (packet.payload.size() < 10)
|
|
return;
|
|
|
|
MODISHeader modisHeader(packet);
|
|
|
|
if (modisHeader.packet_type == MODISHeader::DAY_GROUP)
|
|
{
|
|
if (packet.payload.size() < 636)
|
|
return;
|
|
|
|
day_count++;
|
|
processDayPacket(packet, modisHeader);
|
|
}
|
|
else if (modisHeader.packet_type == MODISHeader::NIGHT_GROUP)
|
|
{
|
|
if (packet.payload.size() < 270)
|
|
return;
|
|
|
|
night_count++;
|
|
processNightPacket(packet, modisHeader);
|
|
}
|
|
else if (modisHeader.packet_type == MODISHeader::ENG_GROUP_1)
|
|
{
|
|
// printf("ENG1!\n");
|
|
if (packet.payload.size() < 636)
|
|
return;
|
|
|
|
processEng1Packet(packet);
|
|
}
|
|
else if (modisHeader.packet_type == MODISHeader::ENG_GROUP_2)
|
|
{
|
|
// printf("ENG2!\n");
|
|
if (packet.payload.size() < 636)
|
|
return;
|
|
|
|
processEng2Packet(packet);
|
|
}
|
|
}
|
|
|
|
void MODISReader::processEng1Packet(ccsds::CCSDSPacket &packet)
|
|
{
|
|
// printf("ENG1 %d\n", packet.header.sequence_flag);
|
|
if (packet.header.sequence_flag == 1)
|
|
{
|
|
}
|
|
else if (packet.header.sequence_flag == 2)
|
|
{
|
|
repackBytesTo12bits(&packet.payload[298], 18, last_obc_bb_temp); // Obc BB Temp
|
|
last_rct_mir_temp[0] = (packet.payload[504] & 0xF) << 8 | packet.payload[505]; // TP_SA_RCT1_MIRE
|
|
last_rct_mir_temp[1] = packet.payload[506] << 4 | packet.payload[507] >> 4; // TP_SA_RCT2_MIRE
|
|
|
|
last_fp_temp[1] = (packet.payload[496] & 0b111111) << 6 | packet.payload[497] >> 2; // TA_AO_NIR_FPAE
|
|
last_fp_temp[0] = (packet.payload[497] & 0b11) << 10 | packet.payload[498] << 2 | packet.payload[499] >> 6; // TA_AO_VIS_FPAE
|
|
last_fp_temp[3] = (packet.payload[499] & 0b111111) << 6 | packet.payload[500] >> 2; // TA_RC_LWIR_CFPAE
|
|
last_fp_temp[2] = (packet.payload[500] & 0b11) << 10 | packet.payload[501] << 2 | packet.payload[502] >> 6; // TA_RC_SMIR_CFPAE
|
|
}
|
|
}
|
|
|
|
void MODISReader::processEng2Packet(ccsds::CCSDSPacket &packet)
|
|
{
|
|
// printf("ENG2 %d\n", packet.header.sequence_flag);
|
|
if (packet.header.sequence_flag == 1)
|
|
{
|
|
auto func_m = [this](uint8_t *block_curr, int major_cycle_cnt)
|
|
{
|
|
if (major_cycle_cnt == 0)
|
|
{
|
|
uint16_t words_tp_ao[5 + 1];
|
|
repackBytesTo12bits(&block_curr[56], 8, words_tp_ao);
|
|
last_ao_inst_temp[0] = words_tp_ao[4]; // TP_AO_SMIR_OBJ
|
|
last_ao_inst_temp[1] = words_tp_ao[1]; // TP_AO_LWIR_OBJ
|
|
last_ao_inst_temp[2] = words_tp_ao[3]; // TP_AO_SMIR_LENS
|
|
last_ao_inst_temp[3] = words_tp_ao[0]; // TP_AO_LWIR_LENS
|
|
}
|
|
else if (major_cycle_cnt == 3)
|
|
{
|
|
last_cav_temp[0] = block_curr[56] << 1 | block_curr[57] >> 7; // TP_MF_CALBKHD_SR
|
|
last_cav_temp[3] = (block_curr[57] & 0b1111111) << 2 | block_curr[58] >> 6; // TP_MF_CVR_OP_SR
|
|
}
|
|
else if (major_cycle_cnt == 4)
|
|
{
|
|
last_cav_temp[2] = (block_curr[58] & 0b111111) << 3 | block_curr[59] >> 5; // TP_MF_Z_BKHD_BB
|
|
}
|
|
else if (major_cycle_cnt == 23)
|
|
{
|
|
last_cav_temp[1] = (block_curr[58] & 0b111111) << 3 | block_curr[59] >> 5; // TP_SR_SNOUT
|
|
}
|
|
|
|
if (major_cycle_cnt == 5 ||
|
|
major_cycle_cnt == 13 ||
|
|
major_cycle_cnt == 21 ||
|
|
major_cycle_cnt == 29 ||
|
|
major_cycle_cnt == 37 ||
|
|
major_cycle_cnt == 45 ||
|
|
major_cycle_cnt == 53 ||
|
|
major_cycle_cnt == 61)
|
|
{
|
|
last_cr_rc_info[0] = block_curr[43] >> 7; // CR_RC_CFPA_T1SET
|
|
last_cr_rc_info[1] = (block_curr[43] >> 6) & 1; // CR_RC_CFPA_T3SET
|
|
last_cr_rc_info[2] = (block_curr[43] >> 2) & 1; // CR_RC_LWHTR_ON
|
|
last_cr_rc_info[3] = (block_curr[44] >> 6) & 1; // CR_RC_SMHTR_ON
|
|
}
|
|
};
|
|
|
|
uint8_t *block_curr1 = &packet.payload[12];
|
|
uint8_t *block_curr2 = &packet.payload[12 + 64];
|
|
int major_cycle_cnt1 = block_curr1[0] >> 2;
|
|
int major_cycle_cnt2 = block_curr2[0] >> 2;
|
|
|
|
func_m(block_curr2, major_cycle_cnt2); // Prior
|
|
func_m(block_curr1, major_cycle_cnt1); // Current
|
|
|
|
// logger->critical("Major Cycle %d - %d", major_cycle_cnt1, major_cycle_cnt2);
|
|
}
|
|
else if (packet.header.sequence_flag == 2)
|
|
{
|
|
}
|
|
}
|
|
|
|
image::Image MODISReader::getImage250m(int channel)
|
|
{
|
|
return image::Image(channels250m[channel].data(), 16, 1354 * 4, lines * 4, 1);
|
|
}
|
|
|
|
image::Image MODISReader::getImage500m(int channel)
|
|
{
|
|
return image::Image(channels500m[channel].data(), 16, 1354 * 2, lines * 2, 1);
|
|
}
|
|
|
|
image::Image MODISReader::getImage1000m(int channel)
|
|
{
|
|
return image::Image(channels1000m[channel].data(), 16, 1354, lines, 1);
|
|
}
|
|
|
|
nlohmann::json MODISReader::getCalib()
|
|
{
|
|
return d_calib;
|
|
}
|
|
} // namespace modis
|
|
} // namespace eos
|