peary/interfaces/Endpoint.hpp

Peary Interface Endpoint. More…

Namespaces

Name
peary
peary::interface

Classes

Name
class peary::interface::InterfaceLock Helper class to hold the interface type-tagged lock.
class peary::interface::Endpoint Communication interface endpoint.

Detailed Description

Peary Interface Endpoint.

Copyright: Copyright (c) 2026 CERN and the Peary Caribou authors. This software is distributed under the terms of the LGPL-3.0-only License, copied verbatim in the file “LICENSE.md”. SPDX-License-Identifier: LGPL-3.0-only

Source code

  
#pragma once

#include <concepts>
#include <mutex>
#include <utility>
#include <vector>

#include "peary/interfaces/exceptions.hpp"
#include "peary/log/log.hpp"
#include "peary/utils/type.hpp"

namespace peary::interface {

    /* Concept for the interface tag to be an empty struct */
    template <typename T>
    concept InterfaceTag = std::is_class_v<T> && std::is_empty_v<T>;

    template <typename InterfaceTag> class InterfaceLock {
    public:
        InterfaceLock() : lock_(mutex()) {
            LOG(TRACE) << "Lock acquired for interface " << utils::demangle(typeid(InterfaceTag));
        }

        ~InterfaceLock() { LOG(TRACE) << "Lock released for interface " << utils::demangle(typeid(InterfaceTag)); }

        InterfaceLock(const InterfaceLock&) = delete;
        InterfaceLock& operator=(const InterfaceLock&) = delete;

    private:
        static std::mutex& mutex() {
            static std::mutex m;
            return m;
        }

        std::scoped_lock<std::mutex> lock_;
    };

    template <typename InterfaceTag, typename RegisterType, typename DataType> class Endpoint {
    public:
        /* Defining shorthand notations for data types */
        using reg_t = RegisterType;
        using data_t = DataType;
        using pair_t = std::pair<RegisterType, DataType>;
        using vector_t = std::vector<DataType>;

        /* Delete copy constructors, since these endpoints communicate with hardware, they cannot be copied */
        Endpoint(const Endpoint&) = delete;
        Endpoint& operator=(const Endpoint&) = delete;

        /* Disallow move semantics */
        Endpoint(Endpoint&&) noexcept = delete;
        Endpoint& operator=(Endpoint&&) noexcept = delete;

        std::string info() const { return endpoint_info_; }

        data_t write(const data_t& value) {
            InterfaceLock<InterfaceTag> lock;
            return write_impl(value);
        }

        vector_t write(const vector_t& values) {
            InterfaceLock<InterfaceTag> lock;
            return write_impl(values);
        }

        pair_t write(const pair_t& regData) {
            InterfaceLock<InterfaceTag> lock;
            return write_impl(regData);
        }

        vector_t write(const reg_t& reg, const vector_t& values) {
            InterfaceLock<InterfaceTag> lock;
            return write_impl(reg, values);
        }

        std::vector<pair_t> write(const std::vector<pair_t>& regDataVec) {
            InterfaceLock<InterfaceTag> lock;
            return write_impl(regDataVec);
        }

        data_t read() {
            InterfaceLock<InterfaceTag> lock;
            return read_impl();
        }

        vector_t read(unsigned int count) {
            InterfaceLock<InterfaceTag> lock;
            return read_impl(count);
        }

        vector_t read(const reg_t& reg, unsigned int count) {
            InterfaceLock<InterfaceTag> lock;
            return read_impl(reg, count);
        }

    protected:
        /* Protected constructor and destructor */
        Endpoint(const std::string& info) : endpoint_info_(info) {};
        virtual ~Endpoint() = default;

        /* write function interface with default implementations which throw */
        virtual data_t write_impl(const data_t& /* data */) { throw CommunicationError("write(data) not supported"); }
        virtual vector_t write_impl(const vector_t& /* data */) { throw CommunicationError("write(vector) not supported"); }
        virtual pair_t write_impl(const pair_t& /* data */) {
            throw CommunicationError("write(pair<reg,data>) not supported");
        }
        virtual vector_t write_impl(const reg_t& /* reg */, const vector_t& /* data */) {
            throw CommunicationError("write(reg,vector) not supported");
        }
        virtual std::vector<pair_t> write_impl(const std::vector<pair_t>& /* data */) {
            throw CommunicationError("write(vector<pair<reg,data>>) not supported");
        }

        /* read function interface with default implementations which throw */
        virtual data_t read_impl() { throw CommunicationError("read() not supported"); }
        virtual vector_t read_impl(const unsigned int /* length */) {
            throw CommunicationError("read(count) not supported");
        }
        virtual vector_t read_impl(const reg_t& /* reg */, const unsigned int /* length */) {
            throw CommunicationError("read(reg,count) not supported");
        }

    private:
        /* Endpoint info, provided by implementations */
        std::string endpoint_info_;
    };

} // namespace peary::interface
  

Updated on 2026-01-30 at 22:01:05 +0100