Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow for unknow prns #14

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 57 additions & 23 deletions examples/novatel/rangecmp/range_decompressor_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ int main(int argc, char* argv[])

if (argc < 3)
{
pclLogger->info("ERROR: Need to specify a JSON message definitions DB, an input file and an output "
"format.\n");
pclLogger->info("Example: converter.exe <path to Json DB> <path to input file> <output format>\n");
pclLogger->error("ERROR: Need to specify a JSON message definitions DB, an input file and an output "
"format.\n");
pclLogger->error("Example: converter.exe <path to Json DB> <path to input file> <output format>\n");
return -1;
}
if (argc == 4) { sEncodeFormat = argv[3]; }
Expand Down Expand Up @@ -135,15 +135,19 @@ int main(int argc, char* argv[])
stReadData.uiDataSize = sizeof(acFileStreamBuffer);

unsigned char acFrameBuffer[MAX_ASCII_MESSAGE_LENGTH];
unsigned char* pucReadBuffer = acFrameBuffer;
unsigned char* pucFrameBuffer = acFrameBuffer;
unsigned char acEncodeBuffer[MAX_ASCII_MESSAGE_LENGTH];
unsigned char* pucEncodedMessageBuffer = acEncodeBuffer;

InputFileStream clIFS(sInFilename.c_str());
OutputFileStream clOFS(sInFilename.append(".DECOMPRESSED.").append(sEncodeFormat).c_str());
OutputFileStream clUnknownBytesOFS(sInFilename.append(".UNKNOWN").c_str());
StreamReadStatus stReadStatus;

STATUS eStatus = STATUS::UNKNOWN;
auto eFramerStatus = STATUS::UNKNOWN; // Framer Status
auto eDecompressStatus = STATUS::UNKNOWN; // Decompressor Status
auto eDecoderStatus = STATUS::UNKNOWN; // Decoder Status
auto eEncoderStatus = STATUS::UNKNOWN; // Encoder Status
Comment on lines +147 to +150
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont see the point of making a description for a variable in a comment that is pretty much the same as the variable name


