diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml new file mode 100644 index 0000000..fd8dcf6 --- /dev/null +++ b/.github/workflows/cmake-multi-platform.yml @@ -0,0 +1,77 @@ +name: CMake on multiple platforms + +on: + push: + branches: ["master"] + pull_request: + branches: ["master"] + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. + fail-fast: false + + # Currently supported: + # - Linux + GCC + # - Linux + CLANG + # Planned: + # - Windows + CL + matrix: + os: [ubuntu-latest, windows-latest] + build_type: [Release] + c_compiler: [gcc, clang, cl] + include: + - os: ubuntu-latest + c_compiler: gcc + cpp_compiler: g++ + - os: ubuntu-latest + c_compiler: clang + cpp_compiler: clang++ + exclude: + - os: windows-latest + c_compiler: cl + - os: windows-latest + c_compiler: gcc + - os: windows-latest + c_compiler: clang + - os: ubuntu-latest + c_compiler: cl + + steps: + - uses: actions/checkout@v4 + with: + submodules: "recursive" + fetch-depth: 1 + + # Dependecies needed only for Linux - Modbus Communication + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libnet1-dev + if: matrix.os == 'ubuntu-latest' + + - name: Set reusable strings + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + + - name: Configure CMake + run: > + cmake -B ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -DMODBUS_EXAMPLE=ON + -DMODBUS_TESTS=ON + -DMODBUS_COMMUNICATION=${{ matrix.os == 'windows-latest' && 'OFF' || matrix.os == 'ubuntu-latest' && 'ON' }} + -S ${{ github.workspace }} + + - name: Build + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + + - name: Test + run: ${{ steps.strings.outputs.build-output-dir }}/tests/Google_Tests_run diff --git a/CMakeLists.txt b/CMakeLists.txt index b1e3cf5..dda75b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,11 @@ project(protocolConverter) set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -pedantic") +if (MSVC) + add_compile_options(/W3) +else() + add_compile_options(-Wall -Wextra -Werror -pedantic) +endif() option(MODBUS_EXAMPLE "Build example program" OFF) option(MODBUS_TESTS "Build tests" OFF) diff --git a/include/MB/modbusRequest.hpp b/include/MB/modbusRequest.hpp index e31f04c..0e9c0b8 100644 --- a/include/MB/modbusRequest.hpp +++ b/include/MB/modbusRequest.hpp @@ -71,7 +71,7 @@ class ModbusRequest { } /** - * Simple constructor, that allows to create "dummy" ModbusResponse + * Simple constructor, that allows to create "dummy" ModbusRequest * object. May be useful in some cases. */ explicit ModbusRequest( @@ -80,7 +80,15 @@ class ModbusRequest { uint16_t address = 0, uint16_t registersNumber = 0, std::vector values = {}) noexcept; - ModbusRequest(const ModbusRequest &) = default; + /** + * Copy constructor for the response. + */ + ModbusRequest(const ModbusRequest&); + + /** + * Equal operator for the response. + */ + ModbusRequest& operator=(const ModbusRequest &); //! Returns string representation of object [[nodiscard]] std::string toString() const noexcept; diff --git a/include/MB/modbusResponse.hpp b/include/MB/modbusResponse.hpp index ccc9c91..b1e9078 100644 --- a/include/MB/modbusResponse.hpp +++ b/include/MB/modbusResponse.hpp @@ -80,7 +80,15 @@ class ModbusResponse { uint16_t address = 0, uint16_t registersNumber = 0, std::vector values = {}); - ModbusResponse(const ModbusResponse &) = default; + /** + * Copy constructor for the response. + */ + ModbusResponse(const ModbusResponse&); + + /** + * Equal operator for the response. + */ + ModbusResponse& operator=(const ModbusResponse &); //! Converts object to it's string representation [[nodiscard]] std::string toString() const; diff --git a/include/MB/modbusUtils.hpp b/include/MB/modbusUtils.hpp index ddb80db..a6c6da6 100644 --- a/include/MB/modbusUtils.hpp +++ b/include/MB/modbusUtils.hpp @@ -233,4 +233,8 @@ inline void pushUint16(std::vector &buffer, const uint16_t val) { buffer.push_back(low); } +//! Ignore some value explicitly +template +inline void ignore_result(T&& v) { (void)v; } + } // namespace MB::utils diff --git a/src/Serial/connection.cpp b/src/Serial/connection.cpp index aea9157..f922860 100644 --- a/src/Serial/connection.cpp +++ b/src/Serial/connection.cpp @@ -3,6 +3,7 @@ // Licensed under: MIT License #include "Serial/connection.hpp" +#include "modbusUtils.hpp" #include using namespace MB::Serial; @@ -139,7 +140,7 @@ std::vector Connection::send(std::vector data) { // most cases) tcflush(_fd, TCOFLUSH); // Write - write(_fd, data.begin().base(), data.size()); + utils::ignore_result(write(_fd, data.begin().base(), data.size())); // It may be a good idea to use tcdrain, although it has tendency to not // work as expected tcdrain(_fd); diff --git a/src/TCP/connection.cpp b/src/TCP/connection.cpp index f40d6d1..68b924d 100644 --- a/src/TCP/connection.cpp +++ b/src/TCP/connection.cpp @@ -3,6 +3,7 @@ // Licensed under: MIT License #include "TCP/connection.hpp" +#include #include #include @@ -25,16 +26,16 @@ std::vector Connection::sendRequest(const MB::ModbusRequest &req) { std::vector rawReq; rawReq.reserve(6); - rawReq.push_back(reinterpret_cast(&_messageID)[1]); - rawReq.push_back(reinterpret_cast(&_messageID)[0]); + rawReq.push_back(static_cast(reinterpret_cast(&_messageID)[1])); + rawReq.push_back(static_cast(_messageID)); rawReq.push_back(0x00); rawReq.push_back(0x00); std::vector dat = req.toRaw(); uint32_t size = dat.size(); - rawReq.push_back(reinterpret_cast(&size)[1]); - rawReq.push_back(reinterpret_cast(&size)[0]); + rawReq.push_back(static_cast(reinterpret_cast(&size)[1])); + rawReq.push_back(static_cast(size)); rawReq.insert(rawReq.end(), dat.begin(), dat.end()); @@ -47,16 +48,16 @@ std::vector Connection::sendResponse(const MB::ModbusResponse &res) { std::vector rawReq; rawReq.reserve(6); - rawReq.push_back(reinterpret_cast(&_messageID)[1]); - rawReq.push_back(reinterpret_cast(&_messageID)[0]); + rawReq.push_back(static_cast(reinterpret_cast(&_messageID)[1])); + rawReq.push_back(static_cast(_messageID)); rawReq.push_back(0x00); rawReq.push_back(0x00); std::vector dat = res.toRaw(); uint32_t size = dat.size(); - rawReq.push_back(reinterpret_cast(&size)[1]); - rawReq.push_back(reinterpret_cast(&size)[0]); + rawReq.push_back(static_cast(reinterpret_cast(&size)[1])); + rawReq.push_back(static_cast(size)); rawReq.insert(rawReq.end(), dat.begin(), dat.end()); @@ -69,16 +70,16 @@ std::vector Connection::sendException(const MB::ModbusException &ex) { std::vector rawReq; rawReq.reserve(6); - rawReq.push_back(reinterpret_cast(&_messageID)[1]); - rawReq.push_back(reinterpret_cast(&_messageID)[0]); + rawReq.push_back(static_cast(reinterpret_cast(&_messageID)[1])); + rawReq.push_back(static_cast(_messageID)); rawReq.push_back(0x00); rawReq.push_back(0x00); std::vector dat = ex.toRaw(); uint32_t size = dat.size(); - rawReq.push_back(reinterpret_cast(&size)[1]); - rawReq.push_back(reinterpret_cast(&size)[0]); + rawReq.push_back(static_cast(reinterpret_cast(&size)[1])); + rawReq.push_back(static_cast(size)); rawReq.insert(rawReq.end(), dat.begin(), dat.end()); diff --git a/src/modbusRequest.cpp b/src/modbusRequest.cpp index c66d240..2944341 100644 --- a/src/modbusRequest.cpp +++ b/src/modbusRequest.cpp @@ -30,6 +30,23 @@ ModbusRequest::ModbusRequest(uint8_t slaveId, utils::MBFunctionCode functionCode } } +ModbusRequest::ModbusRequest(const ModbusRequest& reference) : + _slaveID(reference.slaveID()), + _functionCode(reference.functionCode()), + _address(reference.registerAddress()), + _registersNumber(reference.numberOfRegisters()), + _values(reference.registerValues()){ } + + +ModbusRequest& ModbusRequest::operator=(const ModbusRequest &reference) { + this->_slaveID = reference.slaveID(); + this->_functionCode = reference.functionCode(); + this->_address = reference.registerAddress(); + this->_registersNumber = reference.numberOfRegisters(); + this->_values = reference.registerValues(); + return *this; +} + ModbusRequest::ModbusRequest(const std::vector &inputData, bool CRC) { try { if (inputData.size() < 3) diff --git a/src/modbusResponse.cpp b/src/modbusResponse.cpp index cfd7fa6..905bb3c 100644 --- a/src/modbusResponse.cpp +++ b/src/modbusResponse.cpp @@ -30,6 +30,23 @@ ModbusResponse::ModbusResponse(uint8_t slaveId, utils::MBFunctionCode functionCo } } +ModbusResponse::ModbusResponse(const ModbusResponse& reference) : + _slaveID(reference.slaveID()), + _functionCode(reference.functionCode()), + _address(reference.registerAddress()), + _registersNumber(reference.numberOfRegisters()), + _values(reference.registerValues()){ } + + +ModbusResponse& ModbusResponse::operator=(const ModbusResponse &reference) { + this->_slaveID = reference.slaveID(); + this->_functionCode = reference.functionCode(); + this->_address = reference.registerAddress(); + this->_registersNumber = reference.numberOfRegisters(); + this->_values = reference.registerValues(); + return *this; +} + ModbusResponse::ModbusResponse(std::vector inputData, bool CRC) { try { if (inputData.size() < 3)