ModbusAdapter.h 4.61 KB
/*****************************************************************************
 * Copyright (c) 2022 Priva b.v.
 *****************************************************************************/

#pragma once

#include "ConnectionConfig.h"
#include "IModbusAdapter.h"
#include "modbus.h"

// std
#include <memory>
#include <variant>
#include <vector>

/// @brief The ModbusAdapter class represents a single modbus context. Each context will
///       result in an instance of this class. It is not intended to be
///       created directly but through a factory. The factory will create
///       the object and return the pointer to its interface.
class ModbusAdapter : public IModbusAdapter
{
public:
    /*!
     * \brief Default constructor
     */
    explicit ModbusAdapter();

    /*!
     * \brief Default destructor
     */
    virtual ~ModbusAdapter();

    /*!
     * \brief /// Create a modbus connection, accepting a configuration object.
     */
    bool ModbusConnect( const ConnectionConfig &conncfg ) override;

    /*!
     * \brief   ModbusDisconnect
     *          Disconnect from the serial bus or the TCP connection, freeing its resources
     */
    bool ModbusDisconnect() override;

    /*!
     * \brief Read data from a modbus device given by its parameters.
     * \param   slaveId         - The Id of the ModbusDevice.
     * \param   functionCode    - The code describing the action we want to perform on the device.
     *                            Given by an enum, provided by the modbus-stack.
     * \param   startAddress    - Startaddres of the register we want to read.
     * \param   noOfItems       - The number of items we expect back.
     * \returns modbusData      - A vector holding each register in an entry in the same order as they are received.
     *                            Empty if no data was received.
     */
    modbusData ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems ) override;

    /*!
     * \brief Read data from the holdregisters ( or keep-registers ) of a modbus device.
     * \param   slaveId         - The Id of the ModbusDevice.
     * \param   startAddress    - Startaddres of the register we want to read.
     * \param   noOfItems       - The number of items we expect back.
     * \returns modbusData      - A vector holding each register in an entry in the same order as they are received.
     *                            Empty if no data was received.
     */
    modbusData ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems ) override;

    /*!
     * \brief Write data to the device.
     * \param slaveId           - The Id of the Modbus device
     * \param funtionCode       - The code describing the action we want to perform on the device
     *                            given by an enum, provided by the modbus-stack.
     * \param startAddress      - Startaddres of the register we want to read.
     * \param noOfItems         - The number of items we expect to be written
     * \param values            - The values we want to write to the given device. Each vector-entry represents a single byte
     *                            and they will be sent in sequence.
     */
    void ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values ) override;

    /*!
     * \brief   Indicates if this connection is alive.
     * \return  True if alive, false if not.
     */
    bool isConnected() const override;

    /*!
     * \brief   returns the translated error code coming from the modbus stack.
     * \param   errnum          - error Number coming from the stack.
     * \return  The translated error as a string. Empty if not resolvable.
     */
    std::string ErrorString( int errnum ) const override;

private:    // Methods
    bool    ModbusConnectRTU( const std::string &serialport, int baud, char parity, int dataBits, int stopBits, int RTS, int timeOut );
    bool    ModbusConnectTCP( const std::string &ip, int port, int timeOut = -1 );

    void    InitBuffers();
    void    ClearBuffers();

private:    // Members
    ConnectionType              m_connType  { ConnectionType::CT_UNKNOWN };  ///> The type of connection this instance provides. Needed for administration
    bool                        m_connected { false };                      ///> Shows if the connection is still active.
    modbus_t                   *m_modbus;                                   ///> The actual low-level modbus instance as a raw-pointer. ( unique_pointer gives an error on this struct )

    // Return value Buffers ( Room for improvement )
    uint8_t                     *m_dest;
    uint16_t                    *m_dest16;
};