#pragma once #include #include #include #include #include /** * @brief This base helper class can be used to extract DLE encoded packets from a data stream * @details * The core API of the parser takes received packets which can contains DLE packets. The parser * can deal with DLE packets split across multiple packets. It does so by using a dedicated * decoding ring buffer. The user can process received packets and detect errors by * overriding two provided virtual methods. This also allows detecting multiple DLE packets * inside one passed packet. */ class DleParser : public HasReturnvaluesIF { public: using BufPair = std::pair; enum class ContextType { PACKET_FOUND, ERROR }; enum class ErrorTypes { NONE, ENCODED_BUF_TOO_SMALL, DECODING_BUF_TOO_SMALL, DECODE_ERROR, RING_BUF_ERROR, CONSECUTIVE_STX_CHARS, CONSECUTIVE_ETX_CHARS }; union ErrorInfo { size_t len; ReturnValue_t res; }; using ErrorPair = std::pair; 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 * split across multiple packets * @param decoder Decoder instance * @param encodedBuf Buffer used to store encoded packets. It has to be large enough to hold * the largest expected encoded DLE packet size * @param decodedBuf Buffer used to store decoded packets. It has to be large enough to hold the * largest expected decoded DLE packet size * @param handler Function which will be called on a found packet * @param args Arbitrary user argument */ DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf, BufPair decodedBuf, UserHandler handler, void* args); /** * This function allows to pass new data into the parser. It then scans for DLE packets * automatically and inserts (part of) the packet into a ring buffer if necessary. * @param data * @param len * @return */ ReturnValue_t passData(uint8_t* data, size_t len); /** * Example found packet handler * function call * @param packet Decoded packet * @param len Length of detected packet */ void defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args); /** * Will be called if an error occured in the #passData call * @param err * @param ctx Context information depending on the error type * - 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 */ static void defaultErrorHandler(ErrorTypes err, ErrorInfo ctx); 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: SimpleRingBuffer& decodeRingBuf; DleEncoder& decoder; BufPair encodedBuf; BufPair decodedBuf; UserHandler handler = nullptr; Context ctx; bool startFound = false; };