├── .gitignore ├── .gitmodules ├── .vscode └── settings.json ├── 3rdparty └── popl │ ├── LICENSE │ └── README.md ├── AUTHORS ├── CMakeLists.txt ├── COPYING.LESSER ├── README.md ├── cmake_uninstall.cmake.in ├── config.h.in ├── dev ├── CMakeLists.txt ├── bin │ └── git-version ├── cmake │ ├── FindGzip.cmake │ ├── GetDate.cmake │ ├── GitVersion.cmake │ └── SubDirList.cmake └── codelite │ ├── executable-modbuspp │ ├── executable-modbuspp.project │ ├── icon.png │ └── main.cpp │ └── unit-test-modbuspp │ ├── icon.png │ ├── main.cpp │ └── unit-test-modbuspp.project ├── doc ├── CMakeLists.txt ├── Doxyfile.in ├── DoxygenLayout.xml ├── build_main_page.sh.in ├── images │ ├── lgplv3.png │ ├── modbus.png │ ├── osi.png │ └── router.png ├── libmodbuspp-doc.project ├── main_page_footer.dox ├── main_page_header.dox ├── modbuspp_json.md └── modbuspp_json_fr.md ├── examples ├── .vscode │ └── settings.json ├── CMakeLists.txt ├── master │ ├── CMakeLists.txt │ ├── read-coils │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── main.cpp │ │ ├── read-coils.mk │ │ ├── read-coils.project │ │ └── read-coils.txt │ ├── read-holding-data │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── main.cpp │ │ ├── read-holding-data.mk │ │ ├── read-holding-data.project │ │ └── read-holding-data.txt │ ├── read-input-registers │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── main.cpp │ │ ├── read-input-registers.mk │ │ ├── read-input-registers.project │ │ └── read-input-registers.txt │ ├── report-slave-id │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── main.cpp │ │ ├── report-slave-id.mk │ │ ├── report-slave-id.project │ │ └── report-slave-id.txt │ ├── rw-holding-json │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── main.cpp │ │ ├── master.json │ │ ├── rw-holding-json.mk │ │ ├── rw-holding-json.project │ │ └── rw-holding-json.txt │ └── write-holding-data │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── main.cpp │ │ ├── write-holding-data.mk │ │ ├── write-holding-data.project │ │ └── write-holding-data.txt ├── router │ ├── CMakeLists.txt │ ├── router-json │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── main.cpp │ │ ├── router-json.mk │ │ ├── router-json.project │ │ ├── router-json.txt │ │ ├── router-rf95-rs485.json │ │ ├── router-tcp-rs232-rf95-2slaves.json │ │ ├── router-tcp-rs232-rf95.json │ │ ├── router-tcp-rs232-rf95.png │ │ ├── router-tcp-rs232-virtual.json │ │ ├── router-tcp-rs232.json │ │ ├── router-tcp-rs485-virtual.json │ │ ├── router-virtual-rs232.json │ │ └── router-virtual-rs485.json │ └── router-simple │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── main.cpp │ │ ├── router-simple.mk │ │ ├── router-simple.project │ │ └── router-simple.txt └── server │ ├── CMakeLists.txt │ ├── callback-server-json │ ├── CMakeLists.txt │ ├── README.md │ ├── callback-server-json.mk │ ├── callback-server-json.project │ ├── callback-server-json.txt │ ├── main.cpp │ ├── rtu-server.json │ └── tcp-server.json │ ├── clock-server-json │ ├── CMakeLists.txt │ ├── README.md │ ├── clock-server-json.mk │ ├── clock-server-json.project │ ├── clock-server-json.txt │ ├── clock-server-tcp.json │ ├── clock-server-virtual.json │ └── main.cpp │ ├── clock-server │ ├── CMakeLists.txt │ ├── README.md │ ├── clock-server.mk │ ├── clock-server.project │ ├── clock-server.txt │ └── main.cpp │ └── simple-server-json │ ├── CMakeLists.txt │ ├── README.md │ ├── main.cpp │ ├── simple-server-json.mk │ ├── simple-server-json.project │ ├── simple-server-json.txt │ └── tcp-server.json ├── include ├── modbuspp.h └── modbuspp │ ├── bufferedslave.h │ ├── data.h │ ├── device.h │ ├── global.h │ ├── master.h │ ├── message.h │ ├── netlayer.h │ ├── pimp.h │ ├── popl.h │ ├── request.h │ ├── response.h │ ├── router.h │ ├── rtulayer.h │ ├── server.h │ ├── slave.h │ ├── slavereport.h │ ├── swap.h │ ├── tcplayer.h │ └── timeout.h ├── lib └── CMakeLists.txt ├── libmodbuspp.project ├── modbuspp-config-version.cmake.in ├── modbuspp-config.cmake.in ├── modbuspp.pc.in ├── modbuspp.workspace ├── src ├── bufferedslave.cpp ├── bufferedslave_p.h ├── device.cpp ├── device_p.h ├── json_p.h ├── master.cpp ├── master_p.h ├── message.cpp ├── message_p.h ├── netlayer.cpp ├── netlayer_p.h ├── request.cpp ├── request_p.h ├── response.cpp ├── response_p.h ├── router.cpp ├── router_p.h ├── rtulayer.cpp ├── rtulayer_p.h ├── server.cpp ├── server_p.h ├── slave.cpp ├── slave_p.h ├── tcplayer.cpp ├── tcplayer_p.h └── timeout.cpp ├── tests ├── CMakeLists.txt ├── unit-test-device │ ├── main.cpp │ └── unit-test-device.project └── unit-test-server │ ├── main.cpp │ └── unit-test-server.project └── version.h.in /.gitignore: -------------------------------------------------------------------------------- 1 | *.map 2 | *.lss 3 | *.sym 4 | *.bak 5 | .codelite 6 | .clang 7 | compile_commands.json 8 | *.a 9 | *.so 10 | obj/ 11 | version.h 12 | config.h 13 | *build*/ 14 | work/ 15 | lib/libmodbus -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "3rdparty/variant"] 2 | path = 3rdparty/variant 3 | url = https://github.com/mpark/variant.git 4 | [submodule "3rdparty/json"] 5 | path = 3rdparty/json 6 | url = https://github.com/nlohmann/json.git 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.debugConfig": { 3 | "args": [ 4 | "${workspaceFolder}/examples/router/router-json/router-tcp-rs232-virtual.json" 5 | ] 6 | }, 7 | "cmake.buildDirectory": "${workspaceFolder}/cmake-build-${buildType}" 8 | } -------------------------------------------------------------------------------- /3rdparty/popl/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015-2016 Johannes Pohl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | * Pascal JEAN piduino.org> 2 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include "version.h" 20 | #cmakedefine01 MODBUSPP_HAVE_TIOCRS485 21 | #cmakedefine01 MODBUSPP_HAVE_TIOCM_RTS 22 | #cmakedefine01 MODBUSPP_HAVE_RTU_MULTI_SLAVES 23 | 24 | /* ========================================================================== */ 25 | -------------------------------------------------------------------------------- /dev/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | # This file is part of the libmodbuspp Project. 3 | # 4 | # The libmodbuspp Project is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # The libmodbuspp Project is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with the libmodbuspp Project. If not, see . 16 | # modbuspp/dev CMakeLists.txt 17 | 18 | cmake_minimum_required(VERSION 3.0) 19 | 20 | # set packaging dir 21 | if(NOT CPACK_PACKAGE_DIRECTORY) 22 | set(CPACK_PACKAGE_DIRECTORY ${CMAKE_BINARY_DIR}/packages) 23 | endif() 24 | 25 | if("${CMAKE_PROJECT_NAME}" STREQUAL "Project") 26 | set(PROJECT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..) 27 | endif() 28 | 29 | install (DIRECTORY codelite/executable-modbuspp 30 | DESTINATION "${INSTALL_CODELITE_DIR}/templates/projects" 31 | DIRECTORY_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ 32 | COMPONENT dev 33 | ) 34 | 35 | install (DIRECTORY codelite/unit-test-modbuspp 36 | DESTINATION "${INSTALL_CODELITE_DIR}/templates/projects" 37 | DIRECTORY_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ 38 | COMPONENT dev 39 | ) 40 | -------------------------------------------------------------------------------- /dev/cmake/FindGzip.cmake: -------------------------------------------------------------------------------- 1 | # Find gzip 2 | # Export variables: 3 | # GZIP_FOUND 4 | # GZIP_EXE 5 | 6 | find_program(GZIP_EXE gzip) 7 | 8 | include(FindPackageHandleStandardArgs) 9 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( Gzip DEFAULT_MSG GZIP_EXE ) 10 | mark_as_advanced(GZIP_EXE) 11 | 12 | macro(gzip_compress target_name input_files result_archive) 13 | add_custom_command( 14 | OUTPUT ${result_archive} 15 | COMMAND ${GZIP_EXE} --best --to-stdout ${input_files} > ${result_archive} 16 | COMMENT "Compressing ${input_files}" 17 | DEPENDS ${input_files} ${ARGN} 18 | ) 19 | add_custom_target(${target_name} ALL DEPENDS ${result_archive}) 20 | endmacro() 21 | -------------------------------------------------------------------------------- /dev/cmake/SubDirList.cmake: -------------------------------------------------------------------------------- 1 | # Finds the list of subdirectories in the curdir directory and returns it to result 2 | 3 | macro(SUBDIRLIST result curdir) 4 | file(GLOB children RELATIVE ${curdir} ${curdir}/*) 5 | set(dirlist "") 6 | foreach(child ${children}) 7 | if(IS_DIRECTORY ${curdir}/${child}) 8 | list(APPEND dirlist ${child}) 9 | endif() 10 | endforeach() 11 | set(${result} ${dirlist}) 12 | endmacro() 13 | -------------------------------------------------------------------------------- /dev/codelite/executable-modbuspp/executable-modbuspp.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A project that produces an executable. 5 | Note that this project is set to work with the GNU toolchain (gdb, g++) and libmodbuspp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | None 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | /usr/include/modbuspp 43 | /usr/local/include/modbuspp 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | None 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | /usr/include/modbuspp 73 | /usr/local/include/modbuspp 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /dev/codelite/executable-modbuspp/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epsilonrt/libmodbuspp/0851f3114b90f8e10f565afaec9331f49bc72da1/dev/codelite/executable-modbuspp/icon.png -------------------------------------------------------------------------------- /dev/codelite/executable-modbuspp/main.cpp: -------------------------------------------------------------------------------- 1 | // libmodbuspp template 2 | // This example code is in the public domain. 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace Modbus; 9 | 10 | Master mb; // instantiate new MODBUS Master 11 | 12 | // ----------------------------------------------------------------------------- 13 | int main (int argc, char **argv) { 14 | string port ("/dev/ttyUSB0"); 15 | 16 | if (argc > 1) { 17 | 18 | port = argv[1]; // the serial port can be provided as a parameter on the command line. 19 | } 20 | 21 | mb.setBackend (Rtu, port, "38400E1"); // set master on RTU 22 | // if you have to handle the DE signal of the line driver with RTS, 23 | // you should uncomment the lines below... 24 | // mb.rtu().setRts(RtsDown); 25 | // mb.rtu().setSerialMode(Rs485); 26 | Slave & slv = mb.addSlave (33); // to the slave at address 33 27 | 28 | if (mb.open ()) { // open a connection 29 | // success, do what you want here 30 | uint16_t value; 31 | 32 | slv.readInputRegisters (1, &value); 33 | // .... 34 | cout << "R0=" << value << endl; 35 | mb.close(); 36 | } 37 | 38 | return 0; 39 | } 40 | /* ========================================================================== */ 41 | -------------------------------------------------------------------------------- /dev/codelite/unit-test-modbuspp/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epsilonrt/libmodbuspp/0851f3114b90f8e10f565afaec9331f49bc72da1/dev/codelite/unit-test-modbuspp/icon.png -------------------------------------------------------------------------------- /dev/codelite/unit-test-modbuspp/main.cpp: -------------------------------------------------------------------------------- 1 | // libmodbuspp Unit Test template 2 | // Use UnitTest++ framework -> https://github.com/unittest-cpp/unittest-cpp/wiki 3 | // This test code is in the public domain. 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | using namespace Modbus; 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | // 13 | // To add a test, simply put the following code in the a .cpp file of your choice: 14 | // 15 | // ================================= 16 | // Simple Test 17 | // ================================= 18 | // 19 | // TEST(YourTestName) 20 | // { 21 | // } 22 | // 23 | // The TEST macro contains enough machinery to turn this slightly odd-looking 24 | // syntax into legal C++, and automatically register the test in a global list. 25 | // This test list forms the basis of what is executed by RunAllTests(). 26 | // e.g. 27 | TEST (RtuMasterTest) { 28 | string connection ("/dev/ttyUSB0"); 29 | string settings ("38400E1"); 30 | Net net = Rtu; 31 | int slvAddr = 33; 32 | 33 | Master mb; // instantiate new MODBUS Master 34 | CHECK (!mb.isValid()); 35 | 36 | // set master on RTU 37 | CHECK (mb.setBackend (net, connection, settings)); 38 | CHECK (mb.isValid()); 39 | CHECK (mb.net() == net); 40 | CHECK (mb.connection() == connection); 41 | CHECK (mb.settings() == settings) ; 42 | 43 | Slave & slv = mb.addSlave (slvAddr); 44 | CHECK (mb.hasSlave (slvAddr)); 45 | 46 | REQUIRE CHECK (mb.open ()); 47 | uint16_t value; 48 | CHECK (slv.readInputRegisters (1, &value) == 1); 49 | 50 | cout << "R0=" << value << endl; 51 | mb.close(); 52 | CHECK (!mb.isOpen()); 53 | } 54 | 55 | // 56 | // If you want to re-use a set of test data for more than one test, or provide 57 | // setup/teardown for tests, you can use the TEST_FIXTURE macro instead. 58 | // The macro requires that you pass it a class name that it will instantiate, 59 | // so any setup and teardown code should be in its constructor and destructor. 60 | // 61 | // struct SomeFixture 62 | // { 63 | // SomeFixture() { /* some setup */ } 64 | // ~SomeFixture() { /* some teardown */ } 65 | // 66 | // int testData; 67 | // }; 68 | // 69 | // TEST_FIXTURE(SomeFixture, YourTestName) 70 | // { 71 | // int temp = testData; 72 | // } 73 | // 74 | // ================================= 75 | // Test Suites 76 | // ================================= 77 | // 78 | // Tests can be grouped into suites, using the SUITE macro. A suite serves as a 79 | // namespace for test names, so that the same test name can be used in two 80 | // difference contexts. 81 | // 82 | // SUITE(YourSuiteName) 83 | // { 84 | // TEST(YourTestName) 85 | // { 86 | // } 87 | // 88 | // TEST(YourOtherTestName) 89 | // { 90 | // } 91 | // } 92 | // 93 | // This will place the tests into a C++ namespace called YourSuiteName, and make 94 | // the suite name available to UnitTest++. 95 | // RunAllTests() can be called for a specific suite name, so you can use this to 96 | // build named groups of tests to be run together. 97 | // Note how members of the fixture are used as if they are a part of the test, 98 | // since the macro-generated test class derives from the provided fixture class. 99 | // 100 | // 101 | //////////////////////////////////////////////////////////////////////////////// 102 | 103 | // run all tests 104 | int main (int argc, char **argv) { 105 | return UnitTest::RunAllTests(); 106 | } 107 | 108 | /* ========================================================================== */ 109 | -------------------------------------------------------------------------------- /dev/codelite/unit-test-modbuspp/unit-test-modbuspp.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Unit test for libmodbuspp. 5 | Note that this project is set to work with the GNU toolchain (gdb, g++) and libmodbuspp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | None 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | /usr/include/modbuspp 43 | /usr/local/include/modbuspp 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | None 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | /usr/include/modbuspp 73 | /usr/local/include/modbuspp 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | # This file is part of the libmodbuspp Project. 3 | # 4 | # The libmodbuspp Project is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # The libmodbuspp Project is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with the libmodbuspp Project. If not, see . 16 | 17 | # doc CMakeLists.txt 18 | 19 | cmake_minimum_required(VERSION 3.0) 20 | 21 | set (MODBUSPP_WITH_DOXYGEN_DOC 0 CACHE BOOL "Enable build of the documentation") 22 | 23 | # set packaging dir 24 | if(NOT CPACK_PACKAGE_DIRECTORY) 25 | set(CPACK_PACKAGE_DIRECTORY ${CMAKE_BINARY_DIR}/packages) 26 | endif() 27 | 28 | if("${CMAKE_PROJECT_NAME}" STREQUAL "Project") 29 | set(PROJECT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..) 30 | endif() 31 | 32 | if (MODBUSPP_WITH_DOXYGEN_DOC) 33 | 34 | find_package(Doxygen REQUIRED) 35 | set(DOXYGEN_README ${PROJECT_SOURCE_DIR}/README.md) 36 | set(DOXYGEN_FILE ${CMAKE_BINARY_DIR}/Doxyfile) 37 | set(DOXYGEN_MAINPAGE ${CMAKE_BINARY_DIR}/main_page.dox) 38 | 39 | set(DOXYGEN_INPUT_LIST 40 | ${PROJECT_SOURCE_DIR}/include/modbuspp/bufferedslave.h 41 | ${PROJECT_SOURCE_DIR}/include/modbuspp/data.h 42 | ${PROJECT_SOURCE_DIR}/include/modbuspp/device.h 43 | ${PROJECT_SOURCE_DIR}/include/modbuspp/global.h 44 | ${PROJECT_SOURCE_DIR}/include/modbuspp/master.h 45 | ${PROJECT_SOURCE_DIR}/include/modbuspp/message.h 46 | ${PROJECT_SOURCE_DIR}/include/modbuspp/netlayer.h 47 | ${PROJECT_SOURCE_DIR}/include/modbuspp/request.h 48 | ${PROJECT_SOURCE_DIR}/include/modbuspp/response.h 49 | ${PROJECT_SOURCE_DIR}/include/modbuspp/router.h 50 | ${PROJECT_SOURCE_DIR}/include/modbuspp/rtulayer.h 51 | ${PROJECT_SOURCE_DIR}/include/modbuspp/server.h 52 | ${PROJECT_SOURCE_DIR}/include/modbuspp/slave.h 53 | ${PROJECT_SOURCE_DIR}/include/modbuspp/slavereport.h 54 | ${PROJECT_SOURCE_DIR}/include/modbuspp/swap.h 55 | ${PROJECT_SOURCE_DIR}/include/modbuspp/tcplayer.h 56 | ${PROJECT_SOURCE_DIR}/include/modbuspp/timeout.h 57 | ) 58 | 59 | set(DOXYGEN_INPUT "${CMAKE_BINARY_DIR}/main_page.dox") 60 | foreach(item ${DOXYGEN_INPUT_LIST}) 61 | # get_filename_component(item_dir ${item} DIRECTORY) 62 | string(APPEND DOXYGEN_INPUT " ${item} ") 63 | endforeach(item ${DOXYGEN_INPUT_LIST}) 64 | 65 | #message("DOXYGEN_INPUT=${DOXYGEN_INPUT}") 66 | 67 | configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile @ONLY) 68 | configure_file(build_main_page.sh.in ${CMAKE_BINARY_DIR}/build_main_page.sh @ONLY) 69 | 70 | add_custom_target(main_page.dox 71 | COMMAND ${CMAKE_COMMAND} -E echo_append "Building API Documentation Main Page..." 72 | COMMAND sh ${CMAKE_BINARY_DIR}/build_main_page.sh > /dev/null 73 | COMMAND ${CMAKE_COMMAND} -E echo "Done." 74 | DEPENDS main_page_header.dox main_page_footer.dox ${PROJECT_SOURCE_DIR}/README.md 75 | ) 76 | 77 | add_custom_target(html 78 | COMMAND ${CMAKE_COMMAND} -E echo_append "Building API Documentation..." 79 | COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_FILE} > /dev/null 80 | COMMAND ${CMAKE_COMMAND} -E echo "Done." 81 | DEPENDS main_page.dox DoxygenLayout.xml Doxyfile.in ${DOXYGEN_INPUT_LIST} 82 | ) 83 | 84 | add_custom_target(doc) 85 | add_dependencies(doc main_page.dox html) 86 | 87 | #message("MODBUSPP_INSTALL_DOC_DIR=${MODBUSPP_INSTALL_DOC_DIR}") 88 | #message("INSTALL_DATA_DIR=${INSTALL_DATA_DIR}") 89 | 90 | # API documentation 91 | install(DIRECTORY ${CMAKE_BINARY_DIR}/html/ 92 | DESTINATION ${MODBUSPP_INSTALL_DOC_DIR}/api-manual COMPONENT doc) 93 | 94 | # manpages 95 | install(DIRECTORY ${CMAKE_BINARY_DIR}/man/ 96 | DESTINATION ${INSTALL_DATA_DIR}/man 97 | COMPONENT doc 98 | FILES_MATCHING PATTERN "Modbus_*.3") 99 | 100 | # Examples 101 | install(DIRECTORY ${PROJECT_SOURCE_DIR}/examples/ 102 | DESTINATION ${MODBUSPP_INSTALL_EXAMPLES_DIR} 103 | COMPONENT doc 104 | FILES_MATCHING PATTERN "*.c" PATTERN "*.h" PATTERN "*.cpp" PATTERN "*.mk" PATTERN "*.txt" PATTERN "*.project" PATTERN "*.workspace" PATTERN "CMakeLists.txt" PATTERN "README*" 105 | PATTERN ".clang/" EXCLUDE 106 | PATTERN "Debug/" EXCLUDE 107 | PATTERN "Release/" EXCLUDE 108 | PATTERN ".codelite/" EXCLUDE 109 | PATTERN "cmake-build*/" EXCLUDE) 110 | 111 | endif(MODBUSPP_WITH_DOXYGEN_DOC) 112 | -------------------------------------------------------------------------------- /doc/build_main_page.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # (c) Copyright 2011-2019 Pascal JEAN, All rights reserved. 3 | 4 | TARGET=@DOXYGEN_MAINPAGE@ 5 | README=@DOXYGEN_README@ 6 | 7 | PARSER=cat 8 | command -v markdown >/dev/null 2>&1 && PARSER=markdown 9 | # https://linuxhint.com/install_npm_debian 10 | # marked is needed to correctly display C ++ code in markdown : 11 | # sudo npm install -g marked 12 | command -v marked >/dev/null 2>&1 && PARSER=marked 13 | echo "PARSER=$PARSER" 14 | if [ "$PARSER" = "markdown" ]; then 15 | HEAD_TAG="@htmlonly" 16 | FOOT_TAG="@endhtmlonly" 17 | fi 18 | 19 | cat @PROJECT_SOURCE_DIR@/doc/main_page_header.dox > $TARGET 20 | 21 | # README 22 | echo "$HEAD_TAG" >> $TARGET 23 | tail -n +4 $README | ${PARSER} >> $TARGET 24 | echo "$FOOT_TAG" >> $TARGET 25 | 26 | cat @PROJECT_SOURCE_DIR@/doc/main_page_footer.dox >> $TARGET 27 | -------------------------------------------------------------------------------- /doc/images/lgplv3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epsilonrt/libmodbuspp/0851f3114b90f8e10f565afaec9331f49bc72da1/doc/images/lgplv3.png -------------------------------------------------------------------------------- /doc/images/modbus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epsilonrt/libmodbuspp/0851f3114b90f8e10f565afaec9331f49bc72da1/doc/images/modbus.png -------------------------------------------------------------------------------- /doc/images/osi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epsilonrt/libmodbuspp/0851f3114b90f8e10f565afaec9331f49bc72da1/doc/images/osi.png -------------------------------------------------------------------------------- /doc/images/router.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epsilonrt/libmodbuspp/0851f3114b90f8e10f565afaec9331f49bc72da1/doc/images/router.png -------------------------------------------------------------------------------- /doc/main_page_footer.dox: -------------------------------------------------------------------------------- 1 | 2 | */ 3 | -------------------------------------------------------------------------------- /doc/main_page_header.dox: -------------------------------------------------------------------------------- 1 | /** 2 | * @file main_page.dox 3 | * @mainpage Main page 4 | -------------------------------------------------------------------------------- /examples/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.debugConfig": { 3 | "args": [ 4 | "-m", 5 | "rtu", 6 | "-c", 7 | "/dev/tnt0", 8 | "-s", 9 | "38400E1" 10 | ] 11 | } 12 | } -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | add_subdirectory(master) 4 | add_subdirectory(router) 5 | add_subdirectory(server) -------------------------------------------------------------------------------- /examples/master/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | add_subdirectory(read-coils) 4 | add_subdirectory(read-holding-data) 5 | add_subdirectory(read-input-registers) 6 | add_subdirectory(report-slave-id) 7 | add_subdirectory(rw-holding-json) 8 | add_subdirectory(write-holding-data) 9 | -------------------------------------------------------------------------------- /examples/master/read-coils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(read-coils) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/master/read-coils/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f read-coils.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o read-coils $(pkg-config --cflags --libs modbuspp) main.cpp 20 | -------------------------------------------------------------------------------- /examples/master/read-coils/main.cpp: -------------------------------------------------------------------------------- 1 | // libmodbuspp master read-coils example 2 | 3 | // reads 5 coils on RTU slave at address 8 4 | 5 | // This example code is in the public domain. 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | using namespace Modbus; 11 | 12 | int main (int argc, char **argv) { 13 | string port = string ("/dev/ttyUSB0"); 14 | 15 | if (argc > 1) { 16 | 17 | port = argv[1]; // the serial port can be provided as a parameter on the command line. 18 | } 19 | 20 | Master mb (Rtu, port, "19200E1"); // new master on RTU 21 | // if you have to handle the DE signal of the line driver with RTS, 22 | // you should uncomment the lines below... 23 | // mb.rtu().setRts(RtsDown); 24 | // mb.rtu().setSerialMode(Rs485); 25 | 26 | Slave & slv = mb.addSlave (8); 27 | 28 | cout << "Reads coils of slave[" << slv.number() << "] on " << 29 | mb.connection() << " (" << mb.settings() << ")" << endl; 30 | 31 | if (mb.open ()) { // open a connection 32 | bool coil[5]; 33 | 34 | int ncoils = slv.readCoils (1, coil, 5); // reads coils 1 to 5 35 | if (ncoils > 0) { 36 | 37 | // if success, print the binary values 38 | cout << "coils: "; 39 | for (int i = 0; i < ncoils; i++) { 40 | 41 | cout << coil[i]; 42 | } 43 | cout << endl; 44 | } 45 | else { 46 | cerr << "Unable to read coils ! " << mb.lastError() << endl; 47 | exit (EXIT_FAILURE); 48 | } 49 | mb.close(); 50 | } 51 | else { 52 | cerr << "Unable to open MODBUS connection to " << port << " : " << mb.lastError() << endl; 53 | exit (EXIT_FAILURE); 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /examples/master/read-coils/read-coils.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=read-coils 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/master/read-coils 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="read-coils.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/master/read-coils/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/master/read-coils/read-coils.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/master/read-holding-data/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(read-holding-data) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/master/read-holding-data/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f read-holding-data.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o read-holding-data $(pkg-config --cflags --libs modbuspp) main.cpp 20 | -------------------------------------------------------------------------------- /examples/master/read-holding-data/main.cpp: -------------------------------------------------------------------------------- 1 | // Reads floating point holding registers from SolarPi pressure meter 2 | 3 | // The pressure sensor calibration is composed of 4 decimal values. 4 | // The first 2 are the minimum and maximum pressure calibration values in %RH. 5 | // The following 2 are the output values of the analog-to-digital converter 6 | // (in LSB) corresponding to the calibration values. 7 | 8 | // This example code is in the public domain. 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | using namespace Modbus; 15 | 16 | int main (int argc, char **argv) { 17 | string port ("/dev/ttyUSB0"); 18 | 19 | if (argc > 1) { 20 | 21 | port = argv[1]; // the serial port can be provided as a parameter on the command line. 22 | } 23 | 24 | Master mb (Rtu, port , "38400E1"); // new master on RTU 25 | // if you have to handle the DE signal of the line driver with RTS, 26 | // you should uncomment the lines below... 27 | // mb.rtu().setRts(RtsDown); 28 | // mb.rtu().setSerialMode(Rs485); 29 | 30 | Slave & slv = mb.addSlave (33); // SolarPi Pressure meter 31 | 32 | cout << "Reads holding registers of slave[" << slv.number() << "] on " << 33 | mb.connection() << " (" << mb.settings() << ")" << endl; 34 | 35 | if (mb.open ()) { // open a connection 36 | // success, do what you want here 37 | 38 | // the bytes in the registers are arranged in big endian. 39 | // the solarpi calibration registers are arranged in little endian. 40 | Data registers[4]; 41 | 42 | // reads values .... 43 | if (slv.readRegisters (1, registers, 4) > 0) { 44 | 45 | // then print them ! 46 | cout << "R0=" << registers[0].value() << endl; 47 | cout << "R1=" << registers[1].value() << endl; 48 | cout << "R2=" << registers[2].value() << endl; 49 | cout << "R3=" << registers[3].value() << endl; 50 | } 51 | else { 52 | cerr << "Unable to read input registers ! " << mb.lastError() << endl; 53 | exit (EXIT_FAILURE); 54 | } 55 | mb.close(); 56 | } 57 | else { 58 | cerr << "Unable to open MODBUS connection to " << port << " : " << mb.lastError() << endl; 59 | exit (EXIT_FAILURE); 60 | } 61 | 62 | return 0; 63 | } 64 | /* ========================================================================== */ 65 | -------------------------------------------------------------------------------- /examples/master/read-holding-data/read-holding-data.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=read-holding-data 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/master/read-holding-data 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="read-holding-data.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/master/read-holding-data/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/master/read-holding-data/read-holding-data.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/master/read-input-registers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(read-input-registers) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/master/read-input-registers/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f read-input-registers.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o read-input-registers $(pkg-config --cflags --libs modbuspp) main.cpp 20 | -------------------------------------------------------------------------------- /examples/master/read-input-registers/main.cpp: -------------------------------------------------------------------------------- 1 | // Reads input registers of SolarPi pressure meter 2 | 3 | // This example code is in the public domain. 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | using namespace Modbus; 10 | 11 | 12 | // ----------------------------------------------------------------------------- 13 | int main (int argc, char **argv) { 14 | string port ("/dev/ttyUSB0"); 15 | 16 | if (argc > 1) { 17 | 18 | port = argv[1]; // the serial port can be provided as a parameter on the command line. 19 | } 20 | 21 | Master mb (Rtu, port , "38400E1"); // new master on RTU 22 | // if you have to handle the DE signal of the line driver with RTS, 23 | // you should uncomment the lines below... 24 | // mb.rtu().setRts(RtsDown); 25 | // mb.rtu().setSerialMode(Rs485); 26 | 27 | Slave & slv = mb.addSlave (33); // SolarPi Pressure meter 28 | 29 | cout << "Reads input registers of slave[" << slv.number() << "] on " << 30 | mb.connection() << " (" << mb.settings() << ")" << endl; 31 | 32 | if (mb.open ()) { // open a connection 33 | // success, do what you want here 34 | uint16_t values[2]; 35 | 36 | if (slv.readInputRegisters (1, values, 2) == 2) { 37 | 38 | cout << "R0=" << values[0] << endl; 39 | cout << "R1=" << values[1] << endl; 40 | } 41 | else { 42 | cerr << "Unable to read input registers ! " << mb.lastError() << endl; 43 | exit (EXIT_FAILURE); 44 | } 45 | mb.close(); 46 | } 47 | else { 48 | cerr << "Unable to open MODBUS connection to " << port << " : " << mb.lastError() << endl; 49 | exit (EXIT_FAILURE); 50 | } 51 | 52 | return 0; 53 | } 54 | /* ========================================================================== */ 55 | -------------------------------------------------------------------------------- /examples/master/read-input-registers/read-input-registers.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=read-input-registers 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/master/read-input-registers 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="read-input-registers.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/master/read-input-registers/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/master/read-input-registers/read-input-registers.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/master/report-slave-id/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(report-slave-id) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/master/report-slave-id/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f report-slave-id.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows ™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o clock-server $(pkg-config --cflags --libs libmodbuspp) main.cpp 20 | -------------------------------------------------------------------------------- /examples/master/report-slave-id/main.cpp: -------------------------------------------------------------------------------- 1 | // Reads the slave identifier from SolarPi pressure meter and print as follow : 2 | 3 | // Length: 14 4 | // Id : 0x02 5 | // Status: On 6 | // Data : press-1.1.58 7 | 8 | // This example code is in the public domain. 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | using namespace Modbus; 15 | 16 | // ----------------------------------------------------------------------------- 17 | int main (int argc, char **argv) { 18 | string port ("/dev/ttyUSB0"); 19 | 20 | if (argc > 1) { 21 | 22 | port = argv[1]; // the serial port can be provided as a parameter on the command line. 23 | } 24 | 25 | Master mb (Rtu, port, "38400E1"); // new master on RTU 26 | // if you have to handle the DE signal of the line driver with RTS, 27 | // you should uncomment the lines below... 28 | // mb.rtu().setRts(RtsDown); 29 | // mb.rtu().setSerialMode(Rs485); 30 | 31 | Slave & slv = mb.addSlave (33); // SolarPi Pressure meter 32 | 33 | cout << "Reads identifier of slave[" << slv.number() << "] on " << 34 | mb.connection() << " (" << mb.settings() << ")" << endl; 35 | 36 | if (mb.open ()) { // open a connection 37 | // success, do what you want here 38 | SlaveReport i; 39 | 40 | if (slv.reportSlaveId (i) > 0) { 41 | 42 | cout << "Length: " << i.size() << endl; 43 | cout << "Id : 0x" << setfill ('0') << setw (2) << hex << (int) i.id() << endl; 44 | cout << "Status: " << (i.status() ? "On" : "Off") << endl; 45 | cout << "Data : " << i.data() << endl; 46 | } 47 | else { 48 | cerr << "Unable to read slave identifier ! " << mb.lastError() << endl; 49 | exit (EXIT_FAILURE); 50 | } 51 | mb.close(); 52 | } 53 | else { 54 | cerr << "Unable to open MODBUS connection to " << port << " : " << mb.lastError() << endl; 55 | exit (EXIT_FAILURE); 56 | } 57 | 58 | return 0; 59 | } 60 | /* ========================================================================== */ 61 | -------------------------------------------------------------------------------- /examples/master/report-slave-id/report-slave-id.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=report-slave-id 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/master/report-slave-id 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="report-slave-id.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/master/report-slave-id/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/master/report-slave-id/report-slave-id.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | None 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | /usr/include/modbuspp 55 | /usr/local/include/modbuspp 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | None 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | /usr/include/modbuspp 96 | /usr/local/include/modbuspp 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /examples/master/report-slave-id/report-slave-id.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/master/rw-holding-json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(rw-holding-json) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/master/rw-holding-json/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f rw-holding-json.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o rw-holding-json $(pkg-config --cflags --libs modbuspp) main.cpp 20 | -------------------------------------------------------------------------------- /examples/master/rw-holding-json/main.cpp: -------------------------------------------------------------------------------- 1 | // Read/Writes floating point holding registers to SolarPi pressure meter 2 | // the MODBUS master is configured from the JSON ./master.json file 3 | 4 | // The pressure sensor calibration is composed of 4 decimal values. 5 | // The first 2 are the minimum and maximum pressure calibration values in hPa. 6 | // The following 2 are the output values of the analog-to-digital converter 7 | // (in LSB) corresponding to the calibration values. 8 | 9 | // This example code is in the public domain. 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | using namespace Modbus; 17 | 18 | int main (int argc, char **argv) { 19 | string jsonfile ("../master.json"); 20 | 21 | if (argc > 1) { 22 | 23 | jsonfile = argv[1]; // the JSON filename can be provided as a parameter on the command line. 24 | } 25 | 26 | Master mb (jsonfile, "modbuspp-master"); 27 | Slave & slv = mb.slave (33); // SolarPi Pressure meter 28 | 29 | cout << "Read/Write holding registers of slave[" << slv.number() << "] on " << 30 | mb.connection() << " (" << mb.settings() << ")" << endl; 31 | 32 | if (mb.open ()) { // open a connection 33 | // success, do what you want here 34 | int ret; 35 | 36 | Data backup[4]; 37 | // the bytes in the registers are arranged in big endian. 38 | // the solarpi calibration registers are arranged in little endian. 39 | Data bank1[4]; 40 | Data bank2[4]; 41 | 42 | // reads values .... 43 | if (slv.readRegisters (1, backup, 4) > 0) { 44 | 45 | // then print them ! 46 | cout << "R0=" << backup[0].value() << endl; 47 | cout << "R1=" << backup[1].value() << endl; 48 | cout << "R2=" << backup[2].value() << endl; 49 | cout << "R3=" << backup[3].value() << endl; 50 | } 51 | else { 52 | cerr << "Unable to read holding registers ! " << mb.lastError() << endl; 53 | exit (EXIT_FAILURE); 54 | } 55 | 56 | // set values ... 57 | bank1[0] = 152.3; 58 | bank1[1] = 1010.7; 59 | bank1[2] = 45; 60 | bank1[3] = 901; 61 | 62 | // then writing to registers 63 | ret = slv.writeRegisters (1, bank1, 4); 64 | if (ret < 0) { 65 | 66 | cerr << "Unable to write holding registers ! " << mb.lastError() << endl; 67 | exit (EXIT_FAILURE); 68 | } 69 | else { 70 | cout << ret << " registers written (16-bit)." << endl; 71 | } 72 | 73 | // check if the values have been written 74 | if (slv.readRegisters (1, bank2, 4) > 0) { 75 | bool ok = true; 76 | 77 | for (int i = 0; i < 4; i++) { 78 | ok = ok && (bank1[i] == bank2[i]); 79 | } 80 | 81 | if (ok) { 82 | 83 | cout << "Registers have been correctly written" << endl; 84 | } 85 | else { 86 | 87 | cout << "Registers were not correctly written" << endl; 88 | // then print them ! 89 | cout << "R0=" << bank2[0].value() << endl; 90 | cout << "R1=" << bank2[1].value() << endl; 91 | cout << "R2=" << bank2[2].value() << endl; 92 | cout << "R3=" << bank2[3].value() << endl; 93 | } 94 | } 95 | else { 96 | cerr << "Unable to read holding registers ! " << mb.lastError() << endl; 97 | exit (EXIT_FAILURE); 98 | } 99 | 100 | ret = slv.writeRegisters (1, backup, 4); 101 | if (ret < 0) { 102 | 103 | cerr << "Unable to write holding registers ! " << mb.lastError() << endl; 104 | exit (EXIT_FAILURE); 105 | } 106 | else { 107 | cout << ret << " restored registers (16-bit)." << endl; 108 | } 109 | 110 | mb.close(); 111 | } 112 | else { 113 | cerr << "Unable to open MODBUS connection to " << mb.connection() << " : " 114 | << mb.lastError() << endl; 115 | exit (EXIT_FAILURE); 116 | } 117 | 118 | return 0; 119 | } 120 | /* ========================================================================== */ 121 | -------------------------------------------------------------------------------- /examples/master/rw-holding-json/master.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-master": { 3 | "mode": "rtu", 4 | "connection": "/dev/tnt0", 5 | "settings": "38400E1", 6 | "debug": true, 7 | "response-timeout": 500, 8 | "byte-timeout": 500, 9 | "rtu": { 10 | "mode": "rs232", 11 | "rts": "none", 12 | "rts-delay": 1000 13 | }, 14 | "slaves": [ 15 | { 16 | "id": 32 17 | }, 18 | { 19 | "id": 33 20 | }, 21 | { 22 | "id": 34 23 | }, 24 | { 25 | "id": 35 26 | } 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/master/rw-holding-json/rw-holding-json.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=rw-holding-json 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/master/rw-holding-json 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="rw-holding-json.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/master/rw-holding-json/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/master/rw-holding-json/rw-holding-json.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/master/write-holding-data/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(write-holding-data) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/master/write-holding-data/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f write-holding-data.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o write-holding-dat $(pkg-config --cflags --libs modbuspp) main.cpp 20 | -------------------------------------------------------------------------------- /examples/master/write-holding-data/main.cpp: -------------------------------------------------------------------------------- 1 | // Writes floating point holding registers to SolarPi pressure meter 2 | 3 | // The pressure sensor calibration is composed of 4 decimal values. 4 | // The first 2 are the minimum and maximum pressure calibration values in hPa. 5 | // The following 2 are the output values of the analog-to-digital converter 6 | // (in LSB) corresponding to the calibration values. 7 | 8 | // This example code is in the public domain. 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | using namespace Modbus; 15 | 16 | int main (int argc, char **argv) { 17 | string port ("/dev/ttyUSB0"); 18 | 19 | if (argc > 1) { 20 | 21 | port = argv[1]; // the serial port can be provided as a parameter on the command line. 22 | } 23 | 24 | Master mb (Rtu, port , "38400E1"); // new master on RTU 25 | // if you have to handle the DE signal of the line driver with RTS, 26 | // you should uncomment the lines below... 27 | // mb.rtu().setRts(RtsDown); 28 | // mb.rtu().setSerialMode(Rs485); 29 | 30 | Slave & slv = mb.addSlave (33); // SolarPi Pressure meter 31 | 32 | cout << "Write holding registers of slave[" << slv.number() << "] on " << 33 | mb.connection() << " (" << mb.settings() << ")" << endl; 34 | 35 | if (mb.open ()) { // open a connection 36 | // success, do what you want here 37 | int ret; 38 | 39 | // the bytes in the registers are arranged in big endian. 40 | // the solarpi calibration registers are arranged in little endian. 41 | Data registers[4]; 42 | 43 | // set values ... 44 | registers[0] = 152.3; 45 | registers[1] = 1010.7; 46 | registers[2] = 45; 47 | registers[3] = 901; 48 | 49 | // then writing to registers 50 | ret = slv.writeRegisters (1, registers, 4); 51 | 52 | if (ret < 0) { 53 | 54 | cerr << "Unable to write input registers ! " << mb.lastError() << endl; 55 | exit (EXIT_FAILURE); 56 | } 57 | else { 58 | cout << ret << " registers written (16-bit)." << endl; 59 | } 60 | 61 | mb.close(); 62 | } 63 | else { 64 | cerr << "Unable to open MODBUS connection to " << port << " : " << mb.lastError() << endl; 65 | exit (EXIT_FAILURE); 66 | } 67 | 68 | return 0; 69 | } 70 | /* ========================================================================== */ 71 | -------------------------------------------------------------------------------- /examples/master/write-holding-data/write-holding-data.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=write-holding-data 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/master/write-holding-data 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="write-holding-data.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/master/write-holding-data/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/master/write-holding-data/write-holding-data.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/router/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | add_subdirectory(router-json) 4 | add_subdirectory(router-simple) -------------------------------------------------------------------------------- /examples/router/router-json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(router-json) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/router/router-json/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f router-json.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o router-json $(pkg-config --cflags --libs modbuspp) main.cpp 20 | 21 | -------------------------------------------------------------------------------- /examples/router/router-json/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief libmodbuspp router-json example 3 | * 4 | * Shows how to use libmodbuspp to build a MODBUS time server. 5 | * the MODBUS router is configured from a JSON file 6 | * 7 | * @code 8 | * router-json json_filename 9 | * @endcode 10 | * 11 | * Once the router has started you can test it with mbpoll : 12 | * 13 | * @code 14 | $ mbpoll -mtcp -p1502 -a10 -t3 -c8 localhost 15 | mbpoll 1.4-12 - FieldTalk(tm) Modbus(R) Master Simulator 16 | Copyright © 2015-2019 Pascal JEAN, https://github.com/epsilonrt/mbpoll 17 | This program comes with ABSOLUTELY NO WARRANTY. 18 | This is free software, and you are welcome to redistribute it 19 | under certain conditions; type 'mbpoll -w' for details. 20 | 21 | Protocol configuration: Modbus TCP 22 | Slave configuration...: address = [10] 23 | start reference = 1, count = 8 24 | Communication.........: localhost, port 1502, t/o 1.00 s, poll rate 1000 ms 25 | Data type.............: 16-bit register, input register table 26 | 27 | -- Polling slave 10... Ctrl-C to stop) 28 | [1]: 37 29 | [2]: 40 30 | [3]: 15 31 | [4]: 28 32 | [5]: 11 33 | [6]: 2019 34 | [7]: 4 35 | [8]: 332 36 | * @endcode 37 | * 38 | * These data correspond to 15:40:37 on Thursday 28/11/2019, 332nd day of the 39 | * year. To read the time difference from GMT (in seconds) : 40 | * 41 | * @code 42 | $ mbpoll -mtcp -p1502 -a10 -t4:int -B -1 localhost 43 | .... 44 | -- Polling slave 10... 45 | [1]: 3600 46 | * @endcode 47 | * 48 | * To set the offset to GMT-2 hours : 49 | * 50 | * @code 51 | $ mbpoll -mtcp -p1502 -a10 -t4:int -B localhost -- -7200 52 | .... 53 | Written 1 references. 54 | * @endcode 55 | */ 56 | #include 57 | #include 58 | #include 59 | #include 60 | 61 | using namespace std; 62 | using namespace Modbus; 63 | 64 | Router router; // instantiates new MODBUS Router 65 | 66 | // ----------------------------------------------------------------------------- 67 | // Signal trap, triggers during a CTRL+C or if kill is called 68 | void 69 | sighandler (int sig) { 70 | 71 | router.close(); 72 | cout << "everything was closed." << endl << "Have a nice day !" << endl; 73 | } 74 | 75 | // ----------------------------------------------------------------------------- 76 | int main (int argc, char **argv) { 77 | 78 | if (argc < 2) { 79 | 80 | cerr << "Error: the JSON filename must be provided as a parameter on the command line !" << endl; 81 | cerr << "e.g. : " << argv[0] << " router-tcp-rs232.json" << endl; 82 | exit (EXIT_FAILURE); 83 | } 84 | 85 | string jsonfile = argv[1]; 86 | 87 | cout << "--- Json Modbus Router ---" << endl; 88 | 89 | // CTRL+C and kill call triggers the trap sighandler() 90 | signal (SIGINT, sighandler); 91 | signal (SIGTERM, sighandler); 92 | cout << "Press CTRL+C to stop... " << endl; 93 | 94 | try { 95 | cout << "opening " << jsonfile << "..." << endl; 96 | router.setConfig (jsonfile, "modbuspp-router"); 97 | 98 | if (router.debug()) { 99 | // if debug, list masters and slaves 100 | cout << endl; 101 | for (const auto & m : router.masters()) { 102 | 103 | auto master = m.second; 104 | cout << "Master " << m.first << " connected through " << flush; 105 | cout << master->connection() << ":" ; 106 | cout << master->settings() << " with the slaves below:" << endl; 107 | for (const auto & s : router.slaves()) { 108 | 109 | auto slave = s.second; 110 | if (slave->device() == master.get()) { 111 | cout << "> id: " << slave->number() << endl; 112 | } 113 | } 114 | cout << endl; 115 | } 116 | } 117 | 118 | if (router.open ()) { // open a connection 119 | cout << "Listening server on " << 120 | router.connection() << ":" << router.settings() << "..." 121 | << endl << endl; 122 | 123 | router.run(); 124 | while (router.isOpen()) { 125 | 126 | // std::this_thread::yield(); 127 | std::this_thread::sleep_for (std::chrono::milliseconds (200)); 128 | } 129 | } 130 | } 131 | catch (std::exception & e) { 132 | 133 | cerr << "Error: " << e.what() << endl; 134 | } 135 | catch (...) { 136 | 137 | cerr << "Unattended exception !" << endl; 138 | } 139 | 140 | return EXIT_FAILURE; 141 | } 142 | /* ========================================================================== */ 143 | -------------------------------------------------------------------------------- /examples/router/router-json/router-json.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=router-json 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/router/router-json 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="router-json.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/router/router-json/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/router/router-json/router-json.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/router/router-json/router-rf95-rs485.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-router": { 3 | "name": "rf95-rtu-bridge", 4 | "mode": "rtu", 5 | "connection": "/dev/tnt0", 6 | "settings": "38400E1", 7 | "debug": true, 8 | "response-timeout": 3000, 9 | "byte-timeout": 500, 10 | "masters": [ 11 | { 12 | "name": "rs485", 13 | "mode": "rtu", 14 | "connection": "/dev/ttyS1", 15 | "settings": "38400E1", 16 | "debug": true, 17 | "response-timeout": 500, 18 | "byte-timeout": 500, 19 | "rtu": { 20 | "mode": "rs485", 21 | "rts": "down" 22 | }, 23 | "slaves": [ 24 | { 25 | "id": 16, 26 | "blocks": [ 27 | { 28 | "table": "discrete-input", 29 | "quantity": 1, 30 | "starting-address": 4 31 | }, 32 | { 33 | "table": "coil", 34 | "quantity": 3 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/router/router-json/router-tcp-rs232-rf95-2slaves.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-router": { 3 | "mode": "tcp", 4 | "connection": "*", 5 | "settings": "1502", 6 | "recovery-link": true, 7 | "debug": true, 8 | "response-timeout": 500, 9 | "byte-timeout": 500, 10 | "masters": [ 11 | { 12 | "name": "rs232", 13 | "mode": "rtu", 14 | "connection": "/dev/ttyUSB0", 15 | "settings": "38400E1", 16 | "debug": true, 17 | "response-timeout": 500, 18 | "byte-timeout": 500, 19 | "slaves": [ 20 | { 21 | "id": 40, 22 | "blocks": [ 23 | { 24 | "table": "discrete-input", 25 | "quantity": 6 26 | }, 27 | { 28 | "table": "input-register", 29 | "quantity": 2 30 | }, 31 | { 32 | "table": "holding-register", 33 | "quantity": 8 34 | } 35 | ] 36 | } 37 | ] 38 | }, 39 | { 40 | "name": "rf95-rtu-bridge", 41 | "mode": "rtu", 42 | "connection": "/dev/tnt0", 43 | "settings": "38400E1", 44 | "debug": true, 45 | "response-timeout": 3000, 46 | "byte-timeout": 500, 47 | "slaves": [ 48 | { 49 | "id": 10, 50 | "name": "lamp-on-arduino", 51 | "blocks": [ 52 | { 53 | "table": "coil", 54 | "quantity": 1 55 | } 56 | ] 57 | }, 58 | { 59 | "id": 16, 60 | "name": "hooc-on-lora-station", 61 | "blocks": [ 62 | { 63 | "table": "discrete-input", 64 | "quantity": 1, 65 | "starting-address": 4 66 | }, 67 | { 68 | "table": "coil", 69 | "quantity": 3 70 | } 71 | ] 72 | } 73 | ] 74 | } 75 | ] 76 | } 77 | } -------------------------------------------------------------------------------- /examples/router/router-json/router-tcp-rs232-rf95.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-router": { 3 | "mode": "tcp", 4 | "connection": "*", 5 | "settings": "1502", 6 | "recovery-link": true, 7 | "debug": true, 8 | "response-timeout": 500, 9 | "byte-timeout": 500, 10 | "masters": [ 11 | { 12 | "name": "rs232", 13 | "mode": "rtu", 14 | "connection": "/dev/ttyUSB0", 15 | "settings": "38400E1", 16 | "debug": true, 17 | "response-timeout": 500, 18 | "byte-timeout": 500, 19 | "slaves": [ 20 | { 21 | "id": 40, 22 | "blocks": [ 23 | { 24 | "table": "discrete-input", 25 | "quantity": 6 26 | }, 27 | { 28 | "table": "input-register", 29 | "quantity": 2 30 | }, 31 | { 32 | "table": "holding-register", 33 | "quantity": 8 34 | } 35 | ] 36 | } 37 | ] 38 | }, 39 | { 40 | "name": "rf95-rtu-bridge", 41 | "mode": "rtu", 42 | "connection": "/dev/tnt0", 43 | "settings": "38400E1", 44 | "debug": true, 45 | "response-timeout": 3000, 46 | "byte-timeout": 500, 47 | "slaves": [ 48 | { 49 | "id": 10, 50 | "name": "lamp-on-arduino", 51 | "blocks": [ 52 | { 53 | "table": "coil", 54 | "quantity": 1 55 | } 56 | ] 57 | } 58 | ] 59 | } 60 | ] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /examples/router/router-json/router-tcp-rs232-rf95.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/epsilonrt/libmodbuspp/0851f3114b90f8e10f565afaec9331f49bc72da1/examples/router/router-json/router-tcp-rs232-rf95.png -------------------------------------------------------------------------------- /examples/router/router-json/router-tcp-rs232-virtual.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-router": { 3 | "mode": "tcp", 4 | "connection": "localhost", 5 | "settings": "1502", 6 | "recovery-link": true, 7 | "debug": true, 8 | "response-timeout": 500, 9 | "byte-timeout": 500, 10 | "masters": [ 11 | { 12 | "name": "rs232", 13 | "mode": "rtu", 14 | "connection": "/dev/ttyUSB0", 15 | "settings": "38400E1", 16 | "debug": true, 17 | "response-timeout": 500, 18 | "byte-timeout": 500, 19 | "slaves": [ 20 | { 21 | "id": 33, 22 | "blocks": [ 23 | { 24 | "table": "input-register", 25 | "quantity": 6 26 | }, 27 | { 28 | "table": "holding-register", 29 | "quantity": 8 30 | } 31 | ] 32 | } 33 | ] 34 | }, 35 | { 36 | "name": "virtual-clock", 37 | "mode": "rtu", 38 | "connection": "/dev/tnt0", 39 | "settings": "38400E1", 40 | "debug": true, 41 | "response-timeout": 3000, 42 | "byte-timeout": 500, 43 | "slaves": [ 44 | { 45 | "id": 10, 46 | "blocks": [ 47 | { 48 | "table": "input-register", 49 | "quantity": 8 50 | }, 51 | { 52 | "table": "holding-register", 53 | "quantity": 2 54 | }, 55 | { 56 | "table": "coil", 57 | "quantity": 1 58 | } 59 | ] 60 | } 61 | ] 62 | } 63 | ] 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /examples/router/router-json/router-tcp-rs232.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-router": { 3 | "mode": "tcp", 4 | "connection": "localhost", 5 | "settings": "1502", 6 | "recovery-link": true, 7 | "debug": true, 8 | "response-timeout": 500, 9 | "byte-timeout": 500, 10 | "masters": [ 11 | { 12 | "name": "rs232", 13 | "mode": "rtu", 14 | "connection": "/dev/ttyUSB0", 15 | "settings": "38400E1", 16 | "debug": true, 17 | "response-timeout": 500, 18 | "byte-timeout": 500, 19 | "slaves": [ 20 | { 21 | "id": 33, 22 | "blocks": [ 23 | { 24 | "table": "input-register", 25 | "quantity": 6 26 | }, 27 | { 28 | "table": "holding-register", 29 | "quantity": 8 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/router/router-json/router-tcp-rs485-virtual.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-router": { 3 | "mode": "tcp", 4 | "connection": "localhost", 5 | "settings": "1502", 6 | "recovery-link": true, 7 | "debug": true, 8 | "response-timeout": 500, 9 | "byte-timeout": 500, 10 | "masters": [ 11 | { 12 | "name": "rs485", 13 | "mode": "rtu", 14 | "connection": "/dev/ttyS1", 15 | "settings": "38400E1", 16 | "debug": true, 17 | "response-timeout": 500, 18 | "byte-timeout": 500, 19 | "rtu": { 20 | "mode": "rs485", 21 | "rts": "down" 22 | }, 23 | "slaves": [ 24 | { 25 | "id": 33, 26 | "blocks": [ 27 | { 28 | "table": "input-register", 29 | "quantity": 6 30 | }, 31 | { 32 | "table": "holding-register", 33 | "quantity": 8 34 | } 35 | ] 36 | } 37 | ] 38 | }, 39 | { 40 | "name": "virtual-clock", 41 | "mode": "rtu", 42 | "connection": "/dev/tnt0", 43 | "settings": "38400E1", 44 | "debug": true, 45 | "response-timeout": 3000, 46 | "byte-timeout": 500, 47 | "slaves": [ 48 | { 49 | "id": 10, 50 | "blocks": [ 51 | { 52 | "table": "input-register", 53 | "quantity": 8 54 | }, 55 | { 56 | "table": "holding-register", 57 | "quantity": 2 58 | }, 59 | { 60 | "table": "coil", 61 | "quantity": 1 62 | } 63 | ] 64 | } 65 | ] 66 | } 67 | ] 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /examples/router/router-json/router-virtual-rs232.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-router": { 3 | "mode": "rtu", 4 | "connection": "/dev/tnt1", 5 | "settings": "38400E1", 6 | "debug": true, 7 | "response-timeout": 500, 8 | "byte-timeout": 500, 9 | "masters": [ 10 | { 11 | "name": "rs485", 12 | "mode": "rtu", 13 | "connection": "/dev/ttyUSB0", 14 | "settings": "38400E1", 15 | "debug": true, 16 | "response-timeout": 500, 17 | "byte-timeout": 500, 18 | "slaves": [ 19 | { 20 | "id": 32, 21 | "blocks": [ 22 | { 23 | "table": "input-register", 24 | "quantity": 2 25 | }, 26 | { 27 | "table": "holding-register", 28 | "quantity": 8 29 | } 30 | ] 31 | }, 32 | { 33 | "id": 33, 34 | "blocks": [ 35 | { 36 | "table": "input-register", 37 | "quantity": 6 38 | }, 39 | { 40 | "table": "holding-register", 41 | "quantity": 8 42 | } 43 | ] 44 | }, 45 | { 46 | "id": 34, 47 | "blocks": [ 48 | { 49 | "table": "input-register", 50 | "quantity": 2 51 | }, 52 | { 53 | "table": "holding-register", 54 | "quantity": 8 55 | } 56 | ] 57 | }, 58 | { 59 | "id": 35, 60 | "blocks": [ 61 | { 62 | "table": "input-register", 63 | "quantity": 4 64 | }, 65 | { 66 | "table": "holding-register", 67 | "quantity": 10 68 | } 69 | ] 70 | } 71 | ] 72 | } 73 | ] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/router/router-json/router-virtual-rs485.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-router": { 3 | "mode": "rtu", 4 | "connection": "/dev/tnt1", 5 | "settings": "38400E1", 6 | "debug": true, 7 | "response-timeout": 500, 8 | "byte-timeout": 500, 9 | "masters": [ 10 | { 11 | "name": "rs485", 12 | "mode": "rtu", 13 | "connection": "/dev/ttyS1", 14 | "settings": "38400E1", 15 | "debug": true, 16 | "response-timeout": 500, 17 | "byte-timeout": 500, 18 | "rtu": { 19 | "mode": "rs485", 20 | "rts": "down" 21 | }, 22 | "slaves": [ 23 | { 24 | "id": 33, 25 | "blocks": [ 26 | { 27 | "table": "input-register", 28 | "quantity": 6 29 | }, 30 | { 31 | "table": "holding-register", 32 | "quantity": 8 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/router/router-simple/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(router-simple) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/router/router-simple/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f router-simple.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o router-simple $(pkg-config --cflags --libs modbuspp) main.cpp 20 | 21 | -------------------------------------------------------------------------------- /examples/router/router-simple/router-simple.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=router-simple 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/router/router-simple 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="router-simple.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/router/router-simple/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/router/router-simple/router-simple.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | add_subdirectory(callback-server-json) 4 | add_subdirectory(clock-server) 5 | add_subdirectory(clock-server-json) 6 | add_subdirectory(simple-server-json) -------------------------------------------------------------------------------- /examples/server/callback-server-json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(callback-server-json) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/server/callback-server-json/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f callback-server-json.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o callback-server-json $(pkg-config --cflags --libs modbuspp) main.cpp 20 | 21 | -------------------------------------------------------------------------------- /examples/server/callback-server-json/callback-server-json.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=callback-server-json 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/server/callback-server-json 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="callback-server-json.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/server/callback-server-json/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/server/callback-server-json/callback-server-json.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/server/callback-server-json/rtu-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-server": { 3 | "mode": "rtu", 4 | "connection": "/dev/tnt1", 5 | "settings": "38400E1", 6 | "debug": true, 7 | "response-timeout": 500, 8 | "byte-timeout": 500 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/server/callback-server-json/tcp-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-server": { 3 | "mode": "tcp", 4 | "connection": "localhost", 5 | "settings": "1502", 6 | "debug": true, 7 | "recovery-link": true, 8 | "response-timeout": 500, 9 | "byte-timeout": 500 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/server/clock-server-json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(clock-server-json) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/server/clock-server-json/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f clock-server-json.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o clock-server-json $(pkg-config --cflags --libs modbuspp) main.cpp 20 | 21 | -------------------------------------------------------------------------------- /examples/server/clock-server-json/clock-server-json.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=clock-server-json 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/server/clock-server-json 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="clock-server-json.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/server/clock-server-json/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/server/clock-server-json/clock-server-json.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/server/clock-server-json/clock-server-tcp.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-server": { 3 | "mode": "tcp", 4 | "connection": "localhost", 5 | "settings": "1502", 6 | "recovery-link": true, 7 | "debug": true, 8 | "response-timeout": 500, 9 | "byte-timeout": 500, 10 | "slaves": [ 11 | { 12 | "id": 10, 13 | "pdu-adressing": false, 14 | "blocks": [ 15 | { 16 | "table": "input-register", 17 | "starting-address": 1, 18 | "quantity": 8 19 | }, 20 | { 21 | "table": "holding-register", 22 | "quantity": 2 23 | }, 24 | { 25 | "table": "coil", 26 | "quantity": 1 27 | } 28 | ] 29 | } 30 | ] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/server/clock-server-json/clock-server-virtual.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-server": { 3 | "mode": "rtu", 4 | "connection": "/dev/tnt1", 5 | "settings": "38400E1", 6 | "debug": true, 7 | "response-timeout": 500, 8 | "byte-timeout": 500, 9 | "slaves": [ 10 | { 11 | "id": 10, 12 | "pdu-adressing": false, 13 | "blocks": [ 14 | { 15 | "table": "input-register", 16 | "starting-address": 1, 17 | "quantity": 8 18 | }, 19 | { 20 | "table": "holding-register", 21 | "quantity": 2 22 | }, 23 | { 24 | "table": "coil", 25 | "quantity": 1 26 | } 27 | ] 28 | } 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/server/clock-server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(clock-server) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/server/clock-server/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f clock-server.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o clock-server $(pkg-config --cflags --libs modbuspp) main.cpp 20 | 21 | -------------------------------------------------------------------------------- /examples/server/clock-server/clock-server.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=clock-server 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/server/clock-server 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="clock-server.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/server/clock-server/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/server/clock-server/clock-server.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/server/simple-server-json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # 4 | project(simple-server-json) 5 | 6 | set(CMAKE_CXX_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | find_package(PkgConfig REQUIRED) 11 | pkg_check_modules(LIBMODBUSPP REQUIRED IMPORTED_TARGET modbuspp) 12 | 13 | add_executable(${PROJECT_NAME} main.cpp) 14 | target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::LIBMODBUSPP) 15 | 16 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 17 | -------------------------------------------------------------------------------- /examples/server/simple-server-json/README.md: -------------------------------------------------------------------------------- 1 | # How to build this example ? 2 | 3 | This example is intended to be compiled with [Codelite](https://codelite.org). 4 | 5 | [Codelite](https://codelite.org) is a free cross-platform software... 6 | 7 | If you want to compile it without codelite, you can do it with [GNU make](https://www.gnu.org/software/make/) : 8 | 9 | make -f simple-server-json.mk 10 | 11 | You can then run the program that is in the Debug folder. 12 | 13 | Nevertheless, I am not sure that it works on Windows™ and macOS ™, so you 14 | should follow my advice and use CodeLite... 15 | 16 | This library provides a file for pkg-config that should also allow you to 17 | compile with gcc: 18 | 19 | g++ -o simple-server-json $(pkg-config --cflags --libs modbuspp) main.cpp 20 | 21 | -------------------------------------------------------------------------------- /examples/server/simple-server-json/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief libmodbuspp simple-server-json example 3 | * 4 | * Shows how to make a purely virtual MODBUS TCP server, the JSON file describes 5 | * the different data blocks (coils, discrete inputs, input and storage registers) 6 | * and initializes the values at startup. 7 | * 8 | * @code 9 | * simple-server-json ../tcp-server.json 10 | * @endcode 11 | * 12 | * Once the server has started you can test it with mbpoll : 13 | * 14 | * @code 15 | $ mbpoll -mtcp -p1502 -a10 -t3 -c8 localhost 16 | mbpoll 1.4-12 - FieldTalk(tm) Modbus(R) Master Simulator 17 | Copyright © 2015-2019 Pascal JEAN, https://github.com/epsilonrt/mbpoll 18 | This program comes with ABSOLUTELY NO WARRANTY. 19 | This is free software, and you are welcome to redistribute it 20 | under certain conditions; type 'mbpoll -w' for details. 21 | 22 | Protocol configuration: Modbus TCP 23 | Slave configuration...: address = [10] 24 | start reference = 1, count = 8 25 | Communication.........: localhost, port 1502, t/o 1.00 s, poll rate 1000 ms 26 | Data type.............: 16-bit register, input register table 27 | 28 | -- Polling slave 10... Ctrl-C to stop) 29 | [1]: 37 30 | [2]: 40 31 | [3]: 15 32 | [4]: 28 33 | [5]: 11 34 | [6]: 2019 35 | [7]: 4 36 | [8]: 332 37 | * @endcode 38 | * 39 | */ 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | using namespace std; 46 | using namespace Modbus; 47 | 48 | Server srv; // instantiates new MODBUS Server 49 | 50 | // ----------------------------------------------------------------------------- 51 | // Signal trap, triggers during a CTRL+C or if kill is called 52 | void 53 | sighandler (int sig) { 54 | 55 | srv.close(); 56 | cout << "everything was closed." << endl << "Have a nice day !" << endl; 57 | exit (EXIT_SUCCESS); 58 | } 59 | 60 | // ----------------------------------------------------------------------------- 61 | int main (int argc, char **argv) { 62 | 63 | if (argc < 2) { 64 | 65 | cerr << "Error: the JSON filename must be provided as a parameter on the command line !" << endl; 66 | cerr << "e.g. : " << argv[0] << " virtual-server-tcp.json" << endl; 67 | exit (EXIT_FAILURE); 68 | } 69 | 70 | string jsonfile = argv[1]; 71 | 72 | cout << "Simple Server" << endl; 73 | // CTRL+C and kill call triggers the trap sighandler() 74 | signal (SIGINT, sighandler); 75 | signal (SIGTERM, sighandler); 76 | cout << "Press CTRL+C to stop... " << endl << endl; 77 | 78 | try { 79 | cout << "opening " << jsonfile << "..." << endl; 80 | srv.setConfig (jsonfile, "modbuspp-server"); 81 | 82 | if (srv.open ()) { // open a connection 83 | cout << "Listening server on " << 84 | srv.connection() << ":" << srv.settings() << "..." << endl << endl; 85 | 86 | srv.run(); 87 | while (srv.isOpen()) { 88 | 89 | // std::this_thread::yield(); 90 | std::this_thread::sleep_for (std::chrono::milliseconds (200)); 91 | } 92 | } 93 | } 94 | catch (std::exception & e) { 95 | 96 | cerr << "Error: " << e.what() << endl; 97 | } 98 | catch (...) { 99 | 100 | cerr << "Unattended exception !" << endl; 101 | } 102 | 103 | return EXIT_FAILURE; 104 | } 105 | /* ========================================================================== */ 106 | -------------------------------------------------------------------------------- /examples/server/simple-server-json/simple-server-json.mk: -------------------------------------------------------------------------------- 1 | ## 2 | ## Auto Generated makefile by CodeLite IDE 3 | ## any manual changes will be erased 4 | ## 5 | ## Debug 6 | ProjectName :=simple-server-json 7 | ConfigurationName :=Debug 8 | WorkspacePath :=/home/pascal/src/libmodbuspp 9 | ProjectPath :=/home/pascal/src/libmodbuspp/examples/server/simple-server-json 10 | IntermediateDirectory :=./Debug 11 | OutDir := $(IntermediateDirectory) 12 | CurrentFileName := 13 | CurrentFilePath := 14 | CurrentFileFullPath := 15 | User :=epsilonrt 16 | Date :=03/07/20 17 | CodeLitePath :=/home/pascal/.codelite 18 | LinkerName :=/usr/bin/g++ 19 | SharedObjectLinkerName :=/usr/bin/g++ -shared -fPIC 20 | ObjectSuffix :=.o 21 | DependSuffix :=.o.d 22 | PreprocessSuffix :=.i 23 | DebugSwitch :=-g 24 | IncludeSwitch :=-I 25 | LibrarySwitch :=-l 26 | OutputSwitch :=-o 27 | LibraryPathSwitch :=-L 28 | PreprocessorSwitch :=-D 29 | SourceSwitch :=-c 30 | OutputFile :=$(IntermediateDirectory)/$(ProjectName) 31 | Preprocessors := 32 | ObjectSwitch :=-o 33 | ArchiveOutputSwitch := 34 | PreprocessOnlySwitch :=-E 35 | ObjectsFileList :="simple-server-json.txt" 36 | PCHCompileFlags := 37 | MakeDirCommand :=mkdir -p 38 | LinkOptions := $(shell pkg-config --libs modbuspp) 39 | IncludePath := $(IncludeSwitch). $(IncludeSwitch). 40 | IncludePCH := 41 | RcIncludePath := 42 | Libs := 43 | ArLibs := 44 | LibPath := $(LibraryPathSwitch). 45 | 46 | ## 47 | ## Common variables 48 | ## AR, CXX, CC, AS, CXXFLAGS and CFLAGS can be overriden using an environment variables 49 | ## 50 | AR := /usr/bin/ar rcu 51 | CXX := /usr/bin/g++ 52 | CC := /usr/bin/gcc 53 | CXXFLAGS := -std=c++11 $(shell pkg-config --cflags modbuspp) -g -O0 -Wall $(Preprocessors) 54 | CFLAGS := -std=c99 -g -O0 -Wall $(Preprocessors) 55 | ASFLAGS := 56 | AS := /usr/bin/as 57 | 58 | 59 | ## 60 | ## User defined environment variables 61 | ## 62 | CodeLiteDir:=/usr/share/codelite 63 | Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) 64 | 65 | 66 | 67 | Objects=$(Objects0) 68 | 69 | ## 70 | ## Main Build Targets 71 | ## 72 | .PHONY: all clean PreBuild PrePreBuild PostBuild MakeIntermediateDirs 73 | all: $(OutputFile) 74 | 75 | $(OutputFile): $(IntermediateDirectory)/.d $(Objects) 76 | @$(MakeDirCommand) $(@D) 77 | @echo "" > $(IntermediateDirectory)/.d 78 | @echo $(Objects0) > $(ObjectsFileList) 79 | $(LinkerName) $(OutputSwitch)$(OutputFile) @$(ObjectsFileList) $(LibPath) $(Libs) $(LinkOptions) 80 | 81 | MakeIntermediateDirs: 82 | @test -d ./Debug || $(MakeDirCommand) ./Debug 83 | 84 | 85 | $(IntermediateDirectory)/.d: 86 | @test -d ./Debug || $(MakeDirCommand) ./Debug 87 | 88 | PreBuild: 89 | 90 | 91 | ## 92 | ## Objects 93 | ## 94 | $(IntermediateDirectory)/main.cpp$(ObjectSuffix): main.cpp $(IntermediateDirectory)/main.cpp$(DependSuffix) 95 | $(CXX) $(IncludePCH) $(SourceSwitch) "/home/pascal/src/libmodbuspp/examples/server/simple-server-json/main.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IncludePath) 96 | $(IntermediateDirectory)/main.cpp$(DependSuffix): main.cpp 97 | @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/main.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/main.cpp$(DependSuffix) -MM main.cpp 98 | 99 | $(IntermediateDirectory)/main.cpp$(PreprocessSuffix): main.cpp 100 | $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/main.cpp$(PreprocessSuffix) main.cpp 101 | 102 | 103 | -include $(IntermediateDirectory)/*$(DependSuffix) 104 | ## 105 | ## Clean 106 | ## 107 | clean: 108 | $(RM) -r ./Debug/ 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/server/simple-server-json/simple-server-json.txt: -------------------------------------------------------------------------------- 1 | ./Debug/main.cpp.o 2 | -------------------------------------------------------------------------------- /examples/server/simple-server-json/tcp-server.json: -------------------------------------------------------------------------------- 1 | { 2 | "modbuspp-server": { 3 | "mode": "tcp", 4 | "connection": "localhost", 5 | "settings": "1502", 6 | "debug": true, 7 | "recovery-link": true, 8 | "response-timeout": 500, 9 | "byte-timeout": 500, 10 | "slaves": [ 11 | { 12 | "id": 10, 13 | "blocks": [ 14 | { 15 | "table": "holding-register", 16 | "starting-address": 1, 17 | "data-type": "float", 18 | "quantity": 4, 19 | "endian" : "cdab", 20 | "values" : [1.5,-3.14,5.23e12,1.63e-6] 21 | }, 22 | { 23 | "table": "input-register", 24 | "quantity": 2, 25 | "values" : [101,"0x100"] 26 | }, 27 | { 28 | "table": "coil", 29 | "quantity": 12, 30 | "values" : ["0x5A",true,1,false,0] 31 | }, 32 | { 33 | "table": "discrete-input", 34 | "quantity": 4, 35 | "values" : [0,0,1,1] 36 | } 37 | ] 38 | } 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /include/modbuspp.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | /* ========================================================================== */ 27 | -------------------------------------------------------------------------------- /include/modbuspp/netlayer.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace Modbus { 24 | class Message; 25 | 26 | /** 27 | * @class NetLayer 28 | * @brief Network layer base class (backend) 29 | * 30 | * @author Pascal JEAN, aka epsilonrt 31 | * @copyright GNU Lesser General Public License 32 | */ 33 | class NetLayer { 34 | public: 35 | 36 | /** 37 | * @brief Constructor 38 | */ 39 | NetLayer(); 40 | 41 | /** 42 | * @brief Destructor 43 | */ 44 | virtual ~NetLayer(); 45 | 46 | /** 47 | * @brief Underlying layer used (backend) 48 | * 49 | * This function allows to know the underlying layer used. 50 | */ 51 | Net net() const; 52 | 53 | /** 54 | * @brief Returns the maximum ADU length 55 | */ 56 | uint16_t maxAduLength() const; 57 | 58 | /** 59 | * @brief Returns the connection used 60 | * 61 | * Serial port or host depending on the backend. 62 | */ 63 | const std::string & connection() const; 64 | 65 | /** 66 | * @brief Returns the connection settings 67 | * 68 | * IP port or speed, parity and stop bit depending on the backend 69 | */ 70 | const std::string & settings() const; 71 | 72 | /** 73 | * @brief libmodbus context 74 | * 75 | * context is an opaque structure containing all necessary information to 76 | * establish a connection with other Modbus devices according to the 77 | * selected variant. 78 | */ 79 | modbus_t * context(); 80 | 81 | /** 82 | * @overload 83 | */ 84 | const modbus_t * context() const; 85 | 86 | /** 87 | * @brief Send a request/response @b msg via the socket of the @b context() 88 | * 89 | * This function can be used to send message not handled by the library. 90 | * The message is transmitted "raw", without any modification. 91 | * 92 | * @return The function shall return the full message length, if successful. 93 | * Otherwise it shall return -1 and set errno. 94 | */ 95 | virtual int sendRawMessage (const Message * msg); 96 | 97 | /** 98 | * @brief Prepare the message @b msg before sending 99 | * 100 | * This function updates the ADU header or adds the CRC at the end 101 | * depending on the network used.. 102 | */ 103 | virtual bool prepareToSend (Message & msg); 104 | 105 | /** 106 | * @brief Return true if the message is valid for this backend 107 | */ 108 | static bool checkMessage (const Message & msg); 109 | 110 | /** 111 | * @brief last error message 112 | * 113 | * This function shall return the error message corresponding to 114 | * the last error. This function must be called right after the 115 | * instruction that triggered an error. 116 | */ 117 | static std::string lastError(); 118 | 119 | protected: 120 | class Private; 121 | NetLayer (Private &dd); 122 | std::unique_ptr d_ptr; 123 | 124 | private: 125 | PIMP_DECLARE_PRIVATE (NetLayer) 126 | }; 127 | } 128 | 129 | /* ========================================================================== */ 130 | -------------------------------------------------------------------------------- /include/modbuspp/pimp.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | 21 | /* 22 | * Internal: Pointer to implementation 23 | * "Pointer to implementation" or "pImpl" is a C++ programming technique that 24 | * removes implementation details of a class from its object representation by 25 | * placing them in a separate class, accessed through an opaque pointer. 26 | * This technique is used to construct C++ library interfaces with stable 27 | * ABI and to reduce compile-time dependencies. 28 | */ 29 | #define PIMP_D(Class) Class::Private * const d = d_func() 30 | #define PIMP_Q(Class) Class * const q = q_func() 31 | #define PIMP_DECLARE_PRIVATE(Class)\ 32 | inline Class::Private* d_func() {\ 33 | return reinterpret_cast(d_ptr.get());\ 34 | }\ 35 | inline const Class::Private* d_func() const {\ 36 | return reinterpret_cast(d_ptr.get());\ 37 | }\ 38 | friend class Class::Private; 39 | #define PIMP_DECLARE_PUBLIC(Class) \ 40 | inline Class* q_func() { return reinterpret_cast(q_ptr); } \ 41 | inline const Class* q_func() const { return reinterpret_cast(q_ptr); } \ 42 | friend class Class; 43 | 44 | /* ========================================================================== */ 45 | -------------------------------------------------------------------------------- /include/modbuspp/slavereport.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include // memcpy ... 20 | #include 21 | 22 | namespace Modbus { 23 | 24 | /** 25 | * @class SlaveReport 26 | * @brief For storing and manipulate server identifier datas returns by the MODBUS 17 function 27 | */ 28 | template 29 | class SlaveReport { 30 | 31 | public: 32 | /** 33 | * @brief Default constructor 34 | */ 35 | SlaveReport() : m_endian (e), m_size (0) {} 36 | 37 | SlaveReport (int len, const uint8_t * reply) : SlaveReport() { 38 | memcpy(m_data, reply, len); 39 | m_size = len; 40 | } 41 | 42 | /** 43 | * @brief Run Indicator Status 44 | * @return true if ON. 45 | */ 46 | bool status() const { 47 | 48 | if (m_size > sizeof (T)) { 49 | 50 | return m_data[sizeof (T)] == 0xFF; 51 | } 52 | return false; 53 | } 54 | 55 | /** 56 | * @brief Server ID 57 | * @return the returned value is of type T which depends on the device 58 | */ 59 | T id() const { 60 | T v = 0; 61 | 62 | if (m_size >= sizeof (T)) { 63 | 64 | std::memcpy (&v, m_data, sizeof (T)); 65 | 66 | switch (m_endian) { // net value: ABCDEFGH 67 | case EndianBigBig: // ABCDEFGH: bytes Big, word Big : no swap 68 | break; 69 | case EndianBigLittle: // GHEFCDAB: bytes Big, word Little : swap words 70 | v = swapWords (v); 71 | break; 72 | case EndianLittleBig: // BADCFEHG: bytes Little, word Big : swap bytes of words 73 | v = swapBytesInWords (v); 74 | break; 75 | case EndianLittleLittle: // HGFEDCBA: bytes Little, word Little: swap all 76 | v = swapBytes (v); 77 | break; 78 | } 79 | return ntoh (v); 80 | } 81 | 82 | return v; 83 | } 84 | 85 | /** 86 | * @brief Additional Data 87 | * @return 88 | */ 89 | std::string data() const { 90 | std::string d; 91 | uint16_t len = m_size - (sizeof (T) + 1); 92 | 93 | if (len > 0) { 94 | 95 | d.assign (reinterpret_cast (&m_data[sizeof (T) + 1]), len); 96 | } 97 | return d; 98 | } 99 | 100 | /** 101 | * @brief number of bytes stored in the underlying array. 102 | */ 103 | inline uint16_t size() const { 104 | 105 | return m_size; 106 | } 107 | 108 | friend class Slave; 109 | 110 | protected: 111 | Endian m_endian; 112 | uint16_t m_size; 113 | uint8_t m_data[MODBUS_MAX_PDU_LENGTH]; 114 | }; 115 | } 116 | /* ========================================================================== */ 117 | -------------------------------------------------------------------------------- /include/modbuspp/swap.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #ifndef __DOXYGEN__ 20 | 21 | #include // std::swap until C++11 22 | #include // std::swap since C++11 23 | 24 | /* 25 | * reverse the order of the bytes 26 | */ 27 | template 28 | T swapBytes (T input) { // swap bytes 29 | uint8_t * ptr = reinterpret_cast (&input); 30 | 31 | for (std::size_t i = 0; i < sizeof (T) / 2; ++i) { 32 | 33 | std::swap (ptr[i], ptr[ sizeof (T) - 1 - i ]); 34 | } 35 | return input; 36 | } 37 | 38 | /* 39 | * reverse the order of the 16-bit words 40 | */ 41 | template 42 | T swapWords (T input) { // swap words 43 | uint16_t * ptr = reinterpret_cast (&input); 44 | 45 | for (std::size_t i = 0; i < sizeof (T) / 4; ++i) { 46 | 47 | std::swap (ptr[i], ptr[ (sizeof (T) / 2) - 1 - i ]); 48 | } 49 | return input; 50 | } 51 | 52 | /* 53 | * reverse the byte order of each 16-bit word. 54 | */ 55 | template 56 | T swapBytesInWords (T input) { // swap bytes in each words 57 | uint16_t * ptr = reinterpret_cast (&input); 58 | 59 | for (std::size_t i = 0; i < sizeof (T) / 2; ++i) { 60 | 61 | ptr[i] = swapBytes (ptr[i]); 62 | } 63 | return input; 64 | } 65 | 66 | /* 67 | * converts the input from host byte order to network byte order. 68 | */ 69 | template 70 | T hton (T input) { 71 | #if __BYTE_ORDER == __LITTLE_ENDIAN 72 | return swapBytes (input); 73 | #else 74 | return input; 75 | #endif 76 | } 77 | 78 | /* 79 | * converts the input from host byte network to host byte order. 80 | */ 81 | template 82 | T ntoh (T input) { 83 | #if __BYTE_ORDER == __LITTLE_ENDIAN 84 | return swapBytes (input); 85 | #else 86 | return input; 87 | #endif 88 | } 89 | #endif /* __DOXYGEN__ not defined */ 90 | /* ========================================================================== */ 91 | -------------------------------------------------------------------------------- /include/modbuspp/tcplayer.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | 21 | namespace Modbus { 22 | 23 | /** 24 | * @class TcpLayer 25 | * @brief TCP/IP v4 & v6 network layer 26 | * 27 | * This class can not and should not be instantiated by the user. 28 | * It provides access to properties and methods specific to the TCP layer. 29 | * 30 | * An instance of this class is created by the constructor @b Device::Device() 31 | * of the @b Device class (or its derived classes) if the TCP layer is selected. 32 | * 33 | * Access to this instance is done using the Device::tcp() method. 34 | * 35 | * @author Pascal JEAN, aka epsilonrt 36 | * @copyright GNU Lesser General Public License 37 | * 38 | * @sa Device::Device() 39 | * @sa Device::tcp() 40 | */ 41 | class TcpLayer : public NetLayer { 42 | 43 | public: 44 | /** 45 | * @brief Constructor 46 | */ 47 | TcpLayer (const std::string & host, const std::string & service); 48 | 49 | /** 50 | * @brief Host name or IP address 51 | * 52 | * This property specifies the host name or IP address of the host to 53 | * which we are connected, eg. "192.168.0.5" , "::1" or "server.com". 54 | */ 55 | const std::string & node() const; 56 | 57 | /** 58 | * @brief Service name or port number 59 | * 60 | * This property is the service name/port number to which we are connected. 61 | */ 62 | const std::string & service() const; 63 | 64 | /** 65 | * @overload 66 | */ 67 | virtual int sendRawMessage (const Message * msg); 68 | 69 | /** 70 | * @overload 71 | */ 72 | virtual bool prepareToSend (Message & msg); 73 | 74 | /** 75 | * @overload 76 | */ 77 | static bool checkMessage (const Message & msg); 78 | 79 | protected: 80 | class Private; 81 | TcpLayer (Private &dd); 82 | 83 | private: 84 | PIMP_DECLARE_PRIVATE (TcpLayer) 85 | }; 86 | } 87 | 88 | /* ========================================================================== */ 89 | -------------------------------------------------------------------------------- /include/modbuspp/timeout.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | 21 | namespace Modbus { 22 | 23 | /** 24 | * @class Timeout 25 | * @brief Represents a timeout 26 | * 27 | * @author Pascal JEAN, aka epsilonrt 28 | * @copyright GNU Lesser General Public License 29 | */ 30 | class Timeout { 31 | public: 32 | 33 | /** 34 | * @brief Default constructor 35 | * @param s seconds 36 | * @param us microseconds 37 | */ 38 | Timeout (uint32_t s = 1, uint32_t us = 0); 39 | 40 | /** 41 | * @brief Constructor from a double 42 | * @param t time in seconds 43 | */ 44 | Timeout (const double & t); 45 | 46 | /** 47 | * @brief Return the timeout in seconds 48 | */ 49 | double value() const; 50 | 51 | /** 52 | * @brief Set value from a double 53 | * @param t time in seconds 54 | */ 55 | void setValue (const double & t); 56 | 57 | /** 58 | * @brief Set the value from the integer part and the decimal part 59 | * @param s seconds 60 | * @param us microseconds, if this value is greater than 999999, it is 61 | * adjusted as well as @b s. 62 | */ 63 | void setValue (uint32_t s, uint32_t us); 64 | 65 | /** 66 | * @brief Overload of the assignment operator from a double value 67 | * @param t time in seconds 68 | */ 69 | Timeout& operator= (const double& t) { 70 | setValue (t); 71 | return *this; 72 | } 73 | 74 | /** 75 | * @brief Return the number of seconds 76 | */ 77 | uint32_t sec() const { 78 | return m_sec; 79 | } 80 | 81 | /** 82 | * @brief Return the number of microseconds 83 | * 84 | * in the range 0 to 999999. 85 | */ 86 | uint32_t usec() const { 87 | return m_usec; 88 | } 89 | 90 | friend class Device; 91 | 92 | private: 93 | uint32_t m_sec; 94 | uint32_t m_usec; 95 | }; 96 | } 97 | 98 | /* ========================================================================== */ 99 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file is part of the libmodbuspp Project. 2 | # 3 | # The libmodbuspp Project is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # The libmodbuspp Project is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with the libmodbuspp Project. If not, see . 15 | 16 | # libmodbuspp CMakeLists.txt 17 | cmake_minimum_required(VERSION 3.0) 18 | 19 | # set packaging dir 20 | if(NOT CPACK_PACKAGE_DIRECTORY) 21 | set(CPACK_PACKAGE_DIRECTORY ${CMAKE_BINARY_DIR}/packages) 22 | endif() 23 | 24 | 25 | file(GLOB_RECURSE src_modbuspp ${MODBUSPP_SRC_DIR}/*.cpp) 26 | set (libsrc ${src_modbuspp}) 27 | 28 | # this is the "object library" target: compiles the sources only once 29 | add_library(objlib OBJECT ${libsrc}) 30 | get_target_property(JSON_INCLUDE_DIRS nlohmann_json::nlohmann_json INTERFACE_INCLUDE_DIRECTORIES) 31 | target_include_directories(objlib BEFORE PRIVATE 32 | ${LIBMODBUS_INCLUDE_DIRS} 33 | ${MODBUSPP_INC_DIR} 34 | ${MODBUSPP_SRC_DIR} 35 | ${CMAKE_CURRENT_BINARY_DIR} 36 | ${JSON_INCLUDE_DIRS} 37 | ) 38 | 39 | # shared libraries need PIC 40 | set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1) 41 | 42 | # shared and static libraries built from the same object files 43 | add_library(modbuspp-shared SHARED $) 44 | target_link_libraries(modbuspp-shared PRIVATE nlohmann_json::nlohmann_json) 45 | set_target_properties(modbuspp-shared PROPERTIES 46 | OUTPUT_NAME modbuspp 47 | CLEAN_DIRECT_OUTPUT 1 48 | VERSION ${MODBUSPP_VERSION} 49 | SOVERSION ${MODBUSPP_VERSION_MAJOR} 50 | ) 51 | 52 | if(MODBUSPP_WITH_STATIC) 53 | add_library(modbuspp-static STATIC $) 54 | target_link_libraries(modbuspp-static PRIVATE nlohmann_json::nlohmann_json) 55 | set_target_properties(modbuspp-static PROPERTIES 56 | OUTPUT_NAME modbuspp 57 | CLEAN_DIRECT_OUTPUT 1 58 | VERSION ${MODBUSPP_VERSION} 59 | ) 60 | endif(MODBUSPP_WITH_STATIC) 61 | 62 | install (TARGETS modbuspp-shared 63 | # IMPORTANT: Add the modbuspp library to the "export-set" 64 | EXPORT modbuspp 65 | LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT lib 66 | ) 67 | 68 | if(MODBUSPP_WITH_STATIC) 69 | install (TARGETS modbuspp-static 70 | EXPORT modbuspp 71 | ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" COMPONENT dev 72 | ) 73 | endif(MODBUSPP_WITH_STATIC) 74 | -------------------------------------------------------------------------------- /modbuspp-config-version.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | # This file is part of the libmodbuspp Project. 3 | # 4 | # The libmodbuspp Library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 3 of the License, or (at your option) any later version. 8 | # 9 | # The libmodbuspp Library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public License 15 | # along with the libmodbuspp Library; if not, see . 16 | 17 | set(PACKAGE_VERSION "@MODBUSPP_VERSION@") 18 | 19 | # Check whether the requested PACKAGE_FIND_VERSION is compatible 20 | if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") 21 | set(PACKAGE_VERSION_COMPATIBLE FALSE) 22 | else() 23 | set(PACKAGE_VERSION_COMPATIBLE TRUE) 24 | if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") 25 | set(PACKAGE_VERSION_EXACT TRUE) 26 | endif() 27 | endif() 28 | -------------------------------------------------------------------------------- /modbuspp-config.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | # This file is part of the libmodbuspp Project. 3 | # 4 | # The libmodbuspp Library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 3 of the License, or (at your option) any later version. 8 | # 9 | # The libmodbuspp Library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public License 15 | # along with the libmodbuspp Library; if not, see . 16 | # - Config file for the modbuspp package 17 | # It defines the following variables 18 | # MODBUSPP_INCLUDE_DIRS - include directories for modbuspp 19 | # MODBUSPP_LIBRARY_DIRS - where to find libraries 20 | # MODBUSPP_DATA_DIR - where to find modbuspp data 21 | # MODBUSPP_LIBRARIES - libraries to link against 22 | # MODBUSPP_CFLAGS - all required cflags 23 | # MODBUSPP_LDFLAGS - all required ldflags 24 | 25 | set(CMAKE_MODULE_PATH @MODBUSPP_INSTALL_CMAKE_DIR@ ${CMAKE_MODULE_PATH}) 26 | 27 | # Compute paths 28 | get_filename_component(MODBUSPP_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 29 | 30 | set(CMAKE_THREAD_PREFER_PTHREAD TRUE) 31 | set(THREADS_PREFER_PTHREAD_FLAG TRUE) 32 | find_package(Threads REQUIRED) 33 | 34 | find_package(PkgConfig REQUIRED) 35 | pkg_check_modules (LIBMODBUS lib@LIBMODBUS_NAME@>=@LIBMODBUS_MIN_VERSION@) 36 | 37 | unset(MODBUSPP_INCLUDE_DIRS) 38 | foreach(RELATIVE_PATH @CONF_INCLUDE_DIRS@) 39 | set(ABSOLUTE_PATH) 40 | get_filename_component(ABSOLUTE_PATH "${RELATIVE_PATH}" ABSOLUTE) 41 | list(APPEND MODBUSPP_INCLUDE_DIRS "${ABSOLUTE_PATH}") 42 | endforeach() 43 | list(APPEND MODBUSPP_INCLUDE_DIRS "${LIBMODBUS_INCLUDE_DIRS}") 44 | 45 | unset(MODBUSPP_LIBRARY_DIRS) 46 | foreach(RELATIVE_PATH @CONF_LIB_DIRS@) 47 | set(ABSOLUTE_PATH) 48 | get_filename_component(ABSOLUTE_PATH "${RELATIVE_PATH}" ABSOLUTE) 49 | list(APPEND MODBUSPP_LIBRARY_DIRS "${ABSOLUTE_PATH}") 50 | list(APPEND MODBUSPP_LDFLAGS "-L${ABSOLUTE_PATH}") 51 | endforeach() 52 | list(APPEND MODBUSPP_LIBRARY_DIRS "${LIBMODBUS_LIBDIR}") 53 | 54 | set(MODBUSPP_LDFLAGS -lmodbuspp ${LIBMODBUS_LDFLAGS} -lpthread) 55 | 56 | # Our library dependencies (contains definitions for IMPORTED targets) 57 | if(NOT TARGET modbuspp-shared AND NOT TARGET modbuspp-static) 58 | include("${MODBUSPP_CMAKE_DIR}/modbuspp.cmake") 59 | endif() 60 | 61 | # These are IMPORTED targets created by modbuspp.cmake 62 | set(MODBUSPP_LIBRARIES modbuspp Threads::Threads ${LIBMODBUS_LIBRARIES}) 63 | 64 | unset(MODBUSPP_CFLAGS) 65 | foreach(item ${MODBUSPP_INCLUDE_DIRS}) 66 | list(APPEND MODBUSPP_CFLAGS "-I${item}") 67 | endforeach() 68 | 69 | set(CMAKE_MODULE_PATH "${MODBUSPP_CMAKE_DIR}") 70 | 71 | #message(STATUS "MODBUSPP_CMAKE_DIR=${MODBUSPP_CMAKE_DIR}") 72 | #message(STATUS "MODBUSPP_INCLUDE_DIRS=${MODBUSPP_INCLUDE_DIRS}") 73 | #message(STATUS "MODBUSPP_LIBRARY_DIRS=${MODBUSPP_LIBRARY_DIRS}") 74 | #message(STATUS "MODBUSPP_LIBRARIES=${MODBUSPP_LIBRARIES}") 75 | #message(STATUS "MODBUSPP_CFLAGS=${MODBUSPP_CFLAGS}") 76 | #message(STATUS "MODBUSPP_LDFLAGS=${MODBUSPP_LDFLAGS}") 77 | -------------------------------------------------------------------------------- /modbuspp.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=${prefix} 3 | bindir=@INSTALL_BIN_DIR@ 4 | libdir=@INSTALL_LIB_DIR@ 5 | includedir=@INSTALL_INCLUDE_DIR@ 6 | ldflags_other=@MODBUSPP_LDFLAGS_PKGCONFIG@ 7 | cflags_other=@MODBUSPP_CFLAGS_PKGCONFIG@ 8 | 9 | Name: lib@PROJECT_NAME@ 10 | Description: @PROJECT_DESCRIPTION@ 11 | URL: https://github.com/epsilonrt/libmodbuspp 12 | Version: @MODBUSPP_VERSION@ 13 | Requires: 14 | Libs: -L${libdir} -lmodbuspp ${ldflags_other} 15 | Cflags: -I${includedir} ${cflags_other} 16 | 17 | -------------------------------------------------------------------------------- /modbuspp.workspace: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/bufferedslave_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include "slave_p.h" 22 | 23 | namespace Modbus { 24 | 25 | class BufferedSlave::Private : public Slave::Private { 26 | 27 | public: 28 | Private (BufferedSlave * q); 29 | Private (BufferedSlave * q, int s, Device * d); 30 | virtual ~Private(); 31 | 32 | int setDiscreteInputBlock (int addr, int nmemb); 33 | int setCoilBlock (int addr, int nmemb); 34 | int setHoldingRegisterBlock (int addr, int nmemb); 35 | int setInputRegisterBlock (int addr, int nmemb); 36 | int updateDiscreteInputBlockFromSlave(); 37 | int updateCoilBlockFromSlave(); 38 | int updateHoldingRegisterBlockFromSlave(); 39 | int updateInputRegisterBlockFromSlave(); 40 | int updateSlaveCoilFromBlock(); 41 | int updateSlaveHoldingRegisterFromBlock(); 42 | 43 | modbus_mapping_t * map; 44 | std::vector idReport; 45 | Message::Callback beforeReplyCB; 46 | Message::Callback afterReplyCB; 47 | 48 | PIMP_DECLARE_PUBLIC (BufferedSlave) 49 | }; 50 | } 51 | 52 | /* ========================================================================== */ 53 | -------------------------------------------------------------------------------- /src/device_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "json_p.h" 24 | 25 | namespace Modbus { 26 | 27 | class Device::Private { 28 | 29 | public: 30 | Private (Device * q); 31 | virtual ~Private(); 32 | virtual void setBackend (Net net, const std::string & connection, 33 | const std::string & settings); 34 | virtual void setConfig (const nlohmann::json & config); 35 | 36 | void setConfigFromFile (const std::string & jsonfile, 37 | const std::string & key); 38 | 39 | virtual bool open(); 40 | virtual void close(); 41 | inline modbus_t * ctx() { 42 | return backend->context(); 43 | } 44 | inline modbus_t * ctx() const { 45 | return backend->context(); 46 | } 47 | int defaultSlave (int addr) const; 48 | bool isConnected () const; 49 | void printError (const char * what = nullptr) const; 50 | 51 | Device * const q_ptr; 52 | bool isOpen; 53 | NetLayer * backend; 54 | bool recoveryLink; 55 | bool debug; 56 | 57 | PIMP_DECLARE_PUBLIC (Device) 58 | }; 59 | } 60 | 61 | /* ========================================================================== */ 62 | -------------------------------------------------------------------------------- /src/master_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include "device_p.h" 22 | 23 | namespace Modbus { 24 | 25 | class Master::Private : public Device::Private { 26 | 27 | public: 28 | Private (Master * q); 29 | virtual ~Private(); 30 | virtual void setBackend (Net net, const std::string & connection, 31 | const std::string & settings); 32 | virtual void setConfig (const nlohmann::json & config); 33 | 34 | virtual Slave * addSlave (int slaveAddr); 35 | 36 | std::map > slave; 37 | PIMP_DECLARE_PUBLIC (Master) 38 | }; 39 | } 40 | 41 | /* ========================================================================== */ 42 | -------------------------------------------------------------------------------- /src/message_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | 21 | namespace Modbus { 22 | 23 | class Message::Private { 24 | public: 25 | Private (Message * q, NetLayer * b); 26 | Private (Message * q, NetLayer * b, const std::vector & m); 27 | Private (Message * q, NetLayer * b, Function f); 28 | Private (Message * q, Net n); 29 | Private (Message * q, Net n, const std::vector & m); 30 | Private (Message * q, Net n, Function f); 31 | virtual ~Private(); 32 | 33 | Message * const q_ptr; 34 | Net net; 35 | int pduBegin; 36 | size_t aduSize; 37 | uint16_t maxAduLength; 38 | bool isResponse; 39 | NetLayer * backend; 40 | uint16_t transactionId; 41 | std::vector adu; 42 | }; 43 | } 44 | 45 | /* ========================================================================== */ 46 | -------------------------------------------------------------------------------- /src/netlayer.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #include "netlayer_p.h" 18 | #include "config.h" 19 | 20 | namespace Modbus { 21 | 22 | // --------------------------------------------------------------------------- 23 | // 24 | // NetLayer Class 25 | // 26 | // --------------------------------------------------------------------------- 27 | 28 | // --------------------------------------------------------------------------- 29 | NetLayer::NetLayer (NetLayer::Private &dd) : d_ptr (&dd) {} 30 | 31 | // --------------------------------------------------------------------------- 32 | NetLayer::NetLayer () : 33 | d_ptr (new Private (NoNet, std::string(), std::string(), 0)) {} 34 | 35 | // --------------------------------------------------------------------------- 36 | NetLayer::~NetLayer() = default; 37 | 38 | // --------------------------------------------------------------------------- 39 | uint16_t NetLayer::maxAduLength() const { 40 | PIMP_D (const NetLayer); 41 | 42 | return d->maxAduLength; 43 | } 44 | 45 | // --------------------------------------------------------------------------- 46 | Net NetLayer::net() const { 47 | PIMP_D (const NetLayer); 48 | 49 | return d->net; 50 | } 51 | 52 | // --------------------------------------------------------------------------- 53 | modbus_t * NetLayer::context() { 54 | PIMP_D (NetLayer); 55 | 56 | return d->ctx; 57 | } 58 | 59 | // --------------------------------------------------------------------------- 60 | const modbus_t * NetLayer::context() const { 61 | PIMP_D (const NetLayer); 62 | 63 | return d->ctx; 64 | } 65 | 66 | // --------------------------------------------------------------------------- 67 | const std::string & NetLayer::connection() const { 68 | PIMP_D (const NetLayer); 69 | 70 | return d->connection; 71 | } 72 | 73 | // --------------------------------------------------------------------------- 74 | const std::string & NetLayer::settings() const { 75 | PIMP_D (const NetLayer); 76 | 77 | return d->settings; 78 | } 79 | 80 | // --------------------------------------------------------------------------- 81 | int NetLayer::sendRawMessage (const Message * msg) { 82 | 83 | errno = EINVAL; 84 | return -1; 85 | } 86 | 87 | // --------------------------------------------------------------------------- 88 | bool NetLayer::prepareToSend (Message & msg) { 89 | 90 | return false; 91 | } 92 | 93 | // --------------------------------------------------------------------------- 94 | bool NetLayer::checkMessage (const Message & msg) { 95 | 96 | return false; 97 | } 98 | 99 | // --------------------------------------------------------------------------- 100 | // static 101 | std::string NetLayer::lastError() { 102 | 103 | return modbus_strerror (errno); 104 | } 105 | } 106 | 107 | /* ========================================================================== */ 108 | -------------------------------------------------------------------------------- /src/netlayer_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | 21 | namespace Modbus { 22 | 23 | class NetLayer::Private { 24 | public: 25 | Private (Net n, const std::string & c, const std::string & s, uint16_t m) : 26 | ctx (0), net (n), connection (c), settings (s), maxAduLength (m) {} 27 | virtual ~Private() { 28 | modbus_free (ctx); 29 | } 30 | 31 | modbus_t * ctx; 32 | Net net; 33 | std::string connection; 34 | std::string settings; 35 | uint16_t maxAduLength; 36 | }; 37 | } 38 | 39 | /* ========================================================================== */ 40 | -------------------------------------------------------------------------------- /src/request_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include "message_p.h" 21 | 22 | namespace Modbus { 23 | 24 | class Request::Private : public Message::Private { 25 | public: 26 | Private (Request * q, NetLayer * b); 27 | Private (Request * q, NetLayer * b, const std::vector & m); 28 | Private (Request * q, NetLayer * b, Function f); 29 | Private (Request * q, Net n); 30 | Private (Request * q, Net n, const std::vector & m); 31 | Private (Request * q, Net n, Function f); 32 | virtual ~Private(); 33 | PIMP_DECLARE_PUBLIC (Request) 34 | }; 35 | } 36 | 37 | /* ========================================================================== */ 38 | -------------------------------------------------------------------------------- /src/response_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include "message_p.h" 21 | 22 | namespace Modbus { 23 | 24 | class Response::Private : public Message::Private { 25 | public: 26 | Private (Response * q, NetLayer * b); 27 | Private (Response * q, NetLayer * b, const std::vector & m); 28 | Private (Response * q, NetLayer * b, Function f); 29 | virtual ~Private(); 30 | PIMP_DECLARE_PUBLIC (Response) 31 | }; 32 | } 33 | 34 | /* ========================================================================== */ 35 | -------------------------------------------------------------------------------- /src/router_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include "server_p.h" 21 | 22 | namespace Modbus { 23 | 24 | class Router::Private : public Server::Private { 25 | 26 | public: 27 | Private (Router * q); 28 | virtual ~Private(); 29 | virtual void setConfig (const nlohmann::json & config); 30 | 31 | virtual bool open(); 32 | 33 | Master * addMaster (const std::string & name); 34 | 35 | std::map > master; 36 | PIMP_DECLARE_PUBLIC (Router) 37 | }; 38 | } 39 | 40 | /* ========================================================================== */ 41 | -------------------------------------------------------------------------------- /src/rtulayer_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include "netlayer_p.h" 21 | 22 | namespace Modbus { 23 | 24 | class RtuLayer::Private : public NetLayer::Private { 25 | 26 | public: 27 | Private (const std::string & port, const std::string & settings); 28 | int oneByteTime; 29 | }; 30 | } 31 | 32 | /* ========================================================================== */ 33 | -------------------------------------------------------------------------------- /src/server_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "device_p.h" 24 | 25 | namespace Modbus { 26 | 27 | class Server::Private : public Device::Private { 28 | 29 | public: 30 | Private (Server * q); 31 | virtual ~Private(); 32 | virtual void setBackend (Net net, const std::string & connection, 33 | const std::string & settings); 34 | virtual void setConfig (const nlohmann::json & config); 35 | 36 | virtual bool open(); 37 | virtual void close(); 38 | int task (int rc); 39 | 40 | BufferedSlave * addSlave (int slaveAddr, Device * master); 41 | 42 | static void loop (std::future run, Private * d); 43 | static int receive (Private * d); 44 | 45 | int sock; 46 | std::shared_ptr req; 47 | std::map > slave; 48 | std::future receiveTask; 49 | std::thread daemon; 50 | std::promise stopDaemon; 51 | Message::Callback messageCB; 52 | 53 | PIMP_DECLARE_PUBLIC (Server) 54 | }; 55 | } 56 | 57 | /* ========================================================================== */ 58 | -------------------------------------------------------------------------------- /src/slave_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include "json_p.h" 23 | 24 | namespace Modbus { 25 | 26 | class Slave::Private { 27 | 28 | public: 29 | Private (Slave * q); 30 | Private (Slave * q, int s, Device * d); 31 | virtual ~Private(); 32 | 33 | inline modbus_t * ctx() { 34 | return dev->backend().context(); 35 | } 36 | inline const modbus_t * ctx() const { 37 | return dev->backend().context(); 38 | } 39 | 40 | Slave * const q_ptr; 41 | bool pduAddressing; 42 | int id; 43 | Device * dev; 44 | PIMP_DECLARE_PUBLIC (Slave) 45 | }; 46 | } 47 | 48 | /* ========================================================================== */ 49 | -------------------------------------------------------------------------------- /src/tcplayer.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #ifdef _WIN32 18 | # include 19 | #else 20 | # include 21 | #endif 22 | 23 | #include 24 | #include "tcplayer_p.h" 25 | #include "config.h" 26 | 27 | #if !defined(MSG_NOSIGNAL) 28 | #define MSG_NOSIGNAL 0 29 | #endif 30 | 31 | namespace Modbus { 32 | 33 | // --------------------------------------------------------------------------- 34 | // 35 | // TcpLayer Class 36 | // 37 | // --------------------------------------------------------------------------- 38 | 39 | // --------------------------------------------------------------------------- 40 | TcpLayer::TcpLayer (TcpLayer::Private &dd) : NetLayer (dd) {} 41 | 42 | // --------------------------------------------------------------------------- 43 | TcpLayer::TcpLayer (const std::string & host, const std::string & service) : 44 | NetLayer (*new Private (host, service)) {} 45 | 46 | // --------------------------------------------------------------------------- 47 | const std::string & TcpLayer::node() const { 48 | 49 | return connection(); 50 | } 51 | 52 | // --------------------------------------------------------------------------- 53 | const std::string & TcpLayer::service() const { 54 | 55 | return settings(); 56 | } 57 | 58 | // --------------------------------------------------------------------------- 59 | int TcpLayer::sendRawMessage (const Message * msg) { 60 | PIMP_D (TcpLayer); 61 | 62 | return send (modbus_get_socket (d->ctx), msg->adu(), msg->aduSize(), 63 | MSG_NOSIGNAL); 64 | } 65 | 66 | // --------------------------------------------------------------------------- 67 | bool TcpLayer::prepareToSend (Message & msg) { 68 | 69 | if (msg.net() == Tcp && msg.size() >= 1) { 70 | PIMP_D (TcpLayer); 71 | 72 | uint8_t * adu = msg.adu(); 73 | uint16_t s = msg.size() + 1; 74 | 75 | if (!msg.isResponse()) { 76 | adu[0] = d->transactionId >> 8; 77 | adu[1] = d->transactionId++ & 0xFF; 78 | adu[2] = 0; 79 | adu[3] = 0; 80 | } 81 | adu[4] = s >> 8; 82 | adu[5] = s & 0xFF; 83 | return true; 84 | } 85 | return false; 86 | } 87 | 88 | // --------------------------------------------------------------------------- 89 | bool TcpLayer::checkMessage (const Message & msg) { 90 | 91 | return (msg.net() == Tcp) && (msg.size() >= 1); 92 | } 93 | 94 | // --------------------------------------------------------------------------- 95 | // 96 | // TcpLayer::Private Class 97 | // 98 | // --------------------------------------------------------------------------- 99 | 100 | // --------------------------------------------------------------------------- 101 | TcpLayer::Private::Private (const std::string & host, const std::string & service) : 102 | NetLayer::Private (Tcp, host, service, MODBUS_TCP_MAX_ADU_LENGTH), 103 | transactionId (1) { 104 | const char * node = NULL; 105 | 106 | if (host != "*") { 107 | node = host.c_str(); 108 | } 109 | 110 | ctx = modbus_new_tcp_pi (node, service.c_str()); 111 | if (! ctx) { 112 | 113 | throw std::invalid_argument ( 114 | "Unable to create TCP Modbus Backend(" + 115 | host + ":" + service + ")\n" + lastError()); 116 | } 117 | } 118 | 119 | } 120 | 121 | /* ========================================================================== */ 122 | -------------------------------------------------------------------------------- /src/tcplayer_p.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | #include 20 | #include "netlayer_p.h" 21 | 22 | namespace Modbus { 23 | 24 | class TcpLayer::Private : public NetLayer::Private { 25 | 26 | public: 27 | Private (const std::string & host, const std::string & service); 28 | uint16_t transactionId; 29 | }; 30 | } 31 | 32 | /* ========================================================================== */ 33 | -------------------------------------------------------------------------------- /src/timeout.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #include 18 | #include "config.h" 19 | 20 | namespace Modbus { 21 | 22 | // --------------------------------------------------------------------------- 23 | // 24 | // Timeout Class 25 | // 26 | // --------------------------------------------------------------------------- 27 | 28 | // --------------------------------------------------------------------------- 29 | Timeout::Timeout (uint32_t s, uint32_t us) { 30 | 31 | setValue (s, us); 32 | } 33 | 34 | // --------------------------------------------------------------------------- 35 | Timeout::Timeout (const double & t) { 36 | 37 | setValue (t); 38 | } 39 | 40 | // --------------------------------------------------------------------------- 41 | void Timeout::setValue (const double & t) { 42 | 43 | m_sec = static_cast (t); 44 | m_usec = (t - m_sec) * 1000000UL; 45 | } 46 | 47 | // --------------------------------------------------------------------------- 48 | void Timeout::setValue (uint32_t s, uint32_t us) { 49 | 50 | if (us > 999999) { 51 | uint32_t ts = us / 1000000UL; 52 | s += ts; 53 | us -= ts * 1000000UL; 54 | } 55 | m_sec = s; 56 | m_usec = us; 57 | } 58 | 59 | // --------------------------------------------------------------------------- 60 | double Timeout::value() const { 61 | return static_cast (m_sec) + static_cast (m_usec) / 1000000UL; 62 | } 63 | } 64 | 65 | /* ========================================================================== */ 66 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | # This file is part of the libmodbuspp Project. 3 | # 4 | # The libmodbuspp Project is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # The libmodbuspp Project is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with the libmodbuspp Project. If not, see . 16 | 17 | # modbuspp tests CMakeLists.txt 18 | cmake_minimum_required(VERSION 3.0) 19 | 20 | include(SubDirList) 21 | SUBDIRLIST(TESTS ${CMAKE_CURRENT_SOURCE_DIR}) 22 | 23 | find_package(modbuspp CONFIG) 24 | 25 | add_custom_target(build_and_test ${CMAKE_CTEST_COMMAND} -V) 26 | link_directories(${MODBUSPP_LIBRARY_DIRS}) 27 | 28 | foreach(test ${TESTS}) 29 | message (STATUS " add test ${test}") 30 | # create an executable, which instantiates a runner from UnitTest++ 31 | add_executable(${test} ${test}/main.cpp) 32 | add_dependencies(${test} modbuspp-shared) 33 | 34 | # depending on the framework, you need to link to it 35 | target_link_libraries(${test} ${MODBUSPP_LIBRARIES} ${UNITTESTPP_LIBRARIES}) 36 | target_compile_options(${test} PUBLIC ${MODBUSPP_CFLAGS} ${UNITTESTPP_CFLAGS}) 37 | 38 | # now register the executable with CTest 39 | add_test(NAME ${test} COMMAND ${test}) 40 | endforeach() 41 | 42 | add_dependencies(build_and_test modbuspp-shared) 43 | -------------------------------------------------------------------------------- /tests/unit-test-device/main.cpp: -------------------------------------------------------------------------------- 1 | // libmodbuspp Unit Test template 2 | // Use UnitTest++ framework -> https://github.com/unittest-cpp/unittest-cpp/wiki 3 | // This test code is in the public domain. 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | using namespace Modbus; 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | // 13 | // To add a test, simply put the following code in the a .cpp file of your choice: 14 | // 15 | // ================================= 16 | // Simple Test 17 | // ================================= 18 | // 19 | // TEST(YourTestName) 20 | // { 21 | // } 22 | // 23 | // The TEST macro contains enough machinery to turn this slightly odd-looking 24 | // syntax into legal C++, and automatically register the test in a global list. 25 | // This test list forms the basis of what is executed by RunAllTests(). 26 | // e.g. 27 | TEST (RtuMasterTest) { 28 | string connection ("/dev/ttyUSB0"); 29 | string settings ("38400E1"); 30 | Net net = Rtu; 31 | int slvAddr = 33; 32 | 33 | Master mb; // instantiate new MODBUS Master 34 | CHECK (!mb.isValid()); 35 | 36 | // set master on RTU 37 | CHECK (mb.setBackend (net, connection, settings)); 38 | CHECK (mb.isValid()); 39 | CHECK (mb.net() == net); 40 | CHECK (mb.connection() == connection); 41 | CHECK (mb.settings() == settings) ; 42 | 43 | Slave & slv = mb.addSlave (slvAddr); 44 | CHECK (mb.hasSlave (slvAddr)); 45 | 46 | REQUIRE CHECK (mb.open ()); 47 | uint16_t value; 48 | CHECK (slv.readInputRegisters (1, &value) == 1); 49 | 50 | cout << "R0=" << value << endl; 51 | mb.close(); 52 | CHECK (!mb.isOpen()); 53 | } 54 | 55 | // 56 | // If you want to re-use a set of test data for more than one test, or provide 57 | // setup/teardown for tests, you can use the TEST_FIXTURE macro instead. 58 | // The macro requires that you pass it a class name that it will instantiate, 59 | // so any setup and teardown code should be in its constructor and destructor. 60 | // 61 | // struct SomeFixture 62 | // { 63 | // SomeFixture() { /* some setup */ } 64 | // ~SomeFixture() { /* some teardown */ } 65 | // 66 | // int testData; 67 | // }; 68 | // 69 | // TEST_FIXTURE(SomeFixture, YourTestName) 70 | // { 71 | // int temp = testData; 72 | // } 73 | // 74 | // ================================= 75 | // Test Suites 76 | // ================================= 77 | // 78 | // Tests can be grouped into suites, using the SUITE macro. A suite serves as a 79 | // namespace for test names, so that the same test name can be used in two 80 | // difference contexts. 81 | // 82 | // SUITE(YourSuiteName) 83 | // { 84 | // TEST(YourTestName) 85 | // { 86 | // } 87 | // 88 | // TEST(YourOtherTestName) 89 | // { 90 | // } 91 | // } 92 | // 93 | // This will place the tests into a C++ namespace called YourSuiteName, and make 94 | // the suite name available to UnitTest++. 95 | // RunAllTests() can be called for a specific suite name, so you can use this to 96 | // build named groups of tests to be run together. 97 | // Note how members of the fixture are used as if they are a part of the test, 98 | // since the macro-generated test class derives from the provided fixture class. 99 | // 100 | // 101 | //////////////////////////////////////////////////////////////////////////////// 102 | 103 | // run all tests 104 | int main (int argc, char **argv) { 105 | return UnitTest::RunAllTests(); 106 | } 107 | 108 | /* ========================================================================== */ 109 | -------------------------------------------------------------------------------- /tests/unit-test-device/unit-test-device.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | None 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | /usr/include/modbuspp 52 | /usr/local/include/modbuspp 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | None 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | /usr/include/modbuspp 93 | /usr/local/include/modbuspp 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /tests/unit-test-server/main.cpp: -------------------------------------------------------------------------------- 1 | // libmodbuspp Unit Test template 2 | // Use UnitTest++ framework -> https://github.com/unittest-cpp/unittest-cpp/wiki 3 | // This test code is in the public domain. 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | using namespace Modbus; 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | // 13 | // To add a test, simply put the following code in the a .cpp file of your choice: 14 | // 15 | // ================================= 16 | // Simple Test 17 | // ================================= 18 | // 19 | // TEST(YourTestName) 20 | // { 21 | // } 22 | // 23 | // The TEST macro contains enough machinery to turn this slightly odd-looking 24 | // syntax into legal C++, and automatically register the test in a global list. 25 | // This test list forms the basis of what is executed by RunAllTests(). 26 | // e.g. 27 | TEST (RtuMasterTest) { 28 | string connection ("/dev/ttyUSB0"); 29 | string settings ("38400E1"); 30 | Net net = Rtu; 31 | int slvAddr = 33; 32 | 33 | Master mb; // instantiate new MODBUS Master 34 | CHECK (!mb.isValid()); 35 | 36 | // set master on RTU 37 | CHECK (mb.setBackend (net, connection, settings)); 38 | CHECK (mb.isValid()); 39 | CHECK (mb.net() == net); 40 | CHECK (mb.connection() == connection); 41 | CHECK (mb.settings() == settings) ; 42 | 43 | Slave & slv = mb.addSlave (slvAddr); 44 | CHECK (mb.hasSlave (slvAddr)); 45 | 46 | REQUIRE CHECK (mb.open ()); 47 | uint16_t value; 48 | CHECK (slv.readInputRegisters (1, &value) == 1); 49 | 50 | cout << "R0=" << value << endl; 51 | mb.close(); 52 | CHECK (!mb.isOpen()); 53 | } 54 | 55 | // 56 | // If you want to re-use a set of test data for more than one test, or provide 57 | // setup/teardown for tests, you can use the TEST_FIXTURE macro instead. 58 | // The macro requires that you pass it a class name that it will instantiate, 59 | // so any setup and teardown code should be in its constructor and destructor. 60 | // 61 | // struct SomeFixture 62 | // { 63 | // SomeFixture() { /* some setup */ } 64 | // ~SomeFixture() { /* some teardown */ } 65 | // 66 | // int testData; 67 | // }; 68 | // 69 | // TEST_FIXTURE(SomeFixture, YourTestName) 70 | // { 71 | // int temp = testData; 72 | // } 73 | // 74 | // ================================= 75 | // Test Suites 76 | // ================================= 77 | // 78 | // Tests can be grouped into suites, using the SUITE macro. A suite serves as a 79 | // namespace for test names, so that the same test name can be used in two 80 | // difference contexts. 81 | // 82 | // SUITE(YourSuiteName) 83 | // { 84 | // TEST(YourTestName) 85 | // { 86 | // } 87 | // 88 | // TEST(YourOtherTestName) 89 | // { 90 | // } 91 | // } 92 | // 93 | // This will place the tests into a C++ namespace called YourSuiteName, and make 94 | // the suite name available to UnitTest++. 95 | // RunAllTests() can be called for a specific suite name, so you can use this to 96 | // build named groups of tests to be run together. 97 | // Note how members of the fixture are used as if they are a part of the test, 98 | // since the macro-generated test class derives from the provided fixture class. 99 | // 100 | // 101 | //////////////////////////////////////////////////////////////////////////////// 102 | 103 | // run all tests 104 | int main (int argc, char **argv) { 105 | return UnitTest::RunAllTests(); 106 | } 107 | 108 | /* ========================================================================== */ 109 | -------------------------------------------------------------------------------- /version.h.in: -------------------------------------------------------------------------------- 1 | /* Copyright © 2018-2019 Pascal JEAN, All rights reserved. 2 | * This file is part of the libmodbuspp Library. 3 | * 4 | * The libmodbuspp Library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * The libmodbuspp Library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with the libmodbuspp Library; if not, see . 16 | */ 17 | #pragma once 18 | 19 | /** @brief The full version as string, like 1.0-3-g166e25d */ 20 | #define MODBUSPP_VERSION "@MODBUSPP_VERSION_STRING@" 21 | /** @brief The short version as string, like 1.0-3 */ 22 | #define MODBUSPP_VERSION_SHORT "@MODBUSPP_VERSION_SHORT@" 23 | /** @brief The tiny version as string, like 1.0 */ 24 | #define MODBUSPP_VERSION_TINY "@MODBUSPP_VERSION_TINY@" 25 | /** @brief The major version, (1, if %MODBUSPP_VERSION_SHORT is 1.0-3) */ 26 | #define MODBUSPP_VERSION_MAJOR @MODBUSPP_VERSION_MAJOR@ 27 | /** @brief The minor version (0, if %MODBUSPP_VERSION_SHORT is 1.0-3) */ 28 | #define MODBUSPP_VERSION_MINOR @MODBUSPP_VERSION_MINOR@ 29 | /** @brief The patch version (3, if %MODBUSPP_VERSION_SHORT is 1.0-3) */ 30 | #define MODBUSPP_VERSION_PATCH @MODBUSPP_VERSION_PATCH@ 31 | /** @brief SHA1 HASH of the git version */ 32 | #define MODBUSPP_VERSION_SHA1 @MODBUSPP_VERSION_SHA1@ 33 | 34 | /** @brief Numerically encoded version, like 0x010003 */ 35 | #define MODBUSPP_VERSION_HEX ((MODBUSPP_VERSION_MAJOR << 24) | \ 36 | (MODBUSPP_VERSION_MINOR << 16) | \ 37 | (MODBUSPP_VERSION_PATCH << 8)) 38 | 39 | /** 40 | * @brief Check modbuspp version 41 | * Evaluates to True if the version is greater than @major, @minor and @patch 42 | */ 43 | #define MODBUSPP_VERSION_CHECK(major,minor,patch) \ 44 | (MODBUSPP_VERSION_MAJOR > (major) || \ 45 | (MODBUSPP_VERSION_MAJOR == (major) && \ 46 | MODBUSPP_VERSION_MINOR > (minor)) || \ 47 | (MODBUSPP_VERSION_MAJOR == (major) && \ 48 | MODBUSPP_VERSION_MINOR == (minor) && \ 49 | MODBUSPP_VERSION_PATCH >= (patch))) 50 | 51 | /* ========================================================================== */ 52 | --------------------------------------------------------------------------------