IntermediateHeader stHeader;
IntermediateMessage stMessage;
Expand All @@ -154,50 +158,79 @@ int main(int argc, char* argv[])
auto start = std::chrono::system_clock::now();
uint32_t uiCompletedMessages = 0;
do {
pucReadBuffer = acFrameBuffer;
pucFrameBuffer = acFrameBuffer;

// Get frame, null-terminate.
eStatus = clFramer.GetFrame(pucReadBuffer, MAX_ASCII_MESSAGE_LENGTH, stMetaData);
if (eStatus == STATUS::SUCCESS)
eFramerStatus = clFramer.GetFrame(pucFrameBuffer, MAX_ASCII_MESSAGE_LENGTH, stMetaData);
if (eFramerStatus == STATUS::SUCCESS)
{
if (stMetaData.bResponse)
{
clUnknownBytesOFS.WriteData(reinterpret_cast<char*>(pucFrameBuffer), stMetaData.uiLength);
continue;
}
// Decode the header. Get meta data here and populate the Intermediate header.
eStatus = clHeaderDecoder.Decode(pucReadBuffer, stHeader, stMetaData);
if (eStatus == STATUS::SUCCESS)
eDecoderStatus = clHeaderDecoder.Decode(pucFrameBuffer, stHeader, stMetaData);
if (eDecoderStatus == STATUS::SUCCESS)
{
eStatus = clRangeDecompressor.Decompress(pucReadBuffer, MAX_ASCII_MESSAGE_LENGTH, stMetaData, eEncodeFormat);
if (eStatus == STATUS::SUCCESS)
// Unknown PRNs are, by default, excluded from the range data.
bool bAllowInvalidObs = true;
eDecompressStatus =
clRangeDecompressor.Decompress(pucFrameBuffer, MAX_ASCII_MESSAGE_LENGTH, stMetaData, eEncodeFormat, bAllowInvalidObs);
if (eDecompressStatus == STATUS::SUCCESS)
{
uiCompletedMessages++;
uint32_t uiBytesWritten = clOFS.WriteData(reinterpret_cast<char*>(pucReadBuffer), stMetaData.uiLength);
uint32_t uiBytesWritten = clOFS.WriteData(reinterpret_cast<char*>(pucFrameBuffer), stMetaData.uiLength);
if (stMetaData.uiLength == uiBytesWritten)
{
pucReadBuffer[stMetaData.uiLength] = '\0';
pclLogger->info("Decompressed: ({}) {}", stMetaData.uiLength, reinterpret_cast<char*>(pucReadBuffer));
pucFrameBuffer[stMetaData.uiLength] = '\0';
pclLogger->info("Decompressed: ({}) {}", stMetaData.uiLength, reinterpret_cast<char*>(pucFrameBuffer));
}
else { pclLogger->error("Could only write {}/{} bytes.", uiBytesWritten, stMessageData.uiMessageLength); }
}
else if (eStatus == STATUS::UNSUPPORTED)
else if (eDecompressStatus == STATUS::UNSUPPORTED)
{
if (eStatus == STATUS::SUCCESS)
if (eDecoderStatus == STATUS::SUCCESS)
{
stHeader.usMessageID = stMetaData.usMessageID;
eStatus = clMessageDecoder.Decode((pucReadBuffer + stMetaData.uiHeaderLength), stMessage, stMetaData);
if (eStatus == STATUS::SUCCESS)
eDecoderStatus = clMessageDecoder.Decode((pucFrameBuffer + stMetaData.uiHeaderLength), stMessage, stMetaData);
if (eDecoderStatus == STATUS::SUCCESS)
{
// Encode our message now that we have everything we need.
eStatus = clEncoder.Encode(&pucEncodedMessageBuffer, MAX_ASCII_MESSAGE_LENGTH, stHeader, stMessage, stMessageData,
stMetaData, eEncodeFormat);
if (eStatus == STATUS::SUCCESS)
eEncoderStatus = clEncoder.Encode(&pucEncodedMessageBuffer, MAX_ASCII_MESSAGE_LENGTH, stHeader, stMessage, stMessageData,
stMetaData, eEncodeFormat);
if (eEncoderStatus == STATUS::SUCCESS)
{
stMessageData.pucMessage[stMessageData.uiMessageLength] = '\0';
pclLogger->info("Encoded: ({}) {}", stMessageData.uiMessageLength, reinterpret_cast<char*>(stMessageData.pucMessage));
}
else
{
clUnknownBytesOFS.WriteData(reinterpret_cast<char*>(pucFrameBuffer), stMetaData.uiLength);
pclLogger->warn("Encoder returned with status code {}", static_cast<int>(eEncoderStatus));
}
}
else
{
clUnknownBytesOFS.WriteData(reinterpret_cast<char*>(pucFrameBuffer), stMetaData.uiLength);
pclLogger->warn("MessageDecoder returned with status code {}", static_cast<int>(eDecoderStatus));
}
}
else
{
clUnknownBytesOFS.WriteData(reinterpret_cast<char*>(pucFrameBuffer), stMetaData.uiLength);
pclLogger->warn("HeaderDecoder returned with status code {}", static_cast<int>(eDecoderStatus));
}
}
else
{
clUnknownBytesOFS.WriteData(reinterpret_cast<char*>(pucFrameBuffer), stMetaData.uiLength);
pclLogger->warn("Decompressor returned with status code {}", static_cast<int>(eDecompressStatus));
}
}
}
else if ((eStatus == STATUS::BUFFER_EMPTY) || (eStatus == STATUS::INCOMPLETE))
else if (eFramerStatus == STATUS::UNKNOWN) { clUnknownBytesOFS.WriteData(reinterpret_cast<char*>(pucFrameBuffer), stMetaData.uiLength); }
else if ((eFramerStatus == STATUS::BUFFER_EMPTY) || (eFramerStatus == STATUS::INCOMPLETE))
{
// Read from file, write to framer.
stReadStatus = clIFS.ReadData(stReadData);
Expand All @@ -209,6 +242,7 @@ int main(int argc, char* argv[])

clFramer.Write(reinterpret_cast<unsigned char*>(stReadData.cData), stReadStatus.uiCurrentStreamRead);
}
else { pclLogger->warn("Framer returned with status code {}", static_cast<int>(eFramerStatus)); }
} while (true);

