diff --git a/plugins/elektro_arktika_support/DecompWT/SmartPtr.h b/plugins/elektro_arktika_support/DecompWT/SmartPtr.h index 8cf64b985..57f0e08f0 100644 --- a/plugins/elektro_arktika_support/DecompWT/SmartPtr.h +++ b/plugins/elektro_arktika_support/DecompWT/SmartPtr.h @@ -22,16 +22,16 @@ namespace Util { /** - * thread safe pointer class -**/ + * thread safe pointer class + **/ template class CSmartPtr { private: /** - * Holds address of heap memory and maintains counter of references to it. -**/ + * Holds address of heap memory and maintains counter of references to it. + **/ class CCounted { private: @@ -40,8 +40,8 @@ namespace Util public: /** - * Stores address of heap memory, initializes number of references. -**/ + * Stores address of heap memory, initializes number of references. + **/ CCounted(T *i_Ptr) { m_Ptr = i_Ptr; @@ -49,30 +49,30 @@ namespace Util } /** - * Increments number of references. - **/ + * Increments number of references. + **/ void Use() { m_NumReferences++; } /** - * Decrements number of references,deletes itself when last reference dismisses. -**/ + * Decrements number of references,deletes itself when last reference dismisses. + **/ void Dismiss() { if (0 == --m_NumReferences) { - delete m_Ptr; - // delete this; + delete[] m_Ptr; // ORIGINAL WAS delete + // delete this; } } /** - * Returns heap memory address and set sets own copy of the address to NULL to prevent deletion. - * @returns - * Heap memory address -**/ + * Returns heap memory address and set sets own copy of the address to NULL to prevent deletion. + * @returns + * Heap memory address + **/ T *Release() { /** Return the heap memory address.**/ @@ -82,10 +82,10 @@ namespace Util } /** - * Operators to access the heap memory. - * @returns - * Address or value of dynamic object -**/ + * Operators to access the heap memory. + * @returns + * Address or value of dynamic object + **/ operator T &() const { return *m_Ptr; } operator T *() const { return m_Ptr; } T *operator->() const { return m_Ptr; } @@ -95,8 +95,8 @@ namespace Util public: /** - * constructor -**/ + * constructor + **/ explicit CSmartPtr( T *i_Ptr = NULL /** Start address of heap memory.**/ ) @@ -106,8 +106,8 @@ namespace Util } /** - * copy constructor -**/ + * copy constructor + **/ CSmartPtr( const CSmartPtr &i_Src /** Reference CSmartPtr.**/ ) @@ -117,18 +117,18 @@ namespace Util } /** - * destructor -**/ + * destructor + **/ ~CSmartPtr() { m_Counted->Dismiss(); } /** - * Assignment operator. - * @returns - * Reference to itself. -**/ + * Assignment operator. + * @returns + * Reference to itself. + **/ CSmartPtr &operator=( T *i_Ptr /** Start address of heap memory.**/ ) @@ -140,10 +140,10 @@ namespace Util } /** - * Assignment operator. - * @returns - * Reference to itself. -**/ + * Assignment operator. + * @returns + * Reference to itself. + **/ CSmartPtr &operator=( const CSmartPtr &i_Src /** Reference CSmartPtr.**/ ) @@ -154,10 +154,10 @@ namespace Util return *this; } /** - *compare < operator. Will call the operator for the data itself. - * @returns - * true if this object is'less than' (in terms of the defined data-operator) -**/ + *compare < operator. Will call the operator for the data itself. + * @returns + * true if this object is'less than' (in terms of the defined data-operator) + **/ bool operator<( const CSmartPtr &i_Src /** Reference CSmartPtr.**/ ) @@ -166,27 +166,27 @@ namespace Util } /** - * Operators and functions to access the heap memory. - * @returns - * Address or value of dynamic object. -**/ + * Operators and functions to access the heap memory. + * @returns + * Address or value of dynamic object. + **/ operator T &() const { return m_Counted->operator T &(); } operator T *() const { return m_Counted->operator T *(); } T *operator->() const { return m_Counted->operator->(); } T *Get() const { return m_Counted->operator->(); } /** - *Only for easier conversion of former auto_ptr's. - * -**/ + *Only for easier conversion of former auto_ptr's. + * + **/ T *get() const { return m_Counted->operator->(); } /** - * Returns heap memory address and set sets own copy of the address to NULL to prevent deletion. - * @returns - * Heap memory address. -**/ + * Returns heap memory address and set sets own copy of the address to NULL to prevent deletion. + * @returns + * Heap memory address. + **/ T *Release() { @@ -194,13 +194,13 @@ namespace Util } /** - * Casts a Util::CSmartPtr object to a Util:CSmartPtr object. - * Note that this will actually release the original and set it to NULL. - * @returns - * Util::CSmartPtr. - * - the cast operation is not possible because the classes are not suitably related, or - * - the original CSmartPtr contains a NULL pointer. -**/ + * Casts a Util::CSmartPtr object to a Util:CSmartPtr object. + * Note that this will actually release the original and set it to NULL. + * @returns + * Util::CSmartPtr. + * - the cast operation is not possible because the classes are not suitably related, or + * - the original CSmartPtr contains a NULL pointer. + **/ template inline static Util::CSmartPtr Cast( Util::CSmartPtr i_From) @@ -213,16 +213,16 @@ namespace Util }; /** - * Casts a Util::CSmartPtr object to a Util:CSmartPtr object. - * Note that this will actually release the original and set it to NULL. - * @returns - * Util::CSmartPtr. - * - the cast operation is not possible because the classes are not suitably related, or - * - the original CSmartPtr contains a NULL pointer. - * NOTE: - * Function exists only for backward compatibility. - * Rather use the CSmartPtr::Cast() function directly! -**/ + * Casts a Util::CSmartPtr object to a Util:CSmartPtr object. + * Note that this will actually release the original and set it to NULL. + * @returns + * Util::CSmartPtr. + * - the cast operation is not possible because the classes are not suitably related, or + * - the original CSmartPtr contains a NULL pointer. + * NOTE: + * Function exists only for backward compatibility. + * Rather use the CSmartPtr::Cast() function directly! + **/ template inline Util::CSmartPtr SmartPtrCast( Util::CSmartPtr i_From) diff --git a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/crc_table.h b/plugins/elektro_arktika_support/elektro_arktika/lrit/data/crc_table.h deleted file mode 100644 index 92d268909..000000000 --- a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/crc_table.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -namespace elektro -{ - namespace lrit - { - uint16_t crc_table[] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, - 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, - 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, - 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, - 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, - 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, - 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, - 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, - 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, - 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, - 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, - 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, - 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, - 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, - 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, - 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, - 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, - 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, - 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, - 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, - 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, - 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, - 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0, - }; - } -} \ No newline at end of file diff --git a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/elektro_221_composer.cpp b/plugins/elektro_arktika_support/elektro_arktika/lrit/data/elektro_221_composer.cpp index c658069bf..6856afa8f 100644 --- a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/elektro_221_composer.cpp +++ b/plugins/elektro_arktika_support/elektro_arktika/lrit/data/elektro_221_composer.cpp @@ -1,4 +1,4 @@ -#include "lrit_data_decoder.h" +#include "lrit_data.h" #include "resources.h" #include "imgui/imgui_image.h" #include "logger.h" diff --git a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/elektro_321_composer.cpp b/plugins/elektro_arktika_support/elektro_arktika/lrit/data/elektro_321_composer.cpp index a4994381b..1354b941b 100644 --- a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/elektro_321_composer.cpp +++ b/plugins/elektro_arktika_support/elektro_arktika/lrit/data/elektro_321_composer.cpp @@ -1,4 +1,4 @@ -#include "lrit_data_decoder.h" +#include "lrit_data.h" #include "resources.h" #include "imgui/imgui_image.h" #include "logger.h" diff --git a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_data_decoder.h b/plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_data.h similarity index 67% rename from plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_data_decoder.h rename to plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_data.h index 9116428ba..f99d7db8a 100644 --- a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_data_decoder.h +++ b/plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_data.h @@ -16,6 +16,13 @@ namespace elektro { namespace lrit { + enum lrit_image_status + { + RECEIVING, + SAVING, + IDLE + }; + class SegmentedLRITImageDecoder { private: @@ -33,13 +40,6 @@ namespace elektro std::string image_id = ""; }; - enum lrit_image_status - { - RECEIVING, - SAVING, - IDLE - }; - class ELEKTRO221Composer { private: @@ -100,47 +100,5 @@ namespace elektro unsigned int textureID = 0; uint32_t *textureBuffer; }; - - class LRITDataDecoder - { - private: - const std::string directory; - - bool file_in_progress; - std::vector lrit_data; - - bool is_jpeg_compressed, is_wt_compressed; - std::string current_filename; - std::vector decompression_buffer; - std::map all_headers; - SegmentedLRITImageDecoder segmentedDecoder; - - bool header_parsed = false; - - void processLRITHeader(ccsds::CCSDSPacket &pkt); - void parseHeader(); - void processLRITData(ccsds::CCSDSPacket &pkt); - void finalizeLRITData(); - - public: // Other things - std::shared_ptr elektro_221_composer_full_disk; - std::shared_ptr elektro_321_composer_full_disk; - - public: - LRITDataDecoder(std::string dir); - ~LRITDataDecoder(); - - void save(); - void work(ccsds::CCSDSPacket &packet); - - lrit_image_status imageStatus; - int img_width, img_height; - - public: - // UI Stuff - bool hasToUpdate = false; - unsigned int textureID = 0; - uint32_t *textureBuffer; - }; } // namespace atms } // namespace jpss \ No newline at end of file diff --git a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_header.h b/plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_header.h deleted file mode 100644 index 03729122b..000000000 --- a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_header.h +++ /dev/null @@ -1,289 +0,0 @@ -#pragma once - -#include -#include -#include -#include "common/utils.h" - -namespace elektro -{ - namespace lrit - { - struct PrimaryHeader - { - static constexpr int TYPE = 0; - - uint8_t type; - uint16_t record_length; - uint8_t file_type_code; - uint32_t total_header_length; - uint64_t data_field_length; - - PrimaryHeader(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - file_type_code = data[3]; - total_header_length = (uint32_t)data[4] << 24 | - (uint32_t)data[5] << 16 | - (uint32_t)data[6] << 8 | - (uint32_t)data[7]; - data_field_length = (uint64_t)data[8] << 56 | - (uint64_t)data[9] << 48 | - (uint64_t)data[10] << 40 | - (uint64_t)data[11] << 32 | - (uint64_t)data[12] << 24 | - (uint64_t)data[13] << 16 | - (uint64_t)data[14] << 8 | - (uint64_t)data[15]; - } - }; - - struct ImageStructureRecord - { - static constexpr int TYPE = 1; - - uint8_t type; - uint16_t record_length; - uint8_t bit_per_pixel; - uint16_t columns_count; - uint16_t lines_count; - uint8_t compression_flag; - - ImageStructureRecord(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - bit_per_pixel = data[3]; - columns_count = data[4] << 8 | data[5]; - lines_count = data[6] << 8 | data[7]; - compression_flag = data[8]; - } - }; - - struct ImageNavigationRecord - { - static constexpr int TYPE = 2; - - uint8_t type; - uint16_t record_length; - char projection_name[32]; - uint32_t column_scaling_factor; - uint32_t line_scaling_factor; - uint32_t column_offset; - uint32_t line_offset; - - ImageNavigationRecord(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - std::memcpy(projection_name, &data[3], 32); - column_scaling_factor = (uint32_t)data[36] << 24 | - (uint32_t)data[37] << 16 | - (uint32_t)data[38] << 8 | - (uint32_t)data[39]; - line_scaling_factor = (uint32_t)data[40] << 24 | - (uint32_t)data[41] << 16 | - (uint32_t)data[42] << 8 | - (uint32_t)data[43]; - column_offset = (uint32_t)data[44] << 24 | - (uint32_t)data[45] << 16 | - (uint32_t)data[46] << 8 | - (uint32_t)data[47]; - line_offset = (uint32_t)data[48] << 24 | - (uint32_t)data[49] << 16 | - (uint32_t)data[50] << 8 | - (uint32_t)data[51]; - } - }; - - struct ImageDataFunctionRecord - { - static constexpr int TYPE = 3; - - uint8_t type; - uint16_t record_length; - std::string data_definition; - - ImageDataFunctionRecord(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - data_definition.insert(data_definition.end(), &data[3], &data[record_length]); - } - }; - - struct AnnotationRecord - { - static constexpr int TYPE = 4; - - uint8_t type; - uint16_t record_length; - std::string annotation_text; - - AnnotationRecord(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - annotation_text.insert(annotation_text.end(), &data[3], &data[record_length]); - } - }; - - struct TimeStampRecord - { - static constexpr int TYPE = 5; - - uint8_t type; - uint16_t record_length; - uint16_t days; - uint32_t milliseconds_of_day; - - time_t timestamp; - - TimeStampRecord(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - uint16_t days = data[3] << 8 | data[4]; - uint32_t milliseconds_of_day = data[5] << 24 | data[6] << 16 | data[7] << 8 | data[8]; - - timestamp = (days - 4383) * 86400 + milliseconds_of_day; - } - }; - - struct AncillaryTextRecord - { - static constexpr int TYPE = 6; - - uint8_t type; - uint16_t record_length; - std::string ancillary_text; - - std::map meta; - - AncillaryTextRecord(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - ancillary_text.insert(ancillary_text.end(), &data[3], &data[record_length]); - - // I will admit I needed to peek in goestools to figure that one out - // A bit hard without having live data... - std::vector fields = splitString(ancillary_text, ';'); - - for (std::string &field : fields) - { - std::vector values = splitString(field, '='); - if (values.size() == 2) - { - values[0] = values[0].substr(0, values[0].find_last_not_of(' ') + 1); - values[1] = values[1].substr(values[1].find_first_not_of(' ')); - meta.insert({values[0], values[1]}); - } - } - } - }; - - struct KeyHeader - { - static constexpr int TYPE = 7; - - uint8_t type; - uint16_t record_length; - uint32_t key; - - KeyHeader(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - key = data[3] << 24 | data[4] << 16 | data[5] << 8 | data[6]; - } - }; - - struct SegmentIdentificationHeader - { - static constexpr int TYPE = 128; - - uint8_t type; - uint16_t record_length; - uint16_t sc_id; - uint8_t channel_id; - uint16_t segment_sequence_number; - uint16_t planned_start_segment; - uint16_t planned_end_segment; - uint8_t compression; - - SegmentIdentificationHeader(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - sc_id = data[3] << 8 | data[4]; - channel_id = data[5]; - segment_sequence_number = data[6] << 8 | data[7]; - planned_start_segment = data[8] << 8 | data[9]; - planned_end_segment = data[10] << 8 | data[11]; - compression = data[12]; - } - }; - - /*struct NOAALRITHeader - { - static constexpr int TYPE = 129; - - uint8_t type; - uint16_t record_length; - char agency_signature[4]; - uint16_t product_id; - uint16_t product_subid; - uint16_t parameter; - uint8_t noaa_specific_compression; - - NOAALRITHeader(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - std::memcpy(agency_signature, &data[3], 4); - product_id = data[7] << 8 | data[8]; - product_subid = data[9] << 8 | data[10]; - parameter = data[11] << 8 | data[12]; - noaa_specific_compression = data[13]; - } - };*/ - - struct HeaderStructureRecord - { - static constexpr int TYPE = 130; - - uint8_t type; - uint16_t record_length; - std::string header_structure; - - HeaderStructureRecord(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - header_structure.insert(header_structure.end(), &data[3], &data[record_length]); - } - }; - - /*struct RiceCompressionHeader - { - static constexpr int TYPE = 131; - - uint8_t type; - uint16_t record_length; - uint16_t flags; - uint8_t pixels_per_block; - uint8_t scanlines_per_packet; - - RiceCompressionHeader(uint8_t *data) - { - type = data[0]; - record_length = data[1] << 8 | data[2]; - flags = data[3] << 8 | data[4]; - pixels_per_block = data[5]; - scanlines_per_packet = data[6]; - } - };*/ - } -} \ No newline at end of file diff --git a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/segmented_decoder.cpp b/plugins/elektro_arktika_support/elektro_arktika/lrit/data/segmented_decoder.cpp index 84306a4ab..1e21cc18a 100644 --- a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/segmented_decoder.cpp +++ b/plugins/elektro_arktika_support/elektro_arktika/lrit/data/segmented_decoder.cpp @@ -1,4 +1,4 @@ -#include "lrit_data_decoder.h" +#include "lrit_data.h" #include namespace elektro diff --git a/plugins/elektro_arktika_support/elektro_arktika/lrit/lrit_header.h b/plugins/elektro_arktika_support/elektro_arktika/lrit/lrit_header.h new file mode 100644 index 000000000..c5b522351 --- /dev/null +++ b/plugins/elektro_arktika_support/elektro_arktika/lrit/lrit_header.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include "common/utils.h" + +namespace elektro +{ + namespace lrit + { + struct SegmentIdentificationHeader + { + static constexpr int TYPE = 128; + + uint8_t type; + uint16_t record_length; + uint16_t sc_id; + uint8_t channel_id; + uint16_t segment_sequence_number; + uint16_t planned_start_segment; + uint16_t planned_end_segment; + uint8_t compression; + + SegmentIdentificationHeader(uint8_t *data) + { + type = data[0]; + record_length = data[1] << 8 | data[2]; + sc_id = data[3] << 8 | data[4]; + channel_id = data[5]; + segment_sequence_number = data[6] << 8 | data[7]; + planned_start_segment = data[8] << 8 | data[9]; + planned_end_segment = data[10] << 8 | data[11]; + compression = data[12]; + } + }; + } +} \ No newline at end of file diff --git a/plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder.cpp b/plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder.cpp index 4131a1fb7..8751184e9 100644 --- a/plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder.cpp +++ b/plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder.cpp @@ -1,16 +1,11 @@ #include "module_elektro_lrit_data_decoder.h" #include -#include "common/ccsds/ccsds_1_0_1024/demuxer.h" -#include "common/ccsds/ccsds_1_0_1024/vcdu.h" #include "logger.h" #include #include "imgui/imgui.h" #include "imgui/imgui_image.h" - -#define BUFFER_SIZE 8192 - -// Return filesize -size_t getFilesize(std::string filepath); +#include "common/utils.h" +#include "common/lrit/lrit_demux.h" namespace elektro { @@ -34,9 +29,9 @@ namespace elektro ELEKTROLRITDataDecoderModule::~ELEKTROLRITDataDecoderModule() { - for (std::pair> decMap : decoders) + for (auto &decMap : all_wip_images) { - std::shared_ptr dec = decMap.second; + auto &dec = decMap.second; if (dec->textureID > 0) { @@ -70,7 +65,40 @@ namespace elektro logger->info("Demultiplexing and deframing..."); - std::map> demuxers; + // std::map> demuxers; + + ::lrit::LRITDemux lrit_demux; + + this->directory = directory; + + lrit_demux.onParseHeader = + [](::lrit::LRITFile &file) -> void + { + // Check if this is image data + if (file.hasHeader<::lrit::ImageStructureRecord>()) + { + ::lrit::ImageStructureRecord image_structure_record = file.getHeader<::lrit::ImageStructureRecord>(); //(&lrit_data[all_headers[ImageStructureRecord::TYPE]]); + logger->debug("This is image data. Size " + std::to_string(image_structure_record.columns_count) + "x" + std::to_string(image_structure_record.lines_count)); + + if (image_structure_record.compression_flag == 2 /* Progressive JPEG */) + { + logger->debug("JPEG Compression is used, decompressing..."); + file.custom_flags.insert_or_assign(JPEG_COMPRESSED, true); + file.custom_flags.insert_or_assign(WT_COMPRESSED, false); + } + else if (image_structure_record.compression_flag == 1 /* Wavelet */) + { + logger->debug("Wavelet Compression is used, decompressing..."); + file.custom_flags.insert_or_assign(JPEG_COMPRESSED, false); + file.custom_flags.insert_or_assign(WT_COMPRESSED, true); + } + else + { + file.custom_flags.insert_or_assign(JPEG_COMPRESSED, false); + file.custom_flags.insert_or_assign(WT_COMPRESSED, false); + } + } + }; while (input_data_type == DATA_FILE ? !data_in.eof() : input_active.load()) { @@ -80,33 +108,10 @@ namespace elektro else input_fifo->read((uint8_t *)&cadu, 1024); - // Parse this transport frame - ccsds::ccsds_1_0_1024::VCDU vcdu = ccsds::ccsds_1_0_1024::parseVCDU(cadu); + std::vector<::lrit::LRITFile> files = lrit_demux.work(cadu); - if (vcdu.vcid == 63) - continue; - - if (demuxers.count(vcdu.vcid) <= 0) - demuxers.emplace(std::pair>(vcdu.vcid, std::make_shared(884, false))); - - // Demux - std::vector ccsdsFrames = demuxers[vcdu.vcid]->work(cadu); - - // Push into processor (filtering APID 103 and 104) - for (ccsds::CCSDSPacket &pkt : ccsdsFrames) - { - if (pkt.header.apid != 2047) - { - if (decoders.count(vcdu.vcid) <= 0) - { - decoders.emplace(std::pair>(vcdu.vcid, std::make_shared(directory))); - - decoders[vcdu.vcid]->elektro_221_composer_full_disk = elektro_221_composer_full_disk; - decoders[vcdu.vcid]->elektro_321_composer_full_disk = elektro_321_composer_full_disk; - } - decoders[vcdu.vcid]->work(pkt); - } - } + for (auto &file : files) + processLRITFile(file); if (input_data_type == DATA_FILE) progress = data_in.tellg(); @@ -120,8 +125,19 @@ namespace elektro data_in.close(); - for (const std::pair> &dec : decoders) - dec.second->save(); + for (auto &segmentedDecoder : segmentedDecoders) + { + if (segmentedDecoder.second.image_id != "") + { + logger->info("Writing image " + directory + "/IMAGES/" + segmentedDecoder.second.image_id + ".png" + "..."); + segmentedDecoder.second.image.save_png(std::string(directory + "/IMAGES/" + segmentedDecoder.second.image_id + ".png").c_str()); + } + } + + if (elektro_221_composer_full_disk->hasData) + elektro_221_composer_full_disk->save(directory); + if (elektro_321_composer_full_disk->hasData) + elektro_321_composer_full_disk->save(directory); } void ELEKTROLRITDataDecoderModule::drawUI(bool window) @@ -132,9 +148,9 @@ namespace elektro { bool hasImage = false; - for (std::pair> decMap : decoders) + for (auto &decMap : all_wip_images) { - std::shared_ptr dec = decMap.second; + auto &dec = decMap.second; if (dec->textureID == 0) { @@ -152,7 +168,7 @@ namespace elektro hasImage = true; - if (ImGui::BeginTabItem(std::string("VCID " + std::to_string(decMap.first)).c_str())) + if (ImGui::BeginTabItem(std::string("Ch " + std::to_string(decMap.first)).c_str())) { ImGui::Image((void *)(intptr_t)dec->textureID, {200 * ui_scale, 200 * ui_scale}); ImGui::SameLine(); diff --git a/plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder.h b/plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder.h index b9d27522a..1775290a1 100644 --- a/plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder.h +++ b/plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder.h @@ -1,7 +1,9 @@ #pragma once #include "core/module.h" -#include "data/lrit_data_decoder.h" +#include "data/lrit_data.h" + +#include "common/lrit/lrit_file.h" namespace elektro { @@ -13,10 +15,32 @@ namespace elektro std::atomic filesize; std::atomic progress; - std::map> decoders; - std::shared_ptr elektro_221_composer_full_disk; - std::shared_ptr elektro_321_composer_full_disk; + std::shared_ptr elektro_321_composer_full_disk; + std::map segmentedDecoders; + + std::string directory; + + enum CustomFileParams + { + JPEG_COMPRESSED, + WT_COMPRESSED, + }; + + struct wip_images + { + lrit_image_status imageStatus = RECEIVING; + int img_width, img_height; + + // UI Stuff + bool hasToUpdate = false; + unsigned int textureID = 0; + uint32_t *textureBuffer; + }; + + std::map> all_wip_images; + + void processLRITFile(::lrit::LRITFile &file); public: ELEKTROLRITDataDecoderModule(std::string input_file, std::string output_file_hint, nlohmann::json parameters); diff --git a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_data_decoder.cpp b/plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder_proc.cpp similarity index 62% rename from plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_data_decoder.cpp rename to plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder_proc.cpp index d20dd3c7b..a5cd6283d 100644 --- a/plugins/elektro_arktika_support/elektro_arktika/lrit/data/lrit_data_decoder.cpp +++ b/plugins/elektro_arktika_support/elektro_arktika/lrit/module_elektro_lrit_data_decoder_proc.cpp @@ -1,18 +1,9 @@ -#include "lrit_data_decoder.h" +#include "module_elektro_lrit_data_decoder.h" #include "logger.h" -#include -#include "lrit_header.h" -#include "crc_table.h" -#include -#include -#include #include -#include -#include "common/utils.h" -#include "libs/others/strptime.h" #include "imgui/imgui_image.h" +#include "lrit_header.h" #include "common/image/jpeg_utils.h" -#include "resources.h" #include "DecompWT/CompressWT.h" #include "DecompWT/CompressT4.h" @@ -44,181 +35,28 @@ namespace elektro return utc_filename; } - // CRC Implementation from LRIT-Missin-Specific-Document.pdf - uint16_t computeCRC(const uint8_t *data, int size) + void ELEKTROLRITDataDecoderModule::processLRITFile(::lrit::LRITFile &file) { - uint16_t crc = 0xffff; - for (int i = 0; i < size; i++) - crc = (crc << 8) ^ crc_table[(crc >> 8) ^ (uint16_t)data[i]]; - return crc; - } + std::string current_filename = file.filename; - LRITDataDecoder::LRITDataDecoder(std::string dir) : directory(dir) - { - file_in_progress = false; - imageStatus = IDLE; - img_height = 0; - img_width = 0; - } - - LRITDataDecoder::~LRITDataDecoder() - { - } - - void LRITDataDecoder::work(ccsds::CCSDSPacket &packet) - { - if (packet.header.sequence_flag == 1 || packet.header.sequence_flag == 3) - { - if (file_in_progress) - finalizeLRITData(); - - lrit_data.clear(); - - // Check CRC - uint16_t crc = packet.payload.data()[packet.payload.size() - 2] << 8 | packet.payload.data()[packet.payload.size() - 1]; - - if (crc == computeCRC(packet.payload.data(), packet.payload.size() - 2)) - { - processLRITHeader(packet); - header_parsed = false; - file_in_progress = true; - } - else - { - logger->error("CRC is invalid... Skipping."); - file_in_progress = false; - } - } - else if (packet.header.sequence_flag == 0) - { - if (file_in_progress) - { - processLRITData(packet); - } - } - else if (packet.header.sequence_flag == 2) - { - if (file_in_progress) - { - processLRITData(packet); - finalizeLRITData(); - file_in_progress = false; - } - } - - if (file_in_progress && !header_parsed) - { - PrimaryHeader primary_header(&lrit_data[0]); - - if (lrit_data.size() >= primary_header.total_header_length) - { - parseHeader(); - header_parsed = true; - } - } - } - - void LRITDataDecoder::processLRITHeader(ccsds::CCSDSPacket &pkt) - { - lrit_data.insert(lrit_data.end(), &pkt.payload.data()[10], &pkt.payload.data()[pkt.payload.size() - 2]); - } - - void LRITDataDecoder::parseHeader() - { - PrimaryHeader primary_header(&lrit_data[0]); - - // Get all other headers - all_headers.clear(); - for (uint32_t i = 0; i < primary_header.total_header_length;) - { - uint8_t type = lrit_data[i]; - uint16_t record_length = lrit_data[i + 1] << 8 | lrit_data[i + 2]; - - if (record_length == 0) - break; - - all_headers.emplace(std::pair(type, i)); - - i += record_length; - } - - // Check if this has a filename - if (all_headers.count(AnnotationRecord::TYPE) > 0) - { - AnnotationRecord annotation_record(&lrit_data[all_headers[AnnotationRecord::TYPE]]); - - current_filename = std::string(annotation_record.annotation_text.data()); - - std::replace(current_filename.begin(), current_filename.end(), '/', '_'); // Safety - std::replace(current_filename.begin(), current_filename.end(), '\\', '_'); // Safety - - for (char &c : current_filename) // Strip invalid chars - { - if (c < 33) - c = '_'; - } - - logger->info("New LRIT file : " + current_filename); - - // Check if this is image data - if (all_headers.count(ImageStructureRecord::TYPE) > 0) - { - ImageStructureRecord image_structure_record(&lrit_data[all_headers[ImageStructureRecord::TYPE]]); - logger->debug("This is image data. Size " + std::to_string(image_structure_record.columns_count) + "x" + std::to_string(image_structure_record.lines_count)); - - if (image_structure_record.compression_flag == 2 /* Progressive JPEG */) - { - logger->debug("JPEG Compression is used, decompressing..."); - is_jpeg_compressed = true; - is_wt_compressed = false; - } - else if (image_structure_record.compression_flag == 1 /* Wavelet */) - { - logger->debug("Wavelet Compression is used, decompressing..."); - is_jpeg_compressed = false; - is_wt_compressed = true; - } - else - { - is_jpeg_compressed = false; - is_wt_compressed = false; - } - } - - if (all_headers.count(KeyHeader::TYPE) > 0) - { - KeyHeader key_header(&lrit_data[all_headers[KeyHeader::TYPE]]); - logger->debug("This is encrypted!"); - } - } - } - - void LRITDataDecoder::processLRITData(ccsds::CCSDSPacket &pkt) - { - // File may be encrypted so we cannot process them before the fact... - lrit_data.insert(lrit_data.end(), &pkt.payload.data()[0], &pkt.payload.data()[pkt.payload.size() - 2]); - } - - void LRITDataDecoder::finalizeLRITData() - { - PrimaryHeader primary_header(&lrit_data[0]); + ::lrit::PrimaryHeader primary_header = file.getHeader<::lrit::PrimaryHeader>(); // Check if this is image data, and if so also write it as an image - if (primary_header.file_type_code == 0 && all_headers.count(ImageStructureRecord::TYPE) > 0) + if (primary_header.file_type_code == 0 && file.hasHeader<::lrit::ImageStructureRecord>()) { if (!std::filesystem::exists(directory + "/IMAGES")) std::filesystem::create_directory(directory + "/IMAGES"); - ImageStructureRecord image_structure_record(&lrit_data[all_headers[ImageStructureRecord::TYPE]]); + ::lrit::ImageStructureRecord image_structure_record = file.getHeader<::lrit::ImageStructureRecord>(); - if (is_jpeg_compressed) // Is this Jpeg-Compressed? Decompress + if (file.custom_flags[JPEG_COMPRESSED]) // Is this Jpeg-Compressed? Decompress { logger->info("Decompressing JPEG..."); - image::Image img = image::decompress_jpeg(&lrit_data[primary_header.total_header_length], lrit_data.size() - primary_header.total_header_length, true); - lrit_data.erase(lrit_data.begin() + primary_header.total_header_length, lrit_data.end()); - lrit_data.insert(lrit_data.end(), (uint8_t *)&img[0], (uint8_t *)&img[img.height() * img.width()]); + image::Image img = image::decompress_jpeg(&file.lrit_data[primary_header.total_header_length], file.lrit_data.size() - primary_header.total_header_length, true); + file.lrit_data.erase(file.lrit_data.begin() + primary_header.total_header_length, file.lrit_data.end()); + file.lrit_data.insert(file.lrit_data.end(), (uint8_t *)&img[0], (uint8_t *)&img[img.height() * img.width()]); } - else if (is_wt_compressed) // Is this Wavelet-Compressed? Decompress. We know this will always be 10-bits + else if (file.custom_flags[WT_COMPRESSED]) // Is this Wavelet-Compressed? Decompress. We know this will always be 10-bits { /* This could be better... Sometimes I should maybe adapt the DecompWT code to be cleaner for this purpose... @@ -227,9 +65,9 @@ namespace elektro int compression_type = 3; // We assume Wavelet - if (all_headers.count(SegmentIdentificationHeader::TYPE) > 0) // But if we have a header with better info, use it + if (file.all_headers.count(SegmentIdentificationHeader::TYPE) > 0) // But if we have a header with better info, use it { - SegmentIdentificationHeader segment_id_header(&lrit_data[all_headers[SegmentIdentificationHeader::TYPE]]); + SegmentIdentificationHeader segment_id_header = file.getHeader(); compression_type = segment_id_header.compression; } @@ -241,12 +79,12 @@ namespace elektro // Decompress { // We need to copy over that memory to its own buffer - uint8_t *compressedData = new uint8_t[lrit_data.size() - primary_header.total_header_length]; - std::memcpy(compressedData, &lrit_data[primary_header.total_header_length], lrit_data.size() - primary_header.total_header_length); + uint8_t *compressedData = new uint8_t[file.lrit_data.size() - primary_header.total_header_length]; + std::memcpy(compressedData, &file.lrit_data[primary_header.total_header_length], file.lrit_data.size() - primary_header.total_header_length); // Images object Util::CDataFieldCompressedImage compressedImage(compressedData, - (lrit_data.size() - primary_header.total_header_length) * 8, + (file.lrit_data.size() - primary_header.total_header_length) * 8, image_structure_record.bit_per_pixel, image_structure_record.columns_count, image_structure_record.lines_count); @@ -278,7 +116,7 @@ namespace elektro if (out_pixels == image_structure_record.columns_count * image_structure_record.lines_count) // Matches? { // Empty current LRIT file - lrit_data.erase(lrit_data.begin() + primary_header.total_header_length, lrit_data.end()); + file.lrit_data.erase(file.lrit_data.begin() + primary_header.total_header_length, file.lrit_data.end()); if (image_structure_record.bit_per_pixel == 10) { @@ -290,21 +128,21 @@ namespace elektro uint16_t v3 = ((image_ptr[2] % 16) << 6) | (image_ptr[3] >> 2); uint16_t v4 = ((image_ptr[3] % 4) << 8) | image_ptr[4]; - lrit_data.push_back(v1 >> 2); - lrit_data.push_back(v2 >> 2); - lrit_data.push_back(v3 >> 2); - lrit_data.push_back(v4 >> 2); + file.lrit_data.push_back(v1 >> 2); + file.lrit_data.push_back(v2 >> 2); + file.lrit_data.push_back(v3 >> 2); + file.lrit_data.push_back(v4 >> 2); image_ptr += 5; } // Fill remaining if required for (int i = 0; i < buf_size % 5; i++) - lrit_data.push_back(0); + file.lrit_data.push_back(0); } else if (image_structure_record.bit_per_pixel == 8) // Just in case { - lrit_data.insert(lrit_data.end(), image_ptr, &image_ptr[buf_size]); + file.lrit_data.insert(file.lrit_data.end(), image_ptr, &image_ptr[buf_size]); } else { @@ -318,11 +156,11 @@ namespace elektro out_pixels = image_structure_record.lines_count * image_structure_record.columns_count; // Empty current LRIT file - lrit_data.erase(lrit_data.begin() + primary_header.total_header_length, lrit_data.end()); + file.lrit_data.erase(file.lrit_data.begin() + primary_header.total_header_length, file.lrit_data.end()); // Fill with 0s for (int i = 0; i < out_pixels; i++) - lrit_data.push_back(0); + file.lrit_data.push_back(0); } // Free up memory if necessary @@ -330,10 +168,9 @@ namespace elektro // delete[] image_ptr; } - if (all_headers.count(SegmentIdentificationHeader::TYPE) > 0) + if (file.all_headers.count(SegmentIdentificationHeader::TYPE) > 0) { - imageStatus = RECEIVING; - SegmentIdentificationHeader segment_id_header(&lrit_data[all_headers[SegmentIdentificationHeader::TYPE]]); + SegmentIdentificationHeader segment_id_header = file.getHeader(); std::vector header_parts = splitString(current_filename, '_'); @@ -389,13 +226,23 @@ namespace elektro } } + if (all_wip_images.count(channel) == 0) + all_wip_images.insert({channel, std::make_unique()}); + + std::unique_ptr &wip_img = all_wip_images[channel]; + + if (segmentedDecoders.count(channel) == 0) + segmentedDecoders.insert({channel, SegmentedLRITImageDecoder()}); + + SegmentedLRITImageDecoder &segmentedDecoder = segmentedDecoders[channel]; + if (segmentedDecoder.image_id != image_id) { if (segmentedDecoder.image_id != "") { current_filename = image_id; - imageStatus = SAVING; + wip_img->imageStatus = SAVING; logger->info("Writing image " + directory + "/IMAGES/" + current_filename + ".png" + "..."); segmentedDecoder.image.save_png(std::string(directory + "/IMAGES/" + current_filename + ".png").c_str()); @@ -404,7 +251,7 @@ namespace elektro if (elektro_321_composer_full_disk->hasData) elektro_321_composer_full_disk->save(directory); - imageStatus = RECEIVING; + wip_img->imageStatus = RECEIVING; } segmentedDecoder = SegmentedLRITImageDecoder(segment_id_header.planned_end_segment, @@ -414,7 +261,7 @@ namespace elektro } int seg_number = segment_id_header.segment_sequence_number - 1; - segmentedDecoder.pushSegment(&lrit_data[primary_header.total_header_length], seg_number); + segmentedDecoder.pushSegment(&file.lrit_data[primary_header.total_header_length], seg_number); // Composite? if (channel == 1) @@ -433,22 +280,22 @@ namespace elektro } // If the UI is active, update texture - if (textureID > 0) + if (wip_img->textureID > 0) { // Downscale image - img_height = 1000; - img_width = 1000; + wip_img->img_height = 1000; + wip_img->img_width = 1000; image::Image imageScaled = segmentedDecoder.image; - imageScaled.resize(img_width, img_height); - uchar_to_rgba(imageScaled.data(), textureBuffer, img_height * img_width); - hasToUpdate = true; + imageScaled.resize(wip_img->img_width, wip_img->img_height); + uchar_to_rgba(imageScaled.data(), wip_img->textureBuffer, wip_img->img_height * wip_img->img_width); + wip_img->hasToUpdate = true; } if (segmentedDecoder.isComplete()) { current_filename = image_id; - imageStatus = SAVING; + wip_img->imageStatus = SAVING; logger->info("Writing image " + directory + "/IMAGES/" + current_filename + ".png" + "..."); segmentedDecoder.image.save_png(std::string(directory + "/IMAGES/" + current_filename + ".png").c_str()); @@ -458,14 +305,14 @@ namespace elektro elektro_321_composer_full_disk->save(directory); segmentedDecoder = SegmentedLRITImageDecoder(); - imageStatus = IDLE; + wip_img->imageStatus = IDLE; } } else { // Write raw image dats logger->info("Writing image " + directory + "/IMAGES/" + current_filename + ".png" + "..."); - image::Image image(&lrit_data[primary_header.total_header_length], image_structure_record.columns_count, image_structure_record.lines_count, 1); + image::Image image(&file.lrit_data[primary_header.total_header_length], image_structure_record.columns_count, image_structure_record.lines_count, 1); image.save_png(std::string(directory + "/IMAGES/" + current_filename + ".png").c_str()); } } @@ -474,24 +321,13 @@ namespace elektro if (!std::filesystem::exists(directory + "/LRIT")) std::filesystem::create_directory(directory + "/LRIT"); - logger->info("Writing file " + directory + "/LRIT/" + current_filename + "..."); + logger->info("Writing file " + directory + "/LRIT/" + file.filename + "..."); // Write file out - std::ofstream file(directory + "/LRIT/" + current_filename, std::ios::binary); - file.write((char *)lrit_data.data(), lrit_data.size()); - file.close(); + std::ofstream fileo(directory + "/LRIT/" + file.filename, std::ios::binary); + fileo.write((char *)file.lrit_data.data(), file.lrit_data.size()); + fileo.close(); } } - - void LRITDataDecoder::save() - { - if (segmentedDecoder.image_id != "") - { - finalizeLRITData(); - - logger->info("Writing image " + directory + "/IMAGES/" + current_filename + ".png" + "..."); - segmentedDecoder.image.save_png(std::string(directory + "/IMAGES/" + current_filename + ".png").c_str()); - } - } - } // namespace atms -} // namespace jpss \ No newline at end of file + } // namespace avhrr +} // namespace metop \ No newline at end of file diff --git a/src-core/common/lrit/crc_table.h b/src-core/common/lrit/crc_table.h new file mode 100644 index 000000000..e4d6b8f76 --- /dev/null +++ b/src-core/common/lrit/crc_table.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +namespace lrit +{ + uint16_t crc_table[] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0, + }; +} \ No newline at end of file diff --git a/src-core/common/lrit/lrit_demux.cpp b/src-core/common/lrit/lrit_demux.cpp new file mode 100644 index 000000000..4c975bcbe --- /dev/null +++ b/src-core/common/lrit/lrit_demux.cpp @@ -0,0 +1,129 @@ +#include "lrit_demux.h" +#include "common/ccsds/ccsds_1_0_1024/vcdu.h" +#include "logger.h" +#include "crc_table.h" + +namespace lrit +{ + + LRITDemux::LRITDemux(int mpdu_size) + : d_mpdu_size(mpdu_size) + { + } + + LRITDemux::~LRITDemux() + { + } + + // CRC Implementation from LRIT-Mission-Specific-Document.pdf + uint16_t computeCRC(const uint8_t *data, int size) + { + uint16_t crc = 0xffff; + for (int i = 0; i < size; i++) + crc = (crc << 8) ^ crc_table[(crc >> 8) ^ (uint16_t)data[i]]; + return crc; + } + + std::vector LRITDemux::work(uint8_t *cadu) + { + files.clear(); + + ccsds::ccsds_1_0_1024::VCDU vcdu = ccsds::ccsds_1_0_1024::parseVCDU(cadu); + + if (vcdu.vcid == 63) // Skip filler + return files; + + if (demuxers.count(vcdu.vcid) <= 0) // Add new demux if required + { + demuxers.emplace(std::pair>(vcdu.vcid, std::make_unique(d_mpdu_size, false))); + wip_files.insert({vcdu.vcid, std::map()}); + } + + // Demux + std::vector ccsdsFrames = demuxers[vcdu.vcid]->work(cadu); + + for (ccsds::CCSDSPacket &pkt : ccsdsFrames) + { + if (pkt.header.apid == 2047) // Skip filler + return files; + + if (wip_files[vcdu.vcid].count(pkt.header.apid) == 0) // One file per APID + wip_files[vcdu.vcid].insert({pkt.header.apid, LRITFile()}); + + LRITFile ¤t_file = wip_files[vcdu.vcid][pkt.header.apid]; + + if (pkt.header.sequence_flag == 1 || pkt.header.sequence_flag == 3) + { + if (current_file.file_in_progress) + finalizeLRITData(current_file); + + current_file.lrit_data.clear(); + + // Check CRC + uint16_t crc = pkt.payload.data()[pkt.payload.size() - 2] << 8 | pkt.payload.data()[pkt.payload.size() - 1]; + + if (crc == computeCRC(pkt.payload.data(), pkt.payload.size() - 2)) + { + processLRITHeader(current_file, pkt); + current_file.header_parsed = false; + current_file.file_in_progress = true; + } + else + { + logger->error("LRIT CRC is invalid... Skipping."); + current_file.file_in_progress = false; + } + } + else if (pkt.header.sequence_flag == 0) + { + if (current_file.file_in_progress) + processLRITData(current_file, pkt); + } + else if (pkt.header.sequence_flag == 2) + { + if (current_file.file_in_progress) + { + processLRITData(current_file, pkt); + finalizeLRITData(current_file); + current_file.file_in_progress = false; + } + } + + if (current_file.file_in_progress && !current_file.header_parsed) + { + PrimaryHeader primary_header = current_file.getHeader(); + + if (current_file.lrit_data.size() >= primary_header.total_header_length) + { + parseHeader(current_file); + current_file.header_parsed = true; + } + } + } + + return files; + } + + void LRITDemux::processLRITHeader(LRITFile &file, ccsds::CCSDSPacket &pkt) + { + file.lrit_data.insert(file.lrit_data.end(), &pkt.payload.data()[10], &pkt.payload.data()[pkt.payload.size() - 2]); + } + + void LRITDemux::parseHeader(LRITFile &file) + { + file.parseHeaders(); + logger->info("New LRIT file : " + file.filename); + onParseHeader(file); + } + + void LRITDemux::processLRITData(LRITFile &file, ccsds::CCSDSPacket &pkt) + { + if (onProcessData(file, pkt)) + file.lrit_data.insert(file.lrit_data.end(), &pkt.payload.data()[0], &pkt.payload.data()[pkt.payload.size() - 2]); + } + + void LRITDemux::finalizeLRITData(LRITFile &file) + { + files.push_back(file); + } +}; \ No newline at end of file diff --git a/src-core/common/lrit/lrit_demux.h b/src-core/common/lrit/lrit_demux.h new file mode 100644 index 000000000..ebb2b10fa --- /dev/null +++ b/src-core/common/lrit/lrit_demux.h @@ -0,0 +1,40 @@ +#pragma once + +#include "lrit_file.h" +#include "common/ccsds/ccsds_1_0_1024/demuxer.h" +#include +#include + +namespace lrit +{ + class LRITDemux + { + private: + const int d_mpdu_size; + + private: + std::map> demuxers; + std::map> wip_files; + + std::vector files; + + private: + void processLRITHeader(LRITFile &file, ccsds::CCSDSPacket &pkt); + void parseHeader(LRITFile &file); + void processLRITData(LRITFile &file, ccsds::CCSDSPacket &pkt); + void finalizeLRITData(LRITFile &file); + + public: + std::function onParseHeader = + [](LRITFile &) -> void {}; + std::function onProcessData = + [](LRITFile &, ccsds::CCSDSPacket &) -> bool + { return true; }; + + public: + LRITDemux(int mpdu_size = 884); + ~LRITDemux(); + + std::vector work(uint8_t *cadu); + }; +}; \ No newline at end of file diff --git a/src-core/common/lrit/lrit_file.cpp b/src-core/common/lrit/lrit_file.cpp new file mode 100644 index 000000000..16ce612bf --- /dev/null +++ b/src-core/common/lrit/lrit_file.cpp @@ -0,0 +1,44 @@ +#include "lrit_file.h" +#include + +namespace lrit +{ + void LRITFile::parseHeaders() + { + PrimaryHeader primary_header = getHeader(); + + // Get all other headers + all_headers.clear(); + for (uint32_t i = 0; i < primary_header.total_header_length;) + { + uint8_t type = lrit_data[i]; + uint16_t record_length = lrit_data[i + 1] << 8 | lrit_data[i + 2]; + + if (record_length == 0) + break; + + all_headers.emplace(std::pair(type, i)); + + i += record_length; + } + + // Check if this has a filename + if (all_headers.count(AnnotationRecord::TYPE) > 0) + { + AnnotationRecord annotation_record = getHeader(); + + filename = std::string(annotation_record.annotation_text.data()); + + std::replace(filename.begin(), filename.end(), '/', '_'); // Safety + std::replace(filename.begin(), filename.end(), '\\', '_'); // Safety + + for (char &c : filename) // Strip invalid chars + { + if (c < 33) + c = '_'; + } + } + + total_header_length = primary_header.total_header_length; + } +} diff --git a/src-core/common/lrit/lrit_file.h b/src-core/common/lrit/lrit_file.h new file mode 100644 index 000000000..f09665296 --- /dev/null +++ b/src-core/common/lrit/lrit_file.h @@ -0,0 +1,109 @@ +#pragma once + +#include +#include +#include +#include + +namespace lrit +{ + //////////////////////////////////////// + struct PrimaryHeader + { + static constexpr int TYPE = 0; + + uint8_t type; + uint16_t record_length; + uint8_t file_type_code; + uint32_t total_header_length; + uint64_t data_field_length; + + PrimaryHeader(uint8_t *data) + { + type = data[0]; + record_length = data[1] << 8 | data[2]; + file_type_code = data[3]; + total_header_length = (uint32_t)data[4] << 24 | + (uint32_t)data[5] << 16 | + (uint32_t)data[6] << 8 | + (uint32_t)data[7]; + data_field_length = (uint64_t)data[8] << 56 | + (uint64_t)data[9] << 48 | + (uint64_t)data[10] << 40 | + (uint64_t)data[11] << 32 | + (uint64_t)data[12] << 24 | + (uint64_t)data[13] << 16 | + (uint64_t)data[14] << 8 | + (uint64_t)data[15]; + } + }; + + struct AnnotationRecord + { + static constexpr int TYPE = 4; + + uint8_t type; + uint16_t record_length; + std::string annotation_text; + + AnnotationRecord(uint8_t *data) + { + type = data[0]; + record_length = data[1] << 8 | data[2]; + annotation_text.insert(annotation_text.end(), &data[3], &data[record_length]); + } + }; + + struct ImageStructureRecord + { + static constexpr int TYPE = 1; + + uint8_t type; + uint16_t record_length; + uint8_t bit_per_pixel; + uint16_t columns_count; + uint16_t lines_count; + uint8_t compression_flag; + + ImageStructureRecord(uint8_t *data) + { + type = data[0]; + record_length = data[1] << 8 | data[2]; + bit_per_pixel = data[3]; + columns_count = data[4] << 8 | data[5]; + lines_count = data[6] << 8 | data[7]; + compression_flag = data[8]; + } + }; + //////////////////////////////////////// + + struct LRITFile + { + bool file_in_progress = false; + bool header_parsed = false; + + std::map custom_flags; + + std::string filename; + int total_header_length; + std::map all_headers; + std::vector lrit_data; + + template + T getHeader() + { + if constexpr (std::is_same_v) + return PrimaryHeader(&lrit_data[0]); + else + return T(&lrit_data[all_headers[T::TYPE]]); + } + + template + bool hasHeader() + { + return all_headers.count(T::TYPE); + } + + void parseHeaders(); + }; +}; \ No newline at end of file