Guide to Implementing Communication Protocols in C
  • Introduction
  • Code Generation vs C++ Library
  • Main Challenges
  • Goal
  • Audience
  • Code Examples
  • Final Outcome
  • Contribution
  • Message
    • Reading and Writing
    • Dispatching and Handling
    • Extending Interface
  • Fields
    • Automating Basic Operations
    • Working With Fields
    • Common Field Types
  • Generic Library
    • Generalising Message Interface
    • Generalising Message Implementation
    • Generalising Fields Implementation
  • Transport
    • PAYLOAD Layer
    • ID Layer
    • SIZE Layer
    • SYNC Layer
    • CHECKSUM Layer
    • Defining Protocol Stack
  • Achievements
  • Appendices
    • Appendix A - tupleForEach
    • Appendix B - tupleAccumulate
    • Appendix C - tupleForEachFromUntil
    • Appendix D - tupleForEachType
    • Appendix E - AlignedUnion
Powered by GitBook
On this page

Was this helpful?

  1. Transport

SYNC Layer

This layer is responsible to find and validate the synchronisation prefix.

namespace comms
{
// TField is type of the field used to read/write SYNC prefix
// TNext is the next layer this one wraps
template <typename TField, typename TNext>
class SyncPrefixLayer
{
public:
    // Type of the field object used to read/write SYNC prefix.
    using Field = TField;

    // Take type of the ReadIterator from the next layer
    using ReadIterator = typename TNext::ReadIterator;

    // Take type of the WriteIterator from the next layer
    using WriteIterator = typename TNext::WriteIterator;

    // Take type of the message interface from the next layer
    using Message = typename TNext::Message;

    // Take type of the message interface pointer from the next layer
    using MsgPtr = typename TNext::MsgPtr; 

    template <typename TMsgPtr>
    ErrorStatus read(TMsgPtr& msgPtr, ReadIterator& iter, std::size_t len)
    {
        Field field;
        auto es = field.read(iter, len);
        if (es != ErrorStatus::Success) {
            return es;
        }
        if (field.value() != Field().value()) {
            // doesn't match expected
            return ErrorStatus::ProtocolError;
        }
        return m_next.read(msgPtr, iter, len - field.length());
    } 

    ErrorStatus write(const Message& msg, WriteIterator& iter, std::size_t len) const
    {
        Field field;
        auto es = field.write(iter, len);
        if (es != ErrorStatus::Success) {
            return es;
        }
        return m_next.write(msg, iter, len - field.length());
    }

    std::size_t length(const TMessage& msg) const
    {
        return Field().length() + m_next.length(msg);
    }

private:
    TNext m_next;
};
} // namespace comms

For example, 2 bytes synchronisation prefix 0xab 0xcd with big endian serialisation may be defined as:

using CommonFieldBase = comms::Field<false>; // big endian serialisation base
using SyncPrefixField = 
    comms::IntValueField<
        CommonFieldBase,
        std::uint16_t,
        comms::option::DefaultNumValue<0xabcd>
    >;
PreviousSIZE LayerNextCHECKSUM Layer

Last updated 5 years ago

Was this helpful?

Note, that the value of the SYNC prefix is expected to be equal to the value of the default constructed TField field type. The default construction value may be set using comms::option::DefaultNumValue option described in chapter.

Generalising Fields Implementation