std::chrono::duration<double> elapsed_seconds = std::chrono::system_clock::now() - start;
Expand Down
8 changes: 4 additions & 4 deletions src/decoders/novatel/api/rangecmp/range_decompressor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class RangeDecompressor
void ShutdownLogger();

[[nodiscard]] STATUS Decompress(unsigned char* pucRangeMessageBuffer_, uint32_t uiRangeMessageBufferSize_, MetaDataStruct& stMetaData_,
ENCODEFORMAT eFormat_ = ENCODEFORMAT::UNSPECIFIED);
ENCODEFORMAT eFormat_ = ENCODEFORMAT::UNSPECIFIED, bool bAllowInvalidObs = false);

private:
Filter clMyRangeCmpFilter;
Expand Down Expand Up @@ -102,13 +102,13 @@ class RangeDecompressor
template <bool bIsSecondary>
void DecompressDifferentialBlock(uint8_t** ppucDataPointer_, RangeCmp4MeasurementSignalBlockStruct& stDifferentialBlock_,
const RangeCmp4MeasurementSignalBlockStruct& stReferenceBlock_, double dSecondOffset_);
void PopulateNextRangeData(RangeDataStruct& stRangeData_, const RangeCmp4MeasurementSignalBlockStruct& stBlock_,
bool PopulateNextRangeData(RangeDataStruct& stRangeData_, const RangeCmp4MeasurementSignalBlockStruct& stBlock_,
const MetaDataStruct& stMetaData_, const ChannelTrackingStatusStruct& stChannelTrackingStatus_, uint32_t uiPRN_,
char cGLONASSFrequencyNumber_);
char cGLONASSFrequencyNumber_, bool bAllowInvalidObs);

void RangeCmpToRange(const RangeCmpStruct& stRangeCmpMessage_, RangeStruct& stRangeMessage_);
void RangeCmp2ToRange(const RangeCmp2Struct& stRangeCmp2Message_, RangeStruct& stRangeMessage_, const MetaDataStruct& stMetaData_);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to allow for invalid obs from RangeCMP1-2? I'm unsure if they can even have them or if it's just RangeCMP4.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unsure as well, but this change only shows invalid observations if desired, with the default configuration being that it doesn't show them. Anyone turning this on likely knows what they want to see anyways.

void RangeCmp4ToRange(uint8_t* pucCompressedData_, RangeStruct& stRangeMessage_, const MetaDataStruct& pstMetaData_);
void RangeCmp4ToRange(uint8_t* pucCompressedData_, RangeStruct& stRangeMessage_, const MetaDataStruct& pstMetaData_, bool bAllowInvalidObs);

