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. Fields

Working With Fields

PreviousAutomating Basic OperationsNextCommon Field Types

Last updated 5 years ago

Was this helpful?

In order to some basic operations, all the fields had to provide the same basic interface. As the result the actual field values had to be wrapped in a class that defines the required public interface. Such class must also provide means to access/update the wrapped value. For example:

class SomeField
{
public:
    // Value storage type definition
    using ValueType = ...;

    // Provide an access to the stored value
    ValueType& value() { return m_value; }
    const ValueType& value() const { return m_value; }
    ...
private:
    ValueType m_value;
}

Let's assume the ActualMessage1 defines 3 integer value fields with serialisation lengths of 1, 2, and 4 bytes respectively.

using ActualMessage1Fields = std::tuple<
    IntValueField<std::int8_t>,
    IntValueField<std::int16_t>
    IntValueField<std::int32_t>
>;
class ActualMessage1 : public MessageBase<ActualMessage1Fields> {...};
class Handler
{
public:
    void handle(ActualMessage1& msg)
    {
        // Get access to the field's bundle of type std::tuple
        auto& allFields = msg.fields();

        // Get access to the field abstractions.
        auto& field1 = std::get<0>(allFields);
        auto& field2 = std::get<1>(allFields);
        auto& field3 = std::get<2>(allFields);

        // Get access to the values themselves:
        std::int8_t val1 = field1.value();
        std::int16_t val2 = field2.value();
        std::int32_t val3 = field3.value();

        ... Do something with retrieved values
    }
};

When preparing message to send, the similar code sequence may be applied to update the values:

ActualMessage1 msg;

// Get access to the field's bundle of type std::tuple
auto& allFields = msg.fields();

// Get access to the field abstractions.
auto& field1 = std::get<0>(allFields);
auto& field2 = std::get<1>(allFields);
auto& field3 = std::get<2>(allFields);

// Update the values themselves:
field1.value() = ...;
field2.value() = ...;
field3.value() = ...;

// Serialise and send the message:
sendMessage(msg);

The chapter described the efficient way to dispatch message object to its handler. The appropriate handling function may access its field's value using the following code flow:

automate
Dispatching and Handling