Commit 467852705fb7f1e99346076fa7820b0a990a6385

Authored by Peter M. Groen
1 parent cadcf24a

Setting up working version

3rdparty/libmodbus/modbus-tcp.c
1   -/*
2   - * Copyright © 2001-2013 Stéphane Raimbault <stephane.raimbault@gmail.com>
3   - *
4   - * SPDX-License-Identifier: LGPL-2.1+
5   - */
6   -
7 1 #include <stdio.h>
8 2 #include <stdlib.h>
9 3 #include <string.h>
10 4 #include <errno.h>
11   -#ifndef _MSC_VER
12 5 #include <unistd.h>
13   -#endif
14 6 #include <signal.h>
15 7 #include <sys/types.h>
16 8  
17   -#if defined(_WIN32)
18   -# define OS_WIN32
19   -/* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later.
20   - * minwg32 headers check WINVER before allowing the use of these */
21   -# ifndef WINVER
22   -# define WINVER 0x0501
23   -# endif
24   -/* Already set in modbus-tcp.h but it seems order matters in VS2005 */
25   -# include <winsock2.h>
26   -# include <ws2tcpip.h>
27   -# define SHUT_RDWR 2
28   -# define close closesocket
29   -#else
30 9 # include <sys/socket.h>
31 10 # include <sys/ioctl.h>
32 11  
... ... @@ -40,7 +19,7 @@
40 19 # include <netinet/tcp.h>
41 20 # include <arpa/inet.h>
42 21 # include <netdb.h>
43   -#endif
  22 +
44 23  
45 24 #if !defined(MSG_NOSIGNAL)
46 25 #define MSG_NOSIGNAL 0
... ...
3rdparty/libmodbus/modbus.c
... ... @@ -1129,19 +1129,19 @@ int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
1129 1129 }
1130 1130  
1131 1131 /* Reads the data from a remove device and put that data into an array */
1132   -static int read_registers(modbus_t *ctx, int function, int addr, int nb,
1133   - uint16_t *dest)
  1132 +static int read_registers(modbus_t *ctx, int function, int addr, int nb, uint16_t *dest)
1134 1133 {
1135 1134 int rc;
1136 1135 int req_length;
1137 1136 uint8_t req[_MIN_REQ_LENGTH];
1138 1137 uint8_t rsp[MAX_MESSAGE_LENGTH];
1139 1138  
1140   - if (nb > MODBUS_MAX_READ_REGISTERS) {
1141   - if (ctx->debug) {
  1139 + if (nb > MODBUS_MAX_READ_REGISTERS)
  1140 + {
  1141 + if (ctx->debug)
  1142 + {
1142 1143 fprintf(stderr,
1143   - "ERROR Too many registers requested (%d > %d)\n",
1144   - nb, MODBUS_MAX_READ_REGISTERS);
  1144 + "ERROR Too many registers requested (%d > %d)\n", nb, MODBUS_MAX_READ_REGISTERS);
1145 1145 }
1146 1146 errno = EMBMDATA;
1147 1147 return -1;
... ... @@ -1150,7 +1150,8 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb,
1150 1150 req_length = ctx->backend->build_request_basis(ctx, function, addr, nb, req);
1151 1151  
1152 1152 rc = send_msg(ctx, req, req_length);
1153   - if (rc > 0) {
  1153 + if (rc > 0)
  1154 + {
1154 1155 int offset;
1155 1156 int i;
1156 1157  
... ... @@ -1164,10 +1165,10 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb,
1164 1165  
1165 1166 offset = ctx->backend->header_length;
1166 1167  
1167   - for (i = 0; i < rc; i++) {
  1168 + for (i = 0; i < rc; i++)
  1169 + {
1168 1170 /* shift reg hi_byte to temp OR with lo_byte */
1169   - dest[i] = (rsp[offset + 2 + (i << 1)] << 8) |
1170   - rsp[offset + 3 + (i << 1)];
  1171 + dest[i] = (rsp[offset + 2 + (i << 1)] << 8) | rsp[offset + 3 + (i << 1)];
1171 1172 }
1172 1173 }
1173 1174  
... ...
CMakeLists.txt
... ... @@ -12,6 +12,8 @@ set(SOURCE_FILES
12 12 src/IModbusAdapter.h
13 13 src/ModbusAdapter.h
14 14 src/ModbusAdapter.cpp
  15 + src/ModbusConnections.h
  16 + src/ModbusConnections.cpp
15 17 )
16 18  
17 19 add_executable(main
... ...
src/ConnectionConfig.h
... ... @@ -3,6 +3,9 @@
3 3 #include <string>
4 4 #include <unordered_map>
5 5  
  6 +/*!
  7 + * \brief The ConnectionPort enum
  8 + */
6 9 enum class ConnectionPort : unsigned int
7 10 {
8 11 CP_EXTERNAL = 0,
... ... @@ -10,6 +13,9 @@ enum class ConnectionPort : unsigned int
10 13 CP_TCP
11 14 };
12 15  
  16 +/*!
  17 + * \brief The Parity enum
  18 + */
13 19 enum class Parity : unsigned int
14 20 {
15 21 PAR_ODD,
... ... @@ -17,6 +23,9 @@ enum class Parity : unsigned int
17 23 PAR_NONE
18 24 };
19 25  
  26 +/*!
  27 + * \brief The ConnectionType enum
  28 + */
20 29 enum class ConnectionType : unsigned int
21 30 {
22 31 CT_SERIAL,
... ... @@ -27,6 +36,15 @@ enum class ConnectionType : unsigned int
27 36 class ConnectionConfig
28 37 {
29 38 public:
  39 + /*!
  40 + * \brief ConnectionConfig
  41 + * \param port
  42 + * \param baud
  43 + * \param parity
  44 + * \param dataBits
  45 + * \param stopBits
  46 + * \param timeOut
  47 + */
30 48 ConnectionConfig( ConnectionPort port, int baud = 115200, Parity parity = Parity::PAR_NONE, int dataBits = 8, int stopBits = 1, int timeOut = -1 )
31 49 : m_port( port )
32 50 , m_baudRate( baud )
... ... @@ -36,8 +54,16 @@ public:
36 54 , m_ipaddress()
37 55 , m_portnumber( -1 )
38 56 , m_timeOut( timeOut )
  57 + , m_conType( ConnectionType::CT_SERIAL )
39 58 {}
40 59  
  60 + /*!
  61 + * \brief ConnectionConfig
  62 + * \param port
  63 + * \param ip
  64 + * \param portnum
  65 + * \param timeOut
  66 + */
41 67 ConnectionConfig( ConnectionPort port, const std::string &ip, int portnum, int timeOut = -1 )
42 68 : m_port( port )
43 69 , m_baudRate( -1 )
... ... @@ -47,23 +73,24 @@ public:
47 73 , m_ipaddress( ip )
48 74 , m_portnumber( portnum )
49 75 , m_timeOut( timeOut )
  76 + , m_conType( ConnectionType::CT_TCP )
50 77 {}
51 78  
52 79 // Getters and Setters. Implemented to avoid outside meddling on the member variables.
53   - ConnectionType getType() const { return m_conType; }
54   - std::string getPort() const { return m_portMap.at(m_port); }
55   - int getBaudRate() const { return m_baudRate; }
56   - char getParity() const { return m_parityMap.at(m_parity); }
57   - int getDataBits() const { return m_dataBits; }
58   - int getStopBits() const { return m_stopBits; }
  80 + std::string getPort() const { return m_portMap.at(m_port); } ///<
  81 + ConnectionPort getPortEnum() const { return m_port; } ///<
  82 + int getBaudRate() const { return m_baudRate; } ///<
  83 + char getParity() const { return m_parityMap.at(m_parity); } ///<
  84 + int getDataBits() const { return m_dataBits; } ///<
  85 + int getStopBits() const { return m_stopBits; } ///<
59 86  
60   - std::string getIpAddress() const { return m_ipaddress; }
61   - int getTcpPort() const { return m_portnumber; }
62   - int getTimeOut() const { return m_timeOut; }
  87 + std::string getIpAddress() const { return m_ipaddress; } ///<
  88 + int getTcpPort() const { return m_portnumber; } ///<
63 89  
64   -private:
  90 + int getTimeOut() const { return m_timeOut; } ///<
  91 + ConnectionType getType() const { return m_conType; } ///<
65 92  
66   - ConnectionType m_conType;
  93 +private:
67 94  
68 95 /// Serial connections
69 96 ConnectionPort m_port;
... ... @@ -78,6 +105,9 @@ private:
78 105  
79 106 /// Generic
80 107 int m_timeOut;
  108 + ConnectionType m_conType;
  109 +
  110 + // Change accordingly to the devicenames on your platform.
81 111 std::unordered_map<ConnectionPort, std::string> m_portMap =
82 112 {
83 113 { ConnectionPort::CP_EXTERNAL, "/dev/ttyUSB0" },
... ...
src/IModbusAdapter.h
... ... @@ -36,7 +36,7 @@ public:
36 36 * \param startAddress
37 37 * \param noOfItems
38 38 */
39   - virtual modbusData ModbusReadData( int slaveId, int startAddress, int noOfItems ) = 0;
  39 + virtual modbusData ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems ) = 0;
40 40  
41 41 /*!
42 42 * \brief ModbusReadHoldReg
... ... @@ -55,7 +55,7 @@ public:
55 55 * \param noOfItems
56 56 * \param values
57 57 */
58   - virtual void ModBusWriteData( int slaveId, int funtionCode, int startAddress, int noOfItems, std::vector<int>values ) = 0;
  58 + virtual void ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values ) = 0;
59 59  
60 60 /*!
61 61 * \brief isConnected
... ...
src/ModbusAdapter.cpp
... ... @@ -205,7 +205,7 @@ bool ModbusAdapter::isConnected() const
205 205 return m_connected;
206 206 }
207 207  
208   -std::string ModbusAdapter::ErrorString( int errnum )
  208 +std::string ModbusAdapter::ErrorString( int errnum ) const
209 209 {
210 210 switch(errnum)
211 211 {
... ...
src/ModbusAdapter.h
... ... @@ -23,7 +23,7 @@ public:
23 23 /*!
24 24 * \brief ModbusAdapter
25 25 */
26   - ModbusAdapter();
  26 + explicit ModbusAdapter();
27 27  
28 28 /*!
29 29 * \brief ~ModbusAdapter
... ... @@ -34,12 +34,12 @@ public:
34 34 * \brief ModbusConnect
35 35 * \param conncfg
36 36 */
37   - void ModbusConnect( const ConnectionConfig &conncfg );
  37 + void ModbusConnect( const ConnectionConfig &conncfg ) override;
38 38  
39 39 /*!
40 40 * \brief ModbusDisconnect
41 41 */
42   - void ModbusDisconnect();
  42 + void ModbusDisconnect() override;
43 43  
44 44 /*!
45 45 * \brief ModbusReadData
... ... @@ -47,7 +47,7 @@ public:
47 47 * \param startAddress
48 48 * \param noOfItems
49 49 */
50   - modbusData ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems );
  50 + modbusData ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems ) override;
51 51  
52 52 /*!
53 53 * \brief ModbusReadHoldReg
... ... @@ -56,7 +56,7 @@ public:
56 56 * \param noOfItems
57 57 * \return
58 58 */
59   - modbusData ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems );
  59 + modbusData ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems ) override;
60 60  
61 61 /*!
62 62 * \brief ModBusWriteData
... ... @@ -66,20 +66,20 @@ public:
66 66 * \param noOfItems
67 67 * \param values
68 68 */
69   - void ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values );
  69 + void ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values ) override;
70 70  
71 71 /*!
72 72 * \brief isConnected
73 73 * \return
74 74 */
75   - bool isConnected() const;
  75 + bool isConnected() const override;
76 76  
77 77 /*!
78 78 * \brief ErrorString
79 79 * \param errnum
80 80 * \return
81 81 */
82   - std::string ErrorString( int errnum );
  82 + std::string ErrorString( int errnum ) const override;
83 83  
84 84 private: // Methods
85 85 void ModbusConnectRTU( const std::string &serialport, int baud, char parity, int dataBits, int stopBits, int RTS, int timeOut );
... ...
src/ModbusConnections.cpp 0 → 100644
  1 +#include "ModbusConnections.h"
  2 +
  3 +ModbusConnections::ModbusConnections()
  4 +{
  5 +
  6 +}
  7 +
  8 +ModbusConnections::~ModbusConnections()
  9 +{
  10 + if( m_mapSerial.size() > 0 )
  11 + {
  12 + // Iterate, remove and destroy ( Searching, Seek & Destroy )
  13 + }
  14 +
  15 + if( m_mapTcp.size() > 0 )
  16 + {
  17 + // Iterate, remove and destroy ( Searching, Seek & Destroy )
  18 + }
  19 +}
  20 +
  21 +bool ModbusConnections::CreateConnection( const ConnectionConfig &config )
  22 +{
  23 + std::shared_ptr<IModbusAdapter> ptrNewAdapter = std::make_shared<ModbusAdapter>();
  24 + if( ptrNewAdapter == nullptr )
  25 + {
  26 + // Log a message and bail out
  27 + return false;
  28 + }
  29 +
  30 + // It looks like the pointer is valid. Time to connect.
  31 + ptrNewAdapter->ModbusConnect( config );
  32 + if( !ptrNewAdapter->isConnected() )
  33 + {
  34 + // Unsuccessful. Delete the object and return false
  35 + ptrNewAdapter.reset();
  36 + return false;
  37 + }
  38 +
  39 + std::shared_ptr<IModbusAdapter> ptr = connectionExist( config.getPortEnum(), createEndPoint( config ) );
  40 + if( ptr != nullptr )
  41 + {
  42 + if( !DeleteConnection( config.getPortEnum(), createEndPoint( config ) ) )
  43 + {
  44 + // Something went wrong here.. Our administration is "wonky" so report false and bail.
  45 + // New connection is not created.
  46 + ptrNewAdapter.reset();
  47 + return false;
  48 + }
  49 + }
  50 +
  51 + if( config.getType() == ConnectionType::CT_TCP )
  52 + {
  53 + m_mapTcp.insert( { createEndPoint( config ), ptrNewAdapter } );
  54 + }
  55 + else if( config.getType() == ConnectionType::CT_SERIAL )
  56 + {
  57 + m_mapSerial.insert( { config.getPortEnum(), ptrNewAdapter } );
  58 + }
  59 + else
  60 + {
  61 + // No idea what the type is but not something we recognize.
  62 + ptrNewAdapter.reset();
  63 + return false;
  64 + }
  65 + return true;
  66 +}
  67 +
  68 +bool ModbusConnections::DeleteConnection( const ConnectionPort portName, const std::string &endpoint )
  69 +{
  70 +
  71 +}
  72 +
  73 +int ModbusConnections::ConnectionCount()
  74 +{
  75 + return ( m_mapSerial.size() + m_mapTcp.size() );
  76 +}
  77 +
  78 +std::shared_ptr<IModbusAdapter> ModbusConnections::getConnection( const ConnectionPort portName, const std::string &endpoint )
  79 +{
  80 + return this->connectionExist( portName, endpoint );
  81 +}
  82 +
  83 +std::shared_ptr<IModbusAdapter> ModbusConnections::connectionExist( const ConnectionPort portName, const std::string &endpoint )
  84 +{
  85 + if( portName == ConnectionPort::CP_TCP )
  86 + {
  87 + auto search = m_mapTcp.find( endpoint );
  88 + if( search != m_mapTcp.end() )
  89 + {
  90 + return search->second;
  91 + }
  92 + else
  93 + {
  94 + return nullptr;
  95 + }
  96 + }
  97 + else
  98 + {
  99 + auto search = m_mapSerial.find( portName );
  100 + if( search != m_mapSerial.end() )
  101 + {
  102 + return search->second;
  103 + }
  104 + else
  105 + {
  106 + return nullptr;
  107 + }
  108 + }
  109 +}
  110 +
  111 +std::string ModbusConnections::createEndPoint( const std::string &ipAddress, int portNumber )
  112 +{
  113 + if( portNumber > 0 && !ipAddress.empty() )
  114 + {
  115 + return std::string( "tcp://" + ipAddress + ":" + std::to_string( portNumber ) );
  116 + }
  117 +
  118 + return std::string();
  119 +}
  120 +
  121 +std::string ModbusConnections::createEndPoint( const ConnectionConfig &config )
  122 +{
  123 + if( config.getType() != ConnectionType::CT_TCP )
  124 + {
  125 + // Early opt-out
  126 + return std::string();
  127 + }
  128 +
  129 + return createEndPoint( config.getIpAddress(), config.getTcpPort() );
  130 +}
... ...
src/ModbusConnections.h 0 → 100644
  1 +/****************************************************************************
  2 + * Copyright (c) 2022 Priva B.V.
  3 + ****************************************************************************/
  4 +#pragma once
  5 +
  6 +// Flexblox
  7 +#include "IModbusAdapter.h"
  8 +#include "ModbusAdapter.h"
  9 +
  10 +// std
  11 +#include <memory>
  12 +#include <string>
  13 +#include <unordered_map>
  14 +
  15 +class ModbusConnections
  16 +{
  17 +public:
  18 + /*!
  19 + * \brief ModbusConnections
  20 + */
  21 + explicit ModbusConnections();
  22 +
  23 + /*!
  24 + * \brief ~ModbusConnections
  25 + */
  26 + virtual ~ModbusConnections();
  27 +
  28 + /*!
  29 + * \brief CreateConnection
  30 + * \param config
  31 + * \return
  32 + */
  33 + bool CreateConnection( const ConnectionConfig &config );
  34 +
  35 + /*!
  36 + * \brief DeleteConnection
  37 + * \param portName
  38 + * \param endpoint
  39 + * \return
  40 + */
  41 + bool DeleteConnection( const ConnectionPort portName, const std::string &endpoint = std::string() );
  42 +
  43 + /*!
  44 + * \brief ConnectionCount
  45 + * \return
  46 + */
  47 + int ConnectionCount();
  48 +
  49 + /*!
  50 + * \brief getConnection
  51 + * \param portName
  52 + * \param endpoint
  53 + * \return
  54 + */
  55 + std::shared_ptr<IModbusAdapter> getConnection( const ConnectionPort portName, const std::string &endpoint = std::string() );
  56 +
  57 + // Convenient functions
  58 + /*!
  59 + * \brief getConnection
  60 + * \param portName
  61 + * \param ipAddress
  62 + * \param tcpPortNumber
  63 + * \return
  64 + */
  65 + std::shared_ptr<IModbusAdapter> getConnection( const ConnectionPort portName, const std::string &ipAddress, int tcpPortNumber );
  66 +
  67 +private:
  68 + /*!
  69 + * \brief connectionExist
  70 + * \param portName
  71 + * \param endpoint
  72 + * \return
  73 + */
  74 + std::shared_ptr<IModbusAdapter> connectionExist( const ConnectionPort portName, const std::string &endpoint = std::string() );
  75 +
  76 + /*!
  77 + * \brief createEndPoint
  78 + * \param ipAddress
  79 + * \param portNumber
  80 + * \return
  81 + */
  82 + std::string createEndPoint( const std::string &ipAddress, int portNumber );
  83 +
  84 + /*!
  85 + * \brief createEndPoint
  86 + * \param config
  87 + * \return
  88 + */
  89 + std::string createEndPoint( const ConnectionConfig &config );
  90 +
  91 +private:
  92 + std::unordered_map<ConnectionPort, std::shared_ptr<IModbusAdapter>> m_mapSerial; ///< Unordered map holding the Modbus connections By PortName
  93 + std::unordered_map<std::string, std::shared_ptr<IModbusAdapter>> m_mapTcp; ///< Unordered map holding the Modbus connections By tcp://endpoint:port
  94 +};
... ...
src/main.cpp
1 1 #include <iostream>
2 2  
  3 +#include "ModbusAdapter.h"
  4 +
3 5 int main( int argc, char* argv[] )
4 6 {
  7 + ModbusAdapter oModbus;
  8 + ConnectionConfig oConfig( ConnectionPort::CP_EXTERNAL, 9600, Parity::PAR_NONE, 8, 1, 1 );
  9 +
  10 + std::cout << "========================= [START] Connection test ================================" << std::endl;
  11 + oModbus.ModbusConnect( oConfig );
  12 + if( oModbus.isConnected() )
  13 + {
  14 + std::cout << "Successful connected to : " << oConfig.getPort() << std::endl;
  15 + }
  16 + else
  17 + {
  18 + std::cout << "There was a problem connecting to : " << oConfig.getPort() << std::endl;
  19 + }
  20 +
  21 + oModbus.ModbusDisconnect();
  22 + if( !oModbus.isConnected() )
  23 + {
  24 + std::cout << "Successful disconnected from : " << oConfig.getPort() << std::endl;
  25 + }
  26 + else
  27 + {
  28 + std::cout << "There was a problem disconnecting from : " << oConfig.getPort() << std::endl;
  29 + }
  30 + std::cout << "========================= [END] Connection test ===============================" << std::endl;
  31 +
  32 + std::cout << "========================= [START] Reading test ================================" << std::endl;
  33 + std::cout << "== Reading the Hold Registers ==" << std::endl;
  34 + oModbus.ModbusConnect( oConfig );
  35 + if( oModbus.isConnected() )
  36 + {
  37 + std::cout << "Successful connected to : " << oConfig.getPort() << std::endl;
  38 + modbusData returnValues = oModbus.ModbusReadHoldReg( 1, MODBUS_FC_READ_HOLDING_REGISTERS, 2 );
  39 + if( returnValues.size() == 2 )
  40 + {
  41 + std::cout << "2 items returned from MODBUS_FC_READ_HOLDING_REGISTERS " << std::endl;
  42 + }
  43 + else
  44 + {
  45 + std::cout << "There was an error reading the Hold Registers " << std::endl;
  46 + std::cout << "Number of items returned : " << returnValues.size() << std::endl;
  47 + }
5 48  
  49 + std::cout << "== Reading the Temperature ==" << std::endl;
  50 + returnValues = oModbus.ModbusReadData( 0x01, MODBUS_FC_READ_INPUT_REGISTERS, 0x00, 0x02 );
  51 + if( returnValues.size() == 0 )
  52 + {
  53 + std::cout << "No values returned " << std::endl;
  54 + }
  55 + else
  56 + {
  57 + std::cout << "Number of items returned : " << returnValues.size() << std::endl;
  58 + }
  59 + }
  60 + else
  61 + {
  62 + std::cout << "There was a problem connecting to : " << oConfig.getPort() << std::endl;
  63 + return -1;
  64 + }
  65 + oModbus.ModbusDisconnect();
  66 + std::cout << "=========================== [END] Reading test ================================" << std::endl;
6 67 }
... ...