// Protected members to be accessed by test child classes.
protected:
Expand Down
52 changes: 35 additions & 17 deletions src/decoders/novatel/src/rangecmp/range_decompressor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,10 +561,12 @@ void RangeDecompressor::DecompressDifferentialBlock(uint8_t** ppucDataPointer_,
//! Populates a provided RangeData structure from the RANGECMP4 blocks
//! provided.
//------------------------------------------------------------------------------
void RangeDecompressor::PopulateNextRangeData(RangeDataStruct& stRangeData_, const RangeCmp4MeasurementSignalBlockStruct& stBlock_,
bool RangeDecompressor::PopulateNextRangeData(RangeDataStruct& stRangeData_, const RangeCmp4MeasurementSignalBlockStruct& stBlock_,
const MetaDataStruct& stMetaData_, const ChannelTrackingStatusStruct& stChannelTrackingStatus_,
uint32_t uiPRN_, char cGLONASSFrequencyNumber_)
uint32_t uiPRN_, char cGLONASSFrequencyNumber_, bool bAllowInvalidObs)
{
bool bHasValidObsStatus = true;

double dSignalWavelength =
GetSignalWavelength(stChannelTrackingStatus_, static_cast<int16_t>(cGLONASSFrequencyNumber_ - GLONASS_FREQUENCY_NUMBER_OFFSET));

Expand All @@ -573,13 +575,24 @@ void RangeDecompressor::PopulateNextRangeData(RangeDataStruct& stRangeData_, con
switch (stChannelTrackingStatus_.eSatelliteSystem)
{
case ChannelTrackingStatusStruct::SATELLITE_SYSTEM::GLONASS:
// If ternary returns true, documentation suggests we should save this PRN as
// GLONASS_SLOT_UNKNOWN_UPPER_LIMIT - cGLONASSFrequencyNumber_. However, this
// would output the PRN as an actual valid Slot ID, which is not true. We will
// set this to 0 here because 0 is considered an unknown/invalid GLONASS Slot ID.
stRangeData_.usPRN = (GLONASS_SLOT_UNKNOWN_LOWER_LIMIT <= uiPRN_ && uiPRN_ <= GLONASS_SLOT_UNKNOWN_UPPER_LIMIT)
? 0
: static_cast<uint16_t>(uiPRN_) + GLONASS_SLOT_OFFSET - 1;
// If ternary returns true, documentation suggests we should save this PRN as 63 - GLONASS Frequency Number.
// [ https://docs.novatel.com/OEM7/Content/Logs/RANGECMP4.htm?Highlight=rangecmp4 - Measurement Block Header ]
// It is important to note however, that this would output the PRN as an actual valid Slot ID, which is not true.
// If we allow Unknown obs, then we do the calculation, otherwise, we default to 0
if (bAllowInvalidObs)
{
stRangeData_.usPRN = (GLONASS_SLOT_UNKNOWN_LOWER_LIMIT <= uiPRN_ && uiPRN_ <= GLONASS_SLOT_UNKNOWN_UPPER_LIMIT)
? 63 - static_cast<int16_t>(cGLONASSFrequencyNumber_)
: static_cast<uint16_t>(uiPRN_) + GLONASS_SLOT_OFFSET - 1;
}
else
{
stRangeData_.usPRN = (GLONASS_SLOT_UNKNOWN_LOWER_LIMIT <= uiPRN_ && uiPRN_ <= GLONASS_SLOT_UNKNOWN_UPPER_LIMIT)
? 0
: static_cast<uint16_t>(uiPRN_) + GLONASS_SLOT_OFFSET - 1;
if (stRangeData_.usPRN == 0) { bHasValidObsStatus = false; }
}

break;
case ChannelTrackingStatusStruct::SATELLITE_SYSTEM::SBAS:
stRangeData_.usPRN = (SBAS_PRN_OFFSET_120_LOWER_LIMIT <= uiPRN_ && uiPRN_ <= SBAS_PRN_OFFSET_120_UPPER_LIMIT)
Expand All @@ -592,8 +605,6 @@ void RangeDecompressor::PopulateNextRangeData(RangeDataStruct& stRangeData_, con
default: stRangeData_.usPRN = static_cast<uint16_t>(uiPRN_); break;
}

if (stRangeData_.usPRN == 0) { throw std::runtime_error("PopulateNextRangeData(): PRN outside of limits"); }

// any fields flagged as invalid are set to NaN and appear in the log as such
stRangeData_.sGLONASSFrequency = static_cast<int16_t>(cGLONASSFrequencyNumber_);
stRangeData_.dPSR = stBlock_.bValidPSR ? stBlock_.dPSR : std::numeric_limits<double>::quiet_NaN();
Expand All @@ -607,6 +618,7 @@ void RangeDecompressor::PopulateNextRangeData(RangeDataStruct& stRangeData_, con
stRangeData_.fLockTime = DetermineRangeCmp4ObservationLocktime(
stMetaData_, stBlock_.ucLockTimeBitfield, stChannelTrackingStatus_.eSatelliteSystem, stChannelTrackingStatus_.eSignalType, uiPRN_);
stRangeData_.uiChannelTrackingStatus = stChannelTrackingStatus_.GetAsWord();
return bHasValidObsStatus;
}

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -743,7 +755,8 @@ void RangeDecompressor::RangeCmp2ToRange(const RangeCmp2Struct& stRangeCmp2Messa
//! Decompress a buffer containing a RANGECMP4 message and translate it into
//! a RANGE message.
//------------------------------------------------------------------------------
void RangeDecompressor::RangeCmp4ToRange(uint8_t* pucCompressedData_, RangeStruct& stRangeMessage_, const MetaDataStruct& stMetaData_)
void RangeDecompressor::RangeCmp4ToRange(uint8_t* pucCompressedData_, RangeStruct& stRangeMessage_, const MetaDataStruct& stMetaData_,
bool bAllowInvalidObs)
{
uint8_t* pucTempDataPointer = pucCompressedData_;

Expand Down Expand Up @@ -789,6 +802,8 @@ void RangeDecompressor::RangeCmp4ToRange(uint8_t* pucCompressedData_, RangeStruc
vSignals.clear();
vPRNs.clear();

bool bHasValidObsStatus = false;

// Does this message have any data for this satellite system?
if (usSatelliteSystems & (1UL << static_cast<uint16_t>(eCurrentSatelliteSystem)))
{
Expand Down Expand Up @@ -868,8 +883,11 @@ void RangeDecompressor::RangeCmp4ToRange(uint8_t* pucCompressedData_, RangeStruc
else { DecompressReferenceBlock<true>(&pucTempDataPointer, stMeasurementBlock, eMeasurementSource); }

stChannelTrackingStatus = ChannelTrackingStatusStruct(eCurrentSatelliteSystem, eCurrentSignalType, stMeasurementBlock);
PopulateNextRangeData((stRangeMessage_.astRangeData[stRangeMessage_.uiNumberOfObservations++]), stMeasurementBlock,
stMetaData_, stChannelTrackingStatus, uiPRN, stMeasurementBlockHeader.cGLONASSFrequencyNumber);
bHasValidObsStatus = PopulateNextRangeData((stRangeMessage_.astRangeData[stRangeMessage_.uiNumberOfObservations]),
stMeasurementBlock, stMetaData_, stChannelTrackingStatus, uiPRN,
stMeasurementBlockHeader.cGLONASSFrequencyNumber, bAllowInvalidObs);

if (bHasValidObsStatus) { stRangeMessage_.uiNumberOfObservations++; }

// Always store reference blocks.
ammmMyReferenceBlocks[static_cast<uint32_t>(eMeasurementSource)][eCurrentSatelliteSystem][eCurrentSignalType][uiPRN] =
Expand Down Expand Up @@ -920,7 +938,7 @@ void RangeDecompressor::RangeCmp4ToRange(uint8_t* pucCompressedData_, RangeStruc
ChannelTrackingStatusStruct(eCurrentSatelliteSystem, eCurrentSignalType, stMeasurementBlock);
PopulateNextRangeData(stRangeMessage_.astRangeData[stRangeMessage_.uiNumberOfObservations++], stMeasurementBlock,
stMetaData_, stChannelTrackingStatus, uiPRN,
pstReferenceBlockHeader->cGLONASSFrequencyNumber);
pstReferenceBlockHeader->cGLONASSFrequencyNumber, bAllowInvalidObs);
}
else
{
Expand Down Expand Up @@ -958,7 +976,7 @@ void RangeDecompressor::RangeCmp4ToRange(uint8_t* pucCompressedData_, RangeStruc
//------------------------------------------------------------------------------
STATUS
RangeDecompressor::Decompress(unsigned char* pucRangeMessageBuffer_, uint32_t uiRangeMessageBufferSize_, MetaDataStruct& stMetaData_,
ENCODEFORMAT eFormat_)
ENCODEFORMAT eFormat_, bool bAllowInvalidObs)
{
// Check for buffer validity
if (!pucRangeMessageBuffer_) { return STATUS::NULL_PROVIDED; }
Expand Down Expand Up @@ -1002,7 +1020,7 @@ RangeDecompressor::Decompress(unsigned char* pucRangeMessageBuffer_, uint32_t ui
case RANGECMP_MSG_ID: RangeCmpToRange(*reinterpret_cast<RangeCmpStruct*>(pucTempMessagePointer), stRange); break;
case RANGECMP2_MSG_ID: RangeCmp2ToRange(*reinterpret_cast<RangeCmp2Struct*>(pucTempMessagePointer), stRange, stMetaData_); break;
case RANGECMP3_MSG_ID: [[fallthrough]];
case RANGECMP4_MSG_ID: RangeCmp4ToRange(pucTempMessagePointer, stRange, stMetaData_); break;
case RANGECMP4_MSG_ID: RangeCmp4ToRange(pucTempMessagePointer, stRange, stMetaData_, bAllowInvalidObs); break;
default: return STATUS::UNSUPPORTED;
}

Expand Down