C ++ Разработка архитектуры программного обеспечения для многослойной коммуникации - PullRequest
0 голосов
/ 27 февраля 2019

Как вы все знаете, каждый канал связи имеет различные возможности максимальной длины данных.Например макс.Длина данных в USB HID составляет 64 байта или 256 байтов для канала UART Modbus.Однако, как пользователь, я не хочу заботиться об этих ограничениях.Мое общение должно быть в состоянии разделить большие пакеты на несколько более мелких (в зависимости от максимальной длины данных канала).Фактическая процедура разделения одинакова, меняется только длина данных на один пакет.

Это моя мотивация для написания обобщенного коммуникационного 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 разные задачи: задача высокого уровня запускается по запросу пользователя, фактическая аппаратная связь выполняется в отдельной отдельной задаче, чтобы гарантировать, что данные отправляются только тогда, когда оборудование фактически готово к отправке данных.

A образец класса 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.Однако эта база защищена.Очевидно, я мог бы сделать базу среднего уровня общедоступной, но это означало бы, что пользователь может (случайно) получить доступ к уровню среднего уровня.Я не хочу этого.

У вас есть рекомендации, как решить мою проблему?

спасибо за вашу помощь:)

1 Ответ

0 голосов
/ 27 февраля 2019

Обновление: извините, я скучаю, вас поняли, вот решение, я думаю, вы просили:

#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};
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...