#ifndef HDLC_HPP_
#define HDLC_HPP_
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <openthread/error.h>
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/encoding.hpp"
namespace ot {
namespace Hdlc {
class FrameWritePointer
{
public:
bool CanWrite(uint16_t aWriteLength) const { return (mRemainingLength >= aWriteLength); }
otError WriteByte(uint8_t aByte)
{
return CanWrite(sizeof(uint8_t)) ? (*mWritePointer++ = aByte, mRemainingLength--, OT_ERROR_NONE)
: OT_ERROR_NO_BUFS;
}
void UndoLastWrites(uint16_t aUndoLength)
{
mWritePointer -= aUndoLength;
mRemainingLength += aUndoLength;
}
protected:
FrameWritePointer(void)
: mWritePointer(NULL)
, mRemainingLength(0)
{
}
uint8_t *mWritePointer; uint16_t mRemainingLength; };
template <uint16_t kSize> class FrameBuffer : public FrameWritePointer
{
public:
FrameBuffer(void)
: FrameWritePointer()
{
Clear();
}
void Clear(void)
{
mWritePointer = mBuffer;
mRemainingLength = sizeof(mBuffer);
}
bool IsEmpty(void) const { return (mWritePointer == mBuffer); }
uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - mBuffer); }
uint8_t *GetFrame(void) { return mBuffer; }
private:
uint8_t mBuffer[kSize];
};
template <uint16_t kSize> class MultiFrameBuffer : public FrameWritePointer
{
public:
MultiFrameBuffer(void)
: FrameWritePointer()
{
Clear();
}
void Clear(void)
{
mWriteFrameStart = mBuffer;
mWritePointer = mBuffer + kHeaderSize;
mRemainingLength = kSize - kHeaderSize;
IgnoreError(SetSkipLength(0));
}
bool HasFrame(void) const { return (mWritePointer != GetFrame()); }
otError SetLength(uint16_t aLength)
{
otError error = OT_ERROR_NO_BUFS;
if (GetFrame() + aLength <= OT_ARRAY_END(mBuffer))
{
mWritePointer = GetFrame() + aLength;
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
error = OT_ERROR_NONE;
}
return error;
}
uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - GetFrame()); }
otError SetSkipLength(uint16_t aSkipLength)
{
otError error = OT_ERROR_NO_BUFS;
if (mWriteFrameStart + kHeaderSize + aSkipLength <= OT_ARRAY_END(mBuffer))
{
Encoding::LittleEndian::WriteUint16(aSkipLength, mWriteFrameStart + kHeaderSkipLengthOffset);
mWritePointer = GetFrame();
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
error = OT_ERROR_NONE;
}
return error;
}
uint16_t GetSkipLength(void) const
{
return Encoding::LittleEndian::ReadUint16(mWriteFrameStart + kHeaderSkipLengthOffset);
}
uint8_t *GetFrame(void) const { return mWriteFrameStart + kHeaderSize + GetSkipLength(); }
uint16_t GetFrameMaxLength(void) const { return static_cast<uint16_t>(mBuffer + kSize - GetFrame()); }
void SaveFrame(void)
{
Encoding::LittleEndian::WriteUint16(GetSkipLength() + GetLength(), mWriteFrameStart + kHeaderTotalLengthOffset);
mWriteFrameStart = mWritePointer;
IgnoreError(SetSkipLength(0));
mWritePointer = GetFrame();
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
}
void DiscardFrame(void)
{
IgnoreError(SetSkipLength(0));
mWritePointer = GetFrame();
mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer);
}
bool HasSavedFrame(void) const { return (mWriteFrameStart != mBuffer); }
otError GetNextSavedFrame(uint8_t *&aFrame, uint16_t &aLength)
{
otError error = OT_ERROR_NONE;
OT_ASSERT(aFrame == NULL || (mBuffer <= aFrame && aFrame < OT_ARRAY_END(mBuffer)));
aFrame = (aFrame == NULL) ? mBuffer : aFrame + aLength;
if (aFrame != mWriteFrameStart)
{
uint16_t totalLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderTotalLengthOffset);
uint16_t skipLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderSkipLengthOffset);
aLength = totalLength - skipLength;
aFrame += kHeaderSize + skipLength;
}
else
{
aLength = 0;
aFrame = NULL;
error = OT_ERROR_NOT_FOUND;
}
return error;
}
void ClearSavedFrames(void)
{
uint16_t len = static_cast<uint16_t>(mWriteFrameStart - mBuffer);
if (len > 0)
{
memmove(mBuffer, mWriteFrameStart, static_cast<uint16_t>(mWritePointer - mWriteFrameStart));
mWritePointer -= len;
mWriteFrameStart -= len;
mRemainingLength += len;
}
}
private:
enum
{
kHeaderTotalLengthOffset = 0,
kHeaderSkipLengthOffset = sizeof(uint16_t),
kHeaderSize = sizeof(uint16_t) + sizeof(uint16_t),
};
uint8_t mBuffer[kSize];
uint8_t *mWriteFrameStart; };
class Encoder
{
public:
explicit Encoder(FrameWritePointer &aWritePointer);
otError BeginFrame(void);
otError Encode(uint8_t aByte);
otError Encode(const uint8_t *aData, uint16_t aLength);
otError EndFrame(void);
private:
FrameWritePointer &mWritePointer;
uint16_t mFcs;
};
class Decoder
{
public:
typedef void (*FrameHandler)(void *aContext, otError aError);
Decoder(FrameWritePointer &aFrameWritePointer, FrameHandler aFrameHandler, void *aContext);
void Decode(const uint8_t *aData, uint16_t aLength);
private:
enum State
{
kStateNoSync,
kStateSync,
kStateEscaped,
};
State mState;
FrameWritePointer &mWritePointer;
FrameHandler mFrameHandler;
void * mContext;
uint16_t mFcs;
uint16_t mDecodedLength;
};
} }
#endif