diff --git a/src/ncp/hdlc.cpp b/src/ncp/hdlc.cpp index aceb0bae2..6b3d8acd6 100644 --- a/src/ncp/hdlc.cpp +++ b/src/ncp/hdlc.cpp @@ -40,7 +40,7 @@ namespace Hdlc { * This method updates an FCS. * * @param[in] aFcs The FCS to update. - * @param[in] aByte The intput byte value. + * @param[in] aByte The input byte value. * * @returns The updated FCS. * @@ -103,76 +103,102 @@ uint16_t UpdateFcs(uint16_t aFcs, uint8_t aByte) return (aFcs >> 8) ^ sFcsTable[(aFcs ^ aByte) & 0xff]; } -ThreadError Encoder::Init(uint8_t *aOutBuf, uint16_t &aOutLength) + +Encoder::BufferWriteIterator::BufferWriteIterator(void) +{ + mWritePointer = NULL; + mRemainingLength = 0; +} + +ThreadError Encoder::BufferWriteIterator::WriteByte(uint8_t aByte) { ThreadError error = kThreadError_None; - mFcs = kInitFcs; + VerifyOrExit(mRemainingLength > 0, error = kThreadError_NoBufs); - VerifyOrExit(aOutLength > 0, error = kThreadError_NoBufs); - aOutBuf[0] = kFlagSequence; - aOutLength = 1; + *mWritePointer++ = aByte; + mRemainingLength--; exit: return error; } -ThreadError Encoder::Encode(uint8_t aInByte, uint8_t *aOutBuf, uint16_t aOutLength) +bool Encoder::BufferWriteIterator::CanWrite(uint16_t aWriteLength) const +{ + return (mRemainingLength >= aWriteLength); +} + +ThreadError Encoder::Init(BufferWriteIterator &aIterator) +{ + mFcs = kInitFcs; + + return aIterator.WriteByte(kFlagSequence); +} + +ThreadError Encoder::Encode(uint8_t aInByte, BufferWriteIterator &aIterator) { ThreadError error = kThreadError_None; - mFcs = UpdateFcs(mFcs, aInByte); - if (aInByte == kFlagSequence || aInByte == kEscapeSequence) { - VerifyOrExit(mOutOffset + 2 < aOutLength, error = kThreadError_NoBufs); - aOutBuf[mOutOffset++] = kEscapeSequence; - aOutBuf[mOutOffset++] = aInByte ^ 0x20; + VerifyOrExit(aIterator.CanWrite(2) , error = kThreadError_NoBufs); + + aIterator.WriteByte(kEscapeSequence); + aIterator.WriteByte(aInByte ^ 0x20); } else { - VerifyOrExit(mOutOffset + 1 < aOutLength, error = kThreadError_NoBufs); - aOutBuf[mOutOffset++] = aInByte; + SuccessOrExit(error = aIterator.WriteByte(aInByte)); } + mFcs = UpdateFcs(mFcs, aInByte); + exit: return error; } -ThreadError Encoder::Encode(const uint8_t *aInBuf, uint16_t aInLength, uint8_t *aOutBuf, uint16_t &aOutLength) +ThreadError Encoder::Encode(const uint8_t *aInBuf, uint16_t aInLength, BufferWriteIterator &aIterator) { ThreadError error = kThreadError_None; - - mOutOffset = 0; + BufferWriteIterator oldIterator(aIterator); + uint16_t oldFcs = mFcs; for (int i = 0; i < aInLength; i++) { - SuccessOrExit(error = Encode(aInBuf[i], aOutBuf, aOutLength)); + SuccessOrExit(error = Encode(aInBuf[i], aIterator)); } exit: - aOutLength = mOutOffset; + if (error != kThreadError_None) + { + aIterator = oldIterator; + mFcs = oldFcs; + } + return error; } -ThreadError Encoder::Finalize(uint8_t *aOutBuf, uint16_t &aOutLength) +ThreadError Encoder::Finalize(BufferWriteIterator &aIterator) { ThreadError error = kThreadError_None; + BufferWriteIterator oldIterator(aIterator); + uint16_t oldFcs = mFcs; uint16_t fcs = mFcs; - mOutOffset = 0; - fcs ^= 0xffff; - SuccessOrExit(error = Encode(fcs, aOutBuf, aOutLength)); - SuccessOrExit(error = Encode(fcs >> 8, aOutBuf, aOutLength)); + SuccessOrExit(error = Encode(fcs, aIterator)); + SuccessOrExit(error = Encode(fcs >> 8, aIterator)); - VerifyOrExit(mOutOffset < aOutLength, error = kThreadError_NoBufs); - aOutBuf[mOutOffset++] = kFlagSequence; - - aOutLength = mOutOffset; + SuccessOrExit(error = aIterator.WriteByte(kFlagSequence)); exit: + if (error != kThreadError_None) + { + aIterator = oldIterator; + mFcs = oldFcs; + } + return error; } diff --git a/src/ncp/hdlc.hpp b/src/ncp/hdlc.hpp index 8ee16a44b..8c2806024 100644 --- a/src/ncp/hdlc.hpp +++ b/src/ncp/hdlc.hpp @@ -27,7 +27,7 @@ /** * @file - * This file includes definitions for an HDLC-lite encoder and decoer. + * This file includes definitions for an HDLC-lite encoder and decoder. */ #ifndef HDLC_HPP_ @@ -54,48 +54,97 @@ namespace Hdlc { class Encoder { public: + /** - * This method begins an HDLC frame and puts the initial bytes into @p aOutBuf. + * This class defines a write iterator into a buffer used by Encoder. * - * @param[in] aOutBuf A pointer to the output buffer. - * @param[inout] aOutLength On entry, the output buffer size; On exit, the output length. + * Hdlc users should sub-class this to add the actual buffer space. + */ + class BufferWriteIterator + { + public: + + /** + * This method writes a byte to the buffer and updates the iterator (if space is available). + * + * @retval kThreadError_None Successfully wrote the byte and updates the iterator. + * @retval kThreadError_NoBufs Insufficient buffer space. + * + */ + ThreadError WriteByte(uint8_t aByte); + + /** + * This method checks if there is buffer space available to write @p aWriteLength bytes. + * + * param[in] aWriteLength Number of bytes to write. + * + * @retval true Enough buffer space available to write the requested number of bytes. + * @retval false Insufficient buffer space to write the requested number of bytes. + * + */ + bool CanWrite(uint16_t aWriteLength) const; + + protected: + + BufferWriteIterator(void); ///< Protected constructor to ensure no direct instantiation. + + uint8_t *mWritePointer; ///< A pointer to current write position in the buffer. + uint16_t mRemainingLength; ///< Number of remaining bytes available to write. + }; + + /** + * This method begins an HDLC frame and puts the initial bytes into a buffer at the given @p aIterator. + * + * @param[inout] aIterator A reference to a buffer write iterator. On successful exit, the iterator is updated. * * @retval kThreadError_None Successfully started the HDLC frame. * @retval kThreadError_NoBufs Insufficient buffer space available to start the HDLC frame. * */ - ThreadError Init(uint8_t *aOutBuf, uint16_t &aOutLength); + ThreadError Init(BufferWriteIterator &aIterator); /** - * This method encodes the frame. + * This method encodes a single byte into a buffer at @p aIterator. * - * @param[in] aInBuf A pointer to the input buffer. - * @param[in] aInLength The number of bytes in @p aInBuf to encode. - * @param[out] aOutBuf A pointer to the output buffer. - * @param[out] aOutLength On exit, the number of bytes placed in @p aOutBuf. + * If there is no space to add the byte, the write iterator remains the same. + * + * @param[in] aInByte A byte to encode and add. + * @param[inout] aIterator A reference to a write buffer iterator. On successful exit, the iterator is updated. + * + * @retval kThreadError_None Successfully encoded and added the byte. + * @retval kThreadError_NoBufs Insufficient buffer space available to encode and add the byte. + * + */ + ThreadError Encode(uint8_t aInByte, BufferWriteIterator &aIterator); + + /** + * This method encodes the frame into a buffer at @p aIterator. + * + * This method returns success only if there is space in buffer to encode the entire frame. If there is no space + * to encode the entire frame, the write iterator remains the same. + * + * @param[in] aInBuf A pointer to the input buffer. + * @param[in] aInLength The number of bytes in @p aInBuf to encode. + * @param[inout] aIterator A reference to a write buffer iterator. On successful exit, the iterator is updated. * * @retval kThreadError_None Successfully encoded the HDLC frame. * @retval kThreadError_NoBufs Insufficient buffer space available to encode the HDLC frame. * */ - ThreadError Encode(const uint8_t *aInBuf, uint16_t aInLength, uint8_t *aOutBuf, uint16_t &aOutLength); + ThreadError Encode(const uint8_t *aInBuf, uint16_t aInLength, BufferWriteIterator &aIterator); /** - * This method ends an HDLC frame and puts the initial bytes into @p aOutBuf. + * This method finalizes an HDLC frame. * - * @param[in] aOutBuf A pointer to the output buffer. - * @param[inout] aOutLength On entry, the output buffer size; On exit, the output length. + * @param[inout] aIterator A reference to a write buffer iterator. On successful exit, the iterator is updated. * * @retval kThreadError_None Successfully ended the HDLC frame. * @retval kThreadError_NoBufs Insufficient buffer space available to end the HDLC frame. * */ - ThreadError Finalize(uint8_t *aOutBuf, uint16_t &aOutLength); + ThreadError Finalize(BufferWriteIterator &aIterator); private: - ThreadError Encode(uint8_t aInByte, uint8_t *aOutBuf, uint16_t aOutLength); - - uint16_t mOutOffset; uint16_t mFcs; }; diff --git a/src/ncp/ncp_uart.cpp b/src/ncp/ncp_uart.cpp index 4dbad12f8..bdfaeb273 100644 --- a/src/ncp/ncp_uart.cpp +++ b/src/ncp/ncp_uart.cpp @@ -47,33 +47,58 @@ extern "C" void otNcpInit(void) sNcpUart = new(&sNcpRaw) NcpUart; } +NcpUart::SendHdlcBuffer::SendHdlcBuffer(void) + : BufferWriteIterator() +{ + Reset(); +} + +void +NcpUart::SendHdlcBuffer::Reset(void) +{ + mWritePointer = mBuffer; + mRemainingLength = sizeof(mBuffer); +} + +uint16_t +NcpUart::SendHdlcBuffer::GetLength(void) const +{ + return static_cast(mWritePointer - mBuffer); +} + +const uint8_t * +NcpUart::SendHdlcBuffer::GetBuffer(void) const +{ + return mBuffer; +} + +uint16_t +NcpUart::SendHdlcBuffer::GetRemainingLength(void) const +{ + return mRemainingLength; +} + NcpUart::NcpUart(): NcpBase(), - mFrameDecoder(mReceiveFrame, sizeof(mReceiveFrame), &HandleFrame, this) + mFrameDecoder(mReceiveFrame, sizeof(mReceiveFrame), &HandleFrame, this), + mSendFrame() { } uint16_t NcpUart::OutboundFrameGetRemaining(void) { - return static_cast(sizeof(mSendFrame) - (mSendFrameIter - mSendFrame)); + return mSendFrame.GetRemainingLength(); } ThreadError NcpUart::OutboundFrameBegin(void) { ThreadError errorCode; - uint16_t outLength; - mSendFrameIter = mSendFrame; - outLength = OutboundFrameGetRemaining(); + mSendFrame.Reset(); - errorCode = mFrameEncoder.Init(mSendFrameIter, outLength); - - if (errorCode == kThreadError_None) - { - mSendFrameIter += outLength; - } + errorCode = mFrameEncoder.Init(mSendFrame); return errorCode; } @@ -82,14 +107,8 @@ ThreadError NcpUart::OutboundFrameFeedData(const uint8_t *frame, uint16_t frameLength) { ThreadError errorCode; - uint16_t outLength(OutboundFrameGetRemaining()); - errorCode = mFrameEncoder.Encode(frame, frameLength, mSendFrameIter, outLength); - - if (errorCode == kThreadError_None) - { - mSendFrameIter += outLength; - } + errorCode = mFrameEncoder.Encode(frame, frameLength, mSendFrame); return errorCode; } @@ -122,14 +141,12 @@ ThreadError NcpUart::OutboundFrameSend(void) { ThreadError errorCode; - uint16_t outLength(OutboundFrameGetRemaining()); - errorCode = mFrameEncoder.Finalize(mSendFrameIter, outLength); + errorCode = mFrameEncoder.Finalize(mSendFrame); if (errorCode == kThreadError_None) { - mSendFrameIter += outLength; - errorCode = otPlatUartSend(mSendFrame, mSendFrameIter - mSendFrame); + errorCode = otPlatUartSend(mSendFrame.GetBuffer(), mSendFrame.GetLength()); } if (errorCode == kThreadError_None) diff --git a/src/ncp/ncp_uart.hpp b/src/ncp/ncp_uart.hpp index 788ffd86a..99e598862 100644 --- a/src/ncp/ncp_uart.hpp +++ b/src/ncp/ncp_uart.hpp @@ -62,9 +62,22 @@ private: Hdlc::Encoder mFrameEncoder; Hdlc::Decoder mFrameDecoder; - uint8_t mSendFrame[1500]; - uint8_t mReceiveFrame[1500]; - uint8_t *mSendFrameIter; + class SendHdlcBuffer : public Hdlc::Encoder::BufferWriteIterator + { + public: + SendHdlcBuffer(void); + + void Reset(void); + uint16_t GetLength(void) const; + uint16_t GetRemainingLength(void) const; + const uint8_t *GetBuffer(void) const; + + private: + uint8_t mBuffer[1500]; + }; + + SendHdlcBuffer mSendFrame; + uint8_t mReceiveFrame[1500]; }; } // namespace Thread