C ++设计用于多层通信的软件体系结构

时间:2019-02-27 12:03:15

标签: c++ inheritance

众所周知,每个通信通道都有不同的最大数据长度功能。 例如最大USB HID中的数据长度为64字节,对于UART modbus通道为256字节。 但是,作为用户,我不想关心这些限制。我的通信应该能够将较大的数据包拆分为多个较小的数据包(取决于通道的最大数据长度)。实际的分割例程是相同的,只是每个单个数据包的数据长度有所不同。

那是我编写通用通信API的动机。

所以让我们从更高的级别开始:

template<size_t user_data_length>
class CSlave_Com_API: protected CSlave_Com_Mid_level<user_data_length>
{
    /*
     * all of these Functions need elements from CSlave_Com_Mid_level to
     * work correctly
     */
public:

    /**
     * This Function is called by the user thread. It need access to some elements from CSlave_Com_Mid_level.
     * These elements are not shown here to make this problem better understandable
     * 
     * Processes a Received Request and generates the answer. The answer is copied to pRequest as well
     * @param pRequest Pointer to the Request
     * @return true wenn an answer was generated
     */
    bool Process_Request(CRequest* const pRequest);

private:

    /**
     * This Function is called within Process_Request (by the user thread). 
     * It need access to some elements from CSlave_Com_Mid_level.
     * These elements are not shown here to make this problem better understandable
     * 
     * Tells the LL Driver that the answer has been prepared (and stored to pRequest).
     * The answer is no ready to be sent
     * @param pRequest Pointer to the request
     * @return true if the LL Driver has been notified correctly
     */
    bool Send_Answer(CRequest* const pRequest);

    /**
     * This Function is called within Process_Request (by the user thread). 
     * It need access to some elements from CSlave_Com_Mid_level.
     * These elements are not shown here to make this problem better understandable
     * 
     * Tells the LL driver to abort the request because something went wrong
     * @param pRequest Pointer to the Request
     * @return true if the LL driver has been notified correctly
     */
    bool Abort_Request(CRequest* const pRequest);
};

template<size_t user_data_length>
class CSlave_Com_Mid_level
{

public:
    ///This is the structure of a single packet with is sent or received
    struct Single_Packet_T
    {
        //some header Info...
        uint8_t data[user_data_length]; ///< the actual user data
    };

    /**
     * This Function is called by the driver thread. It need access to some elements from CSlave_Com_Mid_level.
     * These elements are not shown here to make this problem better understandable
     * 
     * Called be the LL Driver when new data was received
     * @param rx_packet Received data
     * @return true when the received data could be processed
     */
    bool Process_received_Packet(const Single_Packet_T& rx_packet);

    /**
     * This Function is called by the driver thread. It need access to some elements from CSlave_Com_Mid_level.
     * These elements are not shown here to make this problem better understandable
     * 
     * Called by the LL driver. Stores new data to sent in tx_packet
     * @param tx_packet Storage buffer for the new TX Data
     * @return true when the buffer was filled correctly
     */
    bool Get_Next_Packet_To_Send(Single_Packet_T& tx_packet);

private:
    /// This queue contains all currently processed requests
    QueueHandle_t requests;
};

这个想法是您可以为每个通道初始化API的实例。即

CSlave_Com_API<64> usb_slave_com;
CSlave_Com_API<256> modbus_slave_com;

现在,每个频道的 LL 显然都非常不同。 问题是,我有2个不同的任务: 高层任务是由用户请求触发的,实际的硬件通信在单独的任务中运行,以确保仅在硬件准备好发送数据时才发送数据。

样本LL类可能如下所示:

class CSlave_Com_LL_Slave_Com
{
public:
    /**
     *Constructor
     * @param mid_level_reference reference to the used midlevel class instance. This instance is needed to correctly
     *  pass the received data to the higher levels and to get the next data to be send
     */
    CSlave_Com_LL_Slave_Com(const CSlave_Com_Mid_level<message_length>& mid_level_reference);

    ///Destruktor
    ~CSlave_Com_LL_Slave_Com();

private:
    ///Midlevel Reference
    const CSlave_Com_Mid_level<message_length>& mid_level_instance;
};

问题是:我的LL类需要访问某些API实例的中级基础。但是,此基础受到保护。 显然,我可以公开中层基础,但这意味着用户可以(偶然)访问中层。我不要那个。

您对如何解决我的问题有任何建议吗?

thx为您提供帮助:)

1 个答案:

答案 0 :(得分:1)

更新:对不起,我想念您,这是解决方案,我想您要求提供:

#include <string>
#include <iostream>


template<size_t user_data_length>
class CSlave_Com_Mid_level
{

public:
    ///This is the structure of a single packet with is sent or received
    struct Single_Packet_T
    {
        //some header Info...
        uint8_t data[user_data_length]; ///< the actual user data
    };

    /**
     * Called be the LL Driver when new data was received
     * @param rx_packet Received data
     * @return true when the received data could be processed
     */
    bool Process_received_Packet(const Single_Packet_T& rx_packet) const {
        std::cout << "Test\n";
        return false;
    }

    /**
     * Called by the LL driver. Stores new data to sent in tx_packet
     * @param tx_packet Storage buffer for the new TX Data
     * @return true when the buffer was filled correctly
     */
    bool Get_Next_Packet_To_Send(Single_Packet_T& tx_packet);


};

template<size_t user_data_length>
class CSlave_Com_API;

template <size_t message_length>
class CSlave_Com_LL_Slave_Com
{
public:
    /**
     *Constructor
     * @param mid_level_reference reference to the used midlevel class instance. This instance is needed to correctly
     *  pass the received data to the higher levels and to get the next data to be send
     */
    CSlave_Com_LL_Slave_Com(const CSlave_Com_API<message_length>& mid_level_reference)
    : mid_level_instance(mid_level_reference) {
        typename CSlave_Com_Mid_level<message_length>::Single_Packet_T packet{};
        this->mid_level_instance.Process_received_Packet(packet);
    }

    ///Destruktor
    ~CSlave_Com_LL_Slave_Com() = default;

private:
    ///Midlevel Reference
    const CSlave_Com_Mid_level<message_length>& mid_level_instance;
};

template<size_t user_data_length>
class CSlave_Com_API: protected CSlave_Com_Mid_level<user_data_length> {
    friend class CSlave_Com_LL_Slave_Com<user_data_length>;
};

int main()
{
    CSlave_Com_API<42UL> foo{};
    CSlave_Com_LL_Slave_Com<42UL> bar{foo};
}