improved DLE parser

This commit is contained in:
Robin Müller 2022-04-09 15:37:17 +02:00
parent bdddee4f81
commit 4e242aa954
No known key found for this signature in database
GPG Key ID: 11D4952C8CCEF814
2 changed files with 104 additions and 34 deletions

View File

@ -4,16 +4,24 @@
#include <fsfw/serviceinterface/ServiceInterface.h> #include <fsfw/serviceinterface/ServiceInterface.h>
DleParser::DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf, DleParser::DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
BufPair decodedBuf, FoundPacketHandler handler, void* args) BufPair decodedBuf, UserHandler handler, void* args)
: decodeRingBuf(decodeRingBuf), : decodeRingBuf(decodeRingBuf),
decoder(decoder), decoder(decoder),
encodedBuf(encodedBuf), encodedBuf(encodedBuf),
decodedBuf(decodedBuf), decodedBuf(decodedBuf),
handler(handler), handler(handler),
args(args) {} ctx(args) {
if (handler == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DleParser::DleParser: Invalid user handler" << std::endl;
#else
sif::printError("DleParser::DleParser: Invalid user handler\n");
#endif
}
}
ReturnValue_t DleParser::passData(uint8_t* data, size_t len) { ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
if (data == nullptr or len == 0) { if (data == nullptr or len == 0 or handler == nullptr) {
return RETURN_FAILED; return RETURN_FAILED;
} }
size_t copyIntoRingBufFromHere = 0; size_t copyIntoRingBufFromHere = 0;
@ -30,8 +38,10 @@ ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
} else { } else {
// Maybe print warning, should not happen // Maybe print warning, should not happen
decodeRingBuf.clear(); decodeRingBuf.clear();
ctx.len = idx; ErrorInfo info;
handleParseError(ErrorTypes::CONSECUTIVE_STX_CHARS, ctx); info.len = idx;
prepareErrorContext(ErrorTypes::CONSECUTIVE_STX_CHARS, info);
handler(ctx);
copyIntoRingBufFromHere = idx; copyIntoRingBufFromHere = idx;
copyAmount = len - idx; copyAmount = len - idx;
} }
@ -44,15 +54,20 @@ ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
result = decoder.decode(data + startIdx, idx + 1 - startIdx, &readLen, decodedBuf.first, result = decoder.decode(data + startIdx, idx + 1 - startIdx, &readLen, decodedBuf.first,
decodedBuf.second, &decodedLen); decodedBuf.second, &decodedLen);
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
if (this->handler != nullptr) { ctx.setType(ContextType::PACKET_FOUND);
this->handler(decodedBuf.first, decodedLen, this->args); ctx.decodedPacket.first = decodedBuf.first;
} ctx.decodedPacket.second = decodedLen;
this->handler(ctx);
} else if (result == DleEncoder::STREAM_TOO_SHORT) { } else if (result == DleEncoder::STREAM_TOO_SHORT) {
ctx.res = result; ErrorInfo info;
handleParseError(ErrorTypes::DECODING_BUF_TOO_SMALL, ctx); info.res = result;
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
handler(ctx);
} else { } else {
ctx.res = result; ErrorInfo info;
handleParseError(ErrorTypes::DECODE_ERROR, ctx); info.res = result;
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
handler(ctx);
} }
decodeRingBuf.clear(); decodeRingBuf.clear();
if ((idx + 1) < len) { if ((idx + 1) < len) {
@ -66,13 +81,17 @@ ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
// to decode it // to decode it
result = decodeRingBuf.writeData(data, idx + 1); result = decodeRingBuf.writeData(data, idx + 1);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
ctx.res = result; ErrorInfo info;
handleParseError(ErrorTypes::RING_BUF_ERROR, ctx); info.res = result;
prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
handler(ctx);
} }
size_t fullEncodedLen = decodeRingBuf.getAvailableReadData(); size_t fullEncodedLen = decodeRingBuf.getAvailableReadData();
if (fullEncodedLen > encodedBuf.second) { if (fullEncodedLen > encodedBuf.second) {
ctx.len = fullEncodedLen; ErrorInfo info;
handleParseError(ErrorTypes::ENCODED_BUF_TOO_SMALL, ctx); info.len = fullEncodedLen;
prepareErrorContext(ErrorTypes::ENCODED_BUF_TOO_SMALL, info);
handler(ctx);
decodeRingBuf.clear(); decodeRingBuf.clear();
} else { } else {
size_t decodedLen = 0; size_t decodedLen = 0;
@ -82,14 +101,21 @@ ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
decodedBuf.second, &decodedLen); decodedBuf.second, &decodedLen);
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
if (this->handler != nullptr) { if (this->handler != nullptr) {
this->handler(decodedBuf.first, decodedLen, this->args); ctx.setType(ContextType::PACKET_FOUND);
ctx.decodedPacket.first = decodedBuf.first;
ctx.decodedPacket.second = decodedLen;
this->handler(ctx);
} }
} else if (result == DleEncoder::STREAM_TOO_SHORT) { } else if (result == DleEncoder::STREAM_TOO_SHORT) {
ctx.res = result; ErrorInfo info;
handleParseError(ErrorTypes::DECODING_BUF_TOO_SMALL, ctx); info.res = result;
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
handler(ctx);
} else { } else {
ctx.res = result; ErrorInfo info;
handleParseError(ErrorTypes::DECODE_ERROR, ctx); info.res = result;
prepareErrorContext(ErrorTypes::DECODE_ERROR, info);
handler(ctx);
} }
decodeRingBuf.clear(); decodeRingBuf.clear();
startFound = false; startFound = false;
@ -103,9 +129,11 @@ ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
} }
} else { } else {
// End data without preceeding STX // End data without preceeding STX
ErrorInfo info;
info.len = idx + 1;
prepareErrorContext(ErrorTypes::CONSECUTIVE_ETX_CHARS, info);
handler(ctx);
decodeRingBuf.clear(); decodeRingBuf.clear();
ctx.len = idx + 1;
handleParseError(ErrorTypes::CONSECUTIVE_ETX_CHARS, ctx);
if ((idx + 1) < len) { if ((idx + 1) < len) {
copyIntoRingBufFromHere = idx + 1; copyIntoRingBufFromHere = idx + 1;
copyAmount = len - idx - 1; copyAmount = len - idx - 1;
@ -120,8 +148,10 @@ ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
if (copyAmount > 0) { if (copyAmount > 0) {
result = decodeRingBuf.writeData(data + copyIntoRingBufFromHere, copyAmount); result = decodeRingBuf.writeData(data + copyIntoRingBufFromHere, copyAmount);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
ctx.res = result; ErrorInfo info;
handleParseError(ErrorTypes::RING_BUF_ERROR, ctx); info.res = result;
prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
handler(ctx);
} }
} }
return RETURN_OK; return RETURN_OK;
@ -138,8 +168,12 @@ void DleParser::defaultFoundPacketHandler(uint8_t* packet, size_t len, void* arg
#endif #endif
} }
void DleParser::handleParseError(ErrorTypes err, ErrorCtx ctx) { void DleParser::defaultErrorHandler(ErrorTypes err, ErrorInfo ctx) {
switch (err) { switch (err) {
case (ErrorTypes::NONE): {
errorPrinter("No error");
break;
}
case (ErrorTypes::DECODE_ERROR): { case (ErrorTypes::DECODE_ERROR): {
errorPrinter("Decode Error"); errorPrinter("Decode Error");
break; break;
@ -183,6 +217,12 @@ void DleParser::errorPrinter(const char* str, const char* opt) {
#endif #endif
} }
void DleParser::prepareErrorContext(ErrorTypes err, ErrorInfo info) {
ctx.setType(ContextType::ERROR);
ctx.error.first = err;
ctx.error.second = info;
}
void DleParser::reset() { void DleParser::reset() {
startFound = false; startFound = false;
decodeRingBuf.clear(); decodeRingBuf.clear();

View File

@ -20,9 +20,11 @@
class DleParser : public HasReturnvaluesIF { class DleParser : public HasReturnvaluesIF {
public: public:
using BufPair = std::pair<uint8_t*, size_t>; using BufPair = std::pair<uint8_t*, size_t>;
using FoundPacketHandler = void (*)(uint8_t* data, size_t len, void* args);
enum class ContextType { PACKET_FOUND, ERROR };
enum class ErrorTypes { enum class ErrorTypes {
NONE,
ENCODED_BUF_TOO_SMALL, ENCODED_BUF_TOO_SMALL,
DECODING_BUF_TOO_SMALL, DECODING_BUF_TOO_SMALL,
DECODE_ERROR, DECODE_ERROR,
@ -31,11 +33,39 @@ class DleParser : public HasReturnvaluesIF {
CONSECUTIVE_ETX_CHARS CONSECUTIVE_ETX_CHARS
}; };
union ErrorCtx { union ErrorInfo {
size_t len; size_t len;
ReturnValue_t res; ReturnValue_t res;
}; };
using ErrorPair = std::pair<ErrorTypes, ErrorInfo>;
struct Context {
public:
Context(void* args) : userArgs(args) { setType(ContextType::PACKET_FOUND); }
void setType(ContextType type) {
if (type == ContextType::PACKET_FOUND) {
error.first = ErrorTypes::NONE;
error.second.len = 0;
} else {
decodedPacket.first = nullptr;
decodedPacket.second = 0;
}
}
ContextType getType() const { return type; }
BufPair decodedPacket = {};
ErrorPair error;
void* userArgs;
private:
ContextType type;
};
using UserHandler = void (*)(const Context& ctx);
/** /**
* Base class constructor * Base class constructor
* @param decodeRingBuf Ring buffer used to store multiple packets to allow detecting DLE packets * @param decodeRingBuf Ring buffer used to store multiple packets to allow detecting DLE packets
@ -49,7 +79,7 @@ class DleParser : public HasReturnvaluesIF {
* @param args Arbitrary user argument * @param args Arbitrary user argument
*/ */
DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf, DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
BufPair decodedBuf, FoundPacketHandler handler, void* args); BufPair decodedBuf, UserHandler handler, void* args);
/** /**
* This function allows to pass new data into the parser. It then scans for DLE packets * This function allows to pass new data into the parser. It then scans for DLE packets
@ -74,23 +104,23 @@ class DleParser : public HasReturnvaluesIF {
* - For buffer length errors, will be set to the detected packet length which is too large * - For buffer length errors, will be set to the detected packet length which is too large
* - For decode or ring buffer errors, will be set to the result returned from the failed call * - For decode or ring buffer errors, will be set to the result returned from the failed call
*/ */
virtual void handleParseError(ErrorTypes err, ErrorCtx ctx); static void defaultErrorHandler(ErrorTypes err, ErrorInfo ctx);
void errorPrinter(const char* str, const char* opt = nullptr); static void errorPrinter(const char* str, const char* opt = nullptr);
void prepareErrorContext(ErrorTypes err, ErrorInfo ctx);
/** /**
* Resets the parser by resetting the internal states and clearing the decoding ring buffer * Resets the parser by resetting the internal states and clearing the decoding ring buffer
*/ */
void reset(); void reset();
private: private:
ErrorCtx ctx;
SimpleRingBuffer& decodeRingBuf; SimpleRingBuffer& decodeRingBuf;
DleEncoder& decoder; DleEncoder& decoder;
BufPair encodedBuf; BufPair encodedBuf;
BufPair decodedBuf; BufPair decodedBuf;
FoundPacketHandler handler = nullptr; UserHandler handler = nullptr;
void* args = nullptr; Context ctx;
bool startFound = false; bool startFound = false;
}; };