mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
Start new LRIT system work, convert ELEKTRO
This commit is contained in:
parent
a86d578827
commit
b03d24fa70
16 changed files with 618 additions and 716 deletions
|
|
@ -22,16 +22,16 @@ namespace Util
|
|||
{
|
||||
|
||||
/**
|
||||
* thread safe pointer class
|
||||
**/
|
||||
* thread safe pointer class
|
||||
**/
|
||||
template <class T>
|
||||
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<T> &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<T> &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<T> &operator=(
|
||||
const CSmartPtr<T> &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<T> &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<F> object to a Util:CSmartPtr<T> object.
|
||||
* Note that this will actually release the original and set it to NULL.
|
||||
* @returns
|
||||
* Util::CSmartPtr<T>.
|
||||
* - 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<F> object to a Util:CSmartPtr<T> object.
|
||||
* Note that this will actually release the original and set it to NULL.
|
||||
* @returns
|
||||
* Util::CSmartPtr<T>.
|
||||
* - the cast operation is not possible because the classes are not suitably related, or
|
||||
* - the original CSmartPtr contains a NULL pointer.
|
||||
**/
|
||||
template <class F>
|
||||
inline static Util::CSmartPtr<T> Cast(
|
||||
Util::CSmartPtr<F> i_From)
|
||||
|
|
@ -213,16 +213,16 @@ namespace Util
|
|||
};
|
||||
|
||||
/**
|
||||
* Casts a Util::CSmartPtr<CFrom> object to a Util:CSmartPtr<CTo> object.
|
||||
* Note that this will actually release the original and set it to NULL.
|
||||
* @returns
|
||||
* Util::CSmartPtr<T>.
|
||||
* - 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<CTo>::Cast() function directly!
|
||||
**/
|
||||
* Casts a Util::CSmartPtr<CFrom> object to a Util:CSmartPtr<CTo> object.
|
||||
* Note that this will actually release the original and set it to NULL.
|
||||
* @returns
|
||||
* Util::CSmartPtr<T>.
|
||||
* - 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<CTo>::Cast() function directly!
|
||||
**/
|
||||
template <class CTo, class CFrom>
|
||||
inline Util::CSmartPtr<CTo> SmartPtrCast(
|
||||
Util::CSmartPtr<CFrom> i_From)
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "lrit_data_decoder.h"
|
||||
#include "lrit_data.h"
|
||||
#include "resources.h"
|
||||
#include "imgui/imgui_image.h"
|
||||
#include "logger.h"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "lrit_data_decoder.h"
|
||||
#include "lrit_data.h"
|
||||
#include "resources.h"
|
||||
#include "imgui/imgui_image.h"
|
||||
#include "logger.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<uint8_t> lrit_data;
|
||||
|
||||
bool is_jpeg_compressed, is_wt_compressed;
|
||||
std::string current_filename;
|
||||
std::vector<uint8_t> decompression_buffer;
|
||||
std::map<int, int> 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<ELEKTRO221Composer> elektro_221_composer_full_disk;
|
||||
std::shared_ptr<ELEKTRO321Composer> 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
|
||||
|
|
@ -1,289 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#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<std::string, std::string> 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<std::string> fields = splitString(ancillary_text, ';');
|
||||
|
||||
for (std::string &field : fields)
|
||||
{
|
||||
std::vector<std::string> 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];
|
||||
}
|
||||
};*/
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "lrit_data_decoder.h"
|
||||
#include "lrit_data.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace elektro
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#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];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,11 @@
|
|||
#include "module_elektro_lrit_data_decoder.h"
|
||||
#include <fstream>
|
||||
#include "common/ccsds/ccsds_1_0_1024/demuxer.h"
|
||||
#include "common/ccsds/ccsds_1_0_1024/vcdu.h"
|
||||
#include "logger.h"
|
||||
#include <filesystem>
|
||||
#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<int, std::shared_ptr<LRITDataDecoder>> decMap : decoders)
|
||||
for (auto &decMap : all_wip_images)
|
||||
{
|
||||
std::shared_ptr<LRITDataDecoder> dec = decMap.second;
|
||||
auto &dec = decMap.second;
|
||||
|
||||
if (dec->textureID > 0)
|
||||
{
|
||||
|
|
@ -70,7 +65,40 @@ namespace elektro
|
|||
|
||||
logger->info("Demultiplexing and deframing...");
|
||||
|
||||
std::map<int, std::shared_ptr<ccsds::ccsds_1_0_1024::Demuxer>> demuxers;
|
||||
// std::map<int, std::shared_ptr<ccsds::ccsds_1_0_1024::Demuxer>> 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<int, std::shared_ptr<ccsds::ccsds_1_0_1024::Demuxer>>(vcdu.vcid, std::make_shared<ccsds::ccsds_1_0_1024::Demuxer>(884, false)));
|
||||
|
||||
// Demux
|
||||
std::vector<ccsds::CCSDSPacket> 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<int, std::shared_ptr<LRITDataDecoder>>(vcdu.vcid, std::make_shared<LRITDataDecoder>(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<const int, std::shared_ptr<LRITDataDecoder>> &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<int, std::shared_ptr<LRITDataDecoder>> decMap : decoders)
|
||||
for (auto &decMap : all_wip_images)
|
||||
{
|
||||
std::shared_ptr<LRITDataDecoder> 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();
|
||||
|
|
|
|||
|
|
@ -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<size_t> filesize;
|
||||
std::atomic<size_t> progress;
|
||||
|
||||
std::map<int, std::shared_ptr<LRITDataDecoder>> decoders;
|
||||
|
||||
std::shared_ptr<ELEKTRO221Composer> elektro_221_composer_full_disk;
|
||||
std::shared_ptr<ELEKTRO321Composer> elektro_321_composer_full_disk;
|
||||
std::shared_ptr<ELEKTRO321Composer> elektro_321_composer_full_disk;
|
||||
std::map<int, SegmentedLRITImageDecoder> 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<int, std::unique_ptr<wip_images>> all_wip_images;
|
||||
|
||||
void processLRITFile(::lrit::LRITFile &file);
|
||||
|
||||
public:
|
||||
ELEKTROLRITDataDecoderModule(std::string input_file, std::string output_file_hint, nlohmann::json parameters);
|
||||
|
|
|
|||
|
|
@ -1,18 +1,9 @@
|
|||
#include "lrit_data_decoder.h"
|
||||
#include "module_elektro_lrit_data_decoder.h"
|
||||
#include "logger.h"
|
||||
#include <fstream>
|
||||
#include "lrit_header.h"
|
||||
#include "crc_table.h"
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#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<int, int>(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<uint8_t> 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<uint8_t> 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<SegmentIdentificationHeader>();
|
||||
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<SegmentIdentificationHeader>();
|
||||
|
||||
std::vector<std::string> 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<wip_images>()});
|
||||
|
||||
std::unique_ptr<wip_images> &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<uint8_t> 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<uint8_t> image(&lrit_data[primary_header.total_header_length], image_structure_record.columns_count, image_structure_record.lines_count, 1);
|
||||
image::Image<uint8_t> 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
|
||||
} // namespace avhrr
|
||||
} // namespace metop
|
||||
41
src-core/common/lrit/crc_table.h
Normal file
41
src-core/common/lrit/crc_table.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
129
src-core/common/lrit/lrit_demux.cpp
Normal file
129
src-core/common/lrit/lrit_demux.cpp
Normal file
|
|
@ -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<LRITFile> 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<int, std::unique_ptr<ccsds::ccsds_1_0_1024::Demuxer>>(vcdu.vcid, std::make_unique<ccsds::ccsds_1_0_1024::Demuxer>(d_mpdu_size, false)));
|
||||
wip_files.insert({vcdu.vcid, std::map<int, LRITFile>()});
|
||||
}
|
||||
|
||||
// Demux
|
||||
std::vector<ccsds::CCSDSPacket> 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<PrimaryHeader>();
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
40
src-core/common/lrit/lrit_demux.h
Normal file
40
src-core/common/lrit/lrit_demux.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include "lrit_file.h"
|
||||
#include "common/ccsds/ccsds_1_0_1024/demuxer.h"
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace lrit
|
||||
{
|
||||
class LRITDemux
|
||||
{
|
||||
private:
|
||||
const int d_mpdu_size;
|
||||
|
||||
private:
|
||||
std::map<int, std::unique_ptr<ccsds::ccsds_1_0_1024::Demuxer>> demuxers;
|
||||
std::map<int, std::map<int, LRITFile>> wip_files;
|
||||
|
||||
std::vector<LRITFile> 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<void(LRITFile &)> onParseHeader =
|
||||
[](LRITFile &) -> void {};
|
||||
std::function<bool(LRITFile &, ccsds::CCSDSPacket &)> onProcessData =
|
||||
[](LRITFile &, ccsds::CCSDSPacket &) -> bool
|
||||
{ return true; };
|
||||
|
||||
public:
|
||||
LRITDemux(int mpdu_size = 884);
|
||||
~LRITDemux();
|
||||
|
||||
std::vector<LRITFile> work(uint8_t *cadu);
|
||||
};
|
||||
};
|
||||
44
src-core/common/lrit/lrit_file.cpp
Normal file
44
src-core/common/lrit/lrit_file.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include "lrit_file.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace lrit
|
||||
{
|
||||
void LRITFile::parseHeaders()
|
||||
{
|
||||
PrimaryHeader primary_header = getHeader<PrimaryHeader>();
|
||||
|
||||
// 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<int, int>(type, i));
|
||||
|
||||
i += record_length;
|
||||
}
|
||||
|
||||
// Check if this has a filename
|
||||
if (all_headers.count(AnnotationRecord::TYPE) > 0)
|
||||
{
|
||||
AnnotationRecord annotation_record = getHeader<AnnotationRecord>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
109
src-core/common/lrit/lrit_file.h
Normal file
109
src-core/common/lrit/lrit_file.h
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
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<int, int> custom_flags;
|
||||
|
||||
std::string filename;
|
||||
int total_header_length;
|
||||
std::map<int, int> all_headers;
|
||||
std::vector<uint8_t> lrit_data;
|
||||
|
||||
template <typename T>
|
||||
T getHeader()
|
||||
{
|
||||
if constexpr (std::is_same_v<T, PrimaryHeader>)
|
||||
return PrimaryHeader(&lrit_data[0]);
|
||||
else
|
||||
return T(&lrit_data[all_headers[T::TYPE]]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool hasHeader()
|
||||
{
|
||||
return all_headers.count(T::TYPE);
|
||||
}
|
||||
|
||||
void parseHeaders();
|
||||
};
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue