diff --git a/globalfunctions/DleEncoder.cpp b/globalfunctions/DleEncoder.cpp index ee934785..d727d665 100644 --- a/globalfunctions/DleEncoder.cpp +++ b/globalfunctions/DleEncoder.cpp @@ -4,50 +4,6 @@ DleEncoder::DleEncoder() {} DleEncoder::~DleEncoder() {} -ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, - size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, - size_t maxDestStreamlen, size_t *decodedLen) { - size_t encodedIndex = 0, decodedIndex = 0; - uint8_t nextByte; - if (*sourceStream != STX) { - return DECODING_ERROR; - } - ++encodedIndex; - while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) - && (sourceStream[encodedIndex] != ETX) - && (sourceStream[encodedIndex] != STX)) { - if (sourceStream[encodedIndex] == DLE) { - nextByte = sourceStream[encodedIndex + 1]; - // The next byte is a DLE character that was escaped by another - // DLE character, so we can write it to the destination stream. - if (nextByte == DLE) { - destStream[decodedIndex] = nextByte; - } else { - // The next byte is a STX, DTX or 0x0D character which - // was escaped by a DLE character - if ((nextByte == 0x42) || (nextByte == 0x43) - || (nextByte == 0x4D)) { - destStream[decodedIndex] = nextByte - 0x40; - } else { - return DECODING_ERROR; - } - } - ++encodedIndex; - } else { - destStream[decodedIndex] = sourceStream[encodedIndex]; - } - ++encodedIndex; - ++decodedIndex; - } - if (sourceStream[encodedIndex] != ETX) { - return DECODING_ERROR; - } else { - *readLen = ++encodedIndex; - *decodedLen = decodedIndex; - return RETURN_OK; - } -} - ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, size_t sourceLen, uint8_t* destStream, size_t maxDestLen, size_t* encodedLen, bool addStxEtx) { @@ -60,39 +16,105 @@ ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, destStream[0] = STX; ++encodedIndex; } - while ((encodedIndex < maxDestLen) && (sourceIndex < sourceLen)) { + + while (encodedIndex < maxDestLen and sourceIndex < sourceLen) { nextByte = sourceStream[sourceIndex]; - if ((nextByte == STX) || (nextByte == ETX) || (nextByte == 0x0D)) { + // STX, ETX and CR characters in the stream need to be escaped with DLE + if (nextByte == STX or nextByte == ETX or nextByte == CARRIAGE_RETURN) { if (encodedIndex + 1 >= maxDestLen) { return STREAM_TOO_SHORT; - } else { + } + else { destStream[encodedIndex] = DLE; ++encodedIndex; - // Escaped byte will be actual byte + 0x40. + /* Escaped byte will be actual byte + 0x40. This prevents + * STX, ETX, and carriage return characters from appearing + * in the encoded data stream at all, so when polling an + * encoded stream, the transmission can be stopped at ETX. + * 0x40 was chosen at random with special requirements: + * - Prevent going from one control char to another + * - Prevent overflow for common characters */ destStream[encodedIndex] = nextByte + 0x40; } - } else if (nextByte == DLE) { + } + // DLE characters are simply escaped with DLE. + else if (nextByte == DLE) { if (encodedIndex + 1 >= maxDestLen) { return STREAM_TOO_SHORT; - } else { + } + else { destStream[encodedIndex] = DLE; ++encodedIndex; destStream[encodedIndex] = DLE; } - } else { + } + else { destStream[encodedIndex] = nextByte; } ++encodedIndex; ++sourceIndex; } - if ((sourceIndex == sourceLen) && (encodedIndex < maxDestLen)) { + + if (sourceIndex == sourceLen and encodedIndex < maxDestLen) { if (addStxEtx) { destStream[encodedIndex] = ETX; ++encodedIndex; } *encodedLen = encodedIndex; return RETURN_OK; - } else { + } + else { return STREAM_TOO_SHORT; } } + +ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, + size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, + size_t maxDestStreamlen, size_t *decodedLen) { + size_t encodedIndex = 0, decodedIndex = 0; + uint8_t nextByte; + if (*sourceStream != STX) { + return DECODING_ERROR; + } + ++encodedIndex; + + while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) + && (sourceStream[encodedIndex] != ETX) + && (sourceStream[encodedIndex] != STX)) { + if (sourceStream[encodedIndex] == DLE) { + nextByte = sourceStream[encodedIndex + 1]; + // The next byte is a DLE character that was escaped by another + // DLE character, so we can write it to the destination stream. + if (nextByte == DLE) { + destStream[decodedIndex] = nextByte; + } + else { + /* The next byte is a STX, DTX or 0x0D character which + * was escaped by a DLE character. The actual byte was + * also encoded by adding + 0x40 to preven having control chars, + * in the stream at all, so we convert it back. */ + if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) { + destStream[decodedIndex] = nextByte - 0x40; + } else { + return DECODING_ERROR; + } + } + ++encodedIndex; + } + else { + destStream[decodedIndex] = sourceStream[encodedIndex]; + } + ++encodedIndex; + ++decodedIndex; + } + + if (sourceStream[encodedIndex] != ETX) { + return DECODING_ERROR; + } + else { + *readLen = ++encodedIndex; + *decodedLen = decodedIndex; + return RETURN_OK; + } +} + diff --git a/globalfunctions/DleEncoder.h b/globalfunctions/DleEncoder.h index 0f4a4c8f..36cb1d3f 100644 --- a/globalfunctions/DleEncoder.h +++ b/globalfunctions/DleEncoder.h @@ -14,9 +14,15 @@ * This encoder can be used to achieve a basic transport layer when using * char based transmission systems. * The passed source strean is converted into a encoded stream by adding - * a STX marker at the startr of the stream and an ETX marker at the end of - * the stream. Any STX, ETX and DLE occurences in the source stream are escaped - * by a DLE character. + * a STX marker at the start of the stream and an ETX marker at the end of + * the stream. Any STX, ETX, DLE and CR occurences in the source stream are + * escaped by a DLE character. The encoder also replaces escaped control chars + * by another char, so STX, ETX and CR should not appear anywhere in the actual + * encoded data stream. + * + * When using a strictly char based reception of packets enoded with DLE, + * STX can be used to notify a reader that actual data will start to arrive + * while ETX can be used to notify the reader that the data has ended. */ class DleEncoder: public HasReturnvaluesIF { private: @@ -29,12 +35,13 @@ public: static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02); //! Start Of Text character. First character is encoded stream - static const uint8_t STX = 0x02; + static constexpr uint8_t STX = 0x02; //! End Of Text character. Last character in encoded stream - static const uint8_t ETX = 0x03; + static constexpr uint8_t ETX = 0x03; //! Data Link Escape character. Used to escape STX, ETX and DLE occurences //! in the source stream. - static const uint8_t DLE = 0x10; + static constexpr uint8_t DLE = 0x10; + static constexpr uint8_t CARRIAGE_RETURN = 0x0D; /** * Encodes the give data stream by preceding it with the STX marker @@ -54,7 +61,7 @@ public: bool addStxEtx = true); /** - * Converts an encoded stream back + * Converts an encoded stream back. * @param sourceStream * @param sourceStreamLen * @param readLen