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

View File

@ -20,9 +20,11 @@
class DleParser : public HasReturnvaluesIF {
public:
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 {
NONE,
ENCODED_BUF_TOO_SMALL,
DECODING_BUF_TOO_SMALL,
DECODE_ERROR,
@ -31,11 +33,39 @@ class DleParser : public HasReturnvaluesIF {
CONSECUTIVE_ETX_CHARS
};
union ErrorCtx {
union ErrorInfo {
size_t len;
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
* @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
*/
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
@ -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 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
*/
void reset();
private:
ErrorCtx ctx;
SimpleRingBuffer& decodeRingBuf;
DleEncoder& decoder;
BufPair encodedBuf;
BufPair decodedBuf;
FoundPacketHandler handler = nullptr;
void* args = nullptr;
UserHandler handler = nullptr;
Context ctx;
bool startFound = false;
};