Skip to content

Commit 3ccdb3e

Browse files
MazurelMightyPiggie
andcommitted
Support for Windows compilation
Thanks for contributions from: - RalfOGit <https://github.com/RalfOGit> - MightyPiggie <https://github.com/MightyPiggie> PR: #5 Co-authored-by: RalfOGit Co-authored-by: MightyPiggie <[email protected]> Signed-off-by: Mateusz Mazur <[email protected]>
1 parent bc6f5fe commit 3ccdb3e

16 files changed

+142
-96
lines changed

.github/workflows/cmake-multi-platform.yml

+5-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ jobs:
3030
- os: ubuntu-latest
3131
c_compiler: clang
3232
cpp_compiler: clang++
33-
exclude:
3433
- os: windows-latest
3534
c_compiler: cl
35+
cpp_compiler: cl
36+
exclude:
3637
- os: windows-latest
3738
c_compiler: gcc
3839
- os: windows-latest
@@ -67,11 +68,12 @@ jobs:
6768
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
6869
-DMODBUS_EXAMPLE=ON
6970
-DMODBUS_TESTS=ON
70-
-DMODBUS_COMMUNICATION=${{ matrix.os == 'windows-latest' && 'OFF' || matrix.os == 'ubuntu-latest' && 'ON' }}
71+
-DMODBUS_TCP_COMMUNICATION=${{ matrix.os == 'windows-latest' && 'OFF' || matrix.os == 'ubuntu-latest' && 'ON' }}
72+
-DMODBUS_SERIAL_COMMUNICATION=${{ matrix.os == 'windows-latest' && 'OFF' || matrix.os == 'ubuntu-latest' && 'ON' }}
7173
-S ${{ github.workspace }}
7274
7375
- name: Build
7476
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
7577

7678
- name: Test
77-
run: ${{ steps.strings.outputs.build-output-dir }}/tests/Google_Tests_run
79+
run: ${{ steps.strings.outputs.build-output-dir }}/${{ matrix.os == 'windows-latest' && 'tests\Release\Google_Tests_run.exe' || matrix.os == 'ubuntu-latest' && '/tests/Google_Tests_run' }}

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@
3030
*.exe
3131
*.out
3232
*.app
33-
3433
build
3534

35+
# Windows specific
36+
out
37+
.vs
38+
3639
# Gtags
3740
GTAGS
3841
GRTAGS

CMakeLists.txt

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
11
cmake_minimum_required(VERSION 3.13)
2-
project(protocolConverter)
2+
project(modbus)
33

44
set(CMAKE_CXX_STANDARD 17)
55

66
if (MSVC)
7-
add_compile_options(/W3)
7+
add_compile_options(/W3 /MT)
8+
# Otherwise, MSVC complains about strncopy
9+
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
810
else()
911
add_compile_options(-Wall -Wextra -Werror -pedantic)
1012
endif()
1113

1214
option(MODBUS_EXAMPLE "Build example program" OFF)
1315
option(MODBUS_TESTS "Build tests" OFF)
14-
option(MODBUS_COMMUNICATION "Use Modbus communication library" ON)
16+
option(MODBUS_TCP_COMMUNICATION "Use Modbus TCP communication library" ON)
17+
18+
if(NOT win32)
19+
# Serial not supported on Windows
20+
option(MODBUS_SERIAL_COMMUNICATION "Use Modbus serial communication library" OFF) # not supported by windows platform
21+
else()
22+
message(STATUS "Modbus Serial not supported on Windows.")
23+
endif()
1524

1625
add_subdirectory(src)
1726

@@ -21,5 +30,5 @@ endif()
2130

2231
if(MODBUS_EXAMPLE)
2332
add_executable(ex example/main.cpp)
24-
target_link_libraries(ex Modbus)
33+
target_link_libraries(ex PUBLIC Modbus_Core)
2534
endif()

include/MB/crc.hpp

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
#include <cstdint>
2+
#include <optional>
23
#include <vector>
34

45
//! This namespace contains functions used for CRC calculation
56
namespace MB::CRC {
6-
//! Calculates CRC based on the input buffer - C style
7-
uint16_t calculateCRC(const uint8_t *buff, std::size_t len);
7+
//! Calculates CRC based on the input buffer - C style
8+
uint16_t calculateCRC(const uint8_t *buff, std::size_t len);
89

9-
//! Calculate CRC based on the input vector of bytes
10-
inline uint16_t calculateCRC(const std::vector<uint8_t> &buffer) {
11-
return calculateCRC(buffer.begin().base(), buffer.size());
10+
//! Calculate CRC based on the input vector of bytes
11+
inline uint16_t calculateCRC(const std::vector<uint8_t> &buffer, std::optional<std::size_t> len = std::nullopt) {
12+
std::size_t bufferLength = buffer.size();
13+
if (len.has_value() && bufferLength >= *len) {
14+
bufferLength = *len;
1215
}
13-
};
16+
17+
return calculateCRC(static_cast<const uint8_t *>(&(*buffer.begin())), bufferLength);
18+
}
19+
}; // namespace MB::CRC

include/MB/modbusCell.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#pragma once
66

77
#include <cstdint>
8-
#include <stdexcept>
8+
#include <string>
99
#include <variant>
1010

1111
/**

include/MB/modbusException.hpp

+8-5
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
#pragma once
66

7+
#include <algorithm>
8+
#include <cstddef>
79
#include <cstdint>
810
#include <cstring>
9-
#include <stdexcept>
1011
#include <vector>
1112

1213
#include "modbusUtils.hpp"
@@ -81,12 +82,14 @@ class ModbusException : public std::exception {
8182

8283
/**
8384
* This function is less optimal, it is just to be compatible with
84-
* std::excepetion You should preferably use toString()
85+
* `std::exception`, you should preferably use toString()
8586
*/
8687
[[nodiscard]] const char *what() const noexcept override {
87-
auto og = toString();
88-
char *str = new char[og.size()];
89-
stpcpy(str, og.c_str());
88+
const std::size_t MAX_STRING_SIZE = 1024;
89+
static char str[MAX_STRING_SIZE];
90+
auto originalStr = toString();
91+
std::strncpy(str, originalStr.c_str(),
92+
std::min(originalStr.size(), MAX_STRING_SIZE));
9093
return str;
9194
}
9295

include/MB/modbusRequest.hpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@ class ModbusRequest {
8181
std::vector<ModbusCell> values = {}) noexcept;
8282

8383
/**
84-
* Copy constructor for the response.
85-
*/
86-
ModbusRequest(const ModbusRequest&);
84+
* Copy constructor for the response.
85+
*/
86+
ModbusRequest(const ModbusRequest &);
8787

8888
/**
89-
* Equal operator for the response.
90-
*/
91-
ModbusRequest& operator=(const ModbusRequest &);
89+
* Equal operator for the response.
90+
*/
91+
ModbusRequest &operator=(const ModbusRequest &);
9292

9393
//! Returns string representation of object
9494
[[nodiscard]] std::string toString() const noexcept;

include/MB/modbusResponse.hpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,12 @@ class ModbusResponse {
8383
/**
8484
* Copy constructor for the response.
8585
*/
86-
ModbusResponse(const ModbusResponse&);
86+
ModbusResponse(const ModbusResponse &);
8787

8888
/**
89-
* Equal operator for the response.
90-
*/
91-
ModbusResponse& operator=(const ModbusResponse &);
89+
* Equal operator for the response.
90+
*/
91+
ModbusResponse &operator=(const ModbusResponse &);
9292

9393
//! Converts object to it's string representation
9494
[[nodiscard]] std::string toString() const;

include/MB/modbusUtils.hpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,7 @@ inline std::string mbFunctionToStr(MBFunctionCode code) noexcept {
204204

205205
//! Create uint16_t from buffer of two bytes, ex. { 0x01, 0x02 } => 0x0102
206206
inline uint16_t bigEndianConv(const uint8_t *buf) {
207-
return static_cast<uint16_t>(buf[1]) +
208-
(static_cast<uint16_t>(buf[0]) << 8u);
207+
return static_cast<uint16_t>(buf[1]) + (static_cast<uint16_t>(buf[0]) << 8u);
209208
}
210209

211210
//! @deprecated Calculates CRC - please use functions from `MB::CRC`
@@ -234,7 +233,6 @@ inline void pushUint16(std::vector<uint8_t> &buffer, const uint16_t val) {
234233
}
235234

236235
//! Ignore some value explicitly
237-
template<typename T>
238-
inline void ignore_result(T&& v) { (void)v; }
236+
template <typename T> inline void ignore_result(T &&v) { (void)v; }
239237

240238
} // namespace MB::utils

src/CMakeLists.txt

+9-5
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@ set(CORE_SOURCE_FILES
1717
)
1818

1919
add_library(Modbus_Core)
20-
target_sources(Modbus_Core PRIVATE ${CORE_SOURCE_FILES} PUBLIC ${CORE_HEADER_FILES})
20+
target_sources(Modbus_Core PRIVATE ${CORE_SOURCE_FILES} INTERFACE ${CORE_HEADER_FILES})
2121
target_include_directories(Modbus_Core PUBLIC ${PROJECT_SOURCE_DIR}/include PRIVATE ${MODBUS_HEADER_FILES_DIR})
2222

2323
add_library(Modbus)
2424
target_link_libraries(Modbus Modbus_Core)
2525

26+
if(MODBUS_SERIAL_COMMUNICATION)
27+
message(STATUS "Enabling Modbus Serial")
28+
add_subdirectory(Serial)
29+
target_link_libraries(Modbus Modbus_Serial)
30+
endif()
2631

27-
if(MODBUS_COMMUNICATION)
28-
message("Modbus communication is experimental")
32+
if(MODBUS_TCP_COMMUNICATION)
33+
message(STATUS "Enabling Modbus Serial")
2934
add_subdirectory(TCP)
30-
add_subdirectory(Serial)
31-
target_link_libraries(Modbus Modbus_TCP Modbus_Serial)
35+
target_link_libraries(Modbus Modbus_TCP)
3236
endif()

src/Serial/connection.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ std::vector<uint8_t> Connection::awaitRawMessage() {
5555
std::vector<uint8_t> data(1024);
5656

5757
pollfd waitingFD;
58-
waitingFD.fd = this->_fd;
59-
waitingFD.events = POLLIN;
58+
waitingFD.fd = this->_fd;
59+
waitingFD.events = POLLIN;
6060
waitingFD.revents = POLLIN;
6161

6262
if (::poll(&waitingFD, 1, _timeout) <= 0) {

src/TCP/connection.cpp

+20-14
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,17 @@ std::vector<uint8_t> Connection::sendRequest(const MB::ModbusRequest &req) {
2626
std::vector<uint8_t> rawReq;
2727
rawReq.reserve(6);
2828

29-
rawReq.push_back(static_cast<const uint8_t&&>(reinterpret_cast<const uint8_t *>(&_messageID)[1]));
29+
rawReq.push_back(
30+
static_cast<const uint8_t &&>(reinterpret_cast<const uint8_t *>(&_messageID)[1]));
3031
rawReq.push_back(static_cast<uint8_t>(_messageID));
3132
rawReq.push_back(0x00);
3233
rawReq.push_back(0x00);
3334

3435
std::vector<uint8_t> dat = req.toRaw();
3536

3637
uint32_t size = dat.size();
37-
rawReq.push_back(static_cast<const uint16_t&&>(reinterpret_cast<const uint16_t *>(&size)[1]));
38+
rawReq.push_back(
39+
static_cast<const uint16_t &&>(reinterpret_cast<const uint16_t *>(&size)[1]));
3840
rawReq.push_back(static_cast<uint16_t>(size));
3941

4042
rawReq.insert(rawReq.end(), dat.begin(), dat.end());
@@ -48,15 +50,17 @@ std::vector<uint8_t> Connection::sendResponse(const MB::ModbusResponse &res) {
4850
std::vector<uint8_t> rawReq;
4951
rawReq.reserve(6);
5052

51-
rawReq.push_back(static_cast<const uint8_t&&>(reinterpret_cast<const uint8_t *>(&_messageID)[1]));
53+
rawReq.push_back(
54+
static_cast<const uint8_t &&>(reinterpret_cast<const uint8_t *>(&_messageID)[1]));
5255
rawReq.push_back(static_cast<uint8_t>(_messageID));
5356
rawReq.push_back(0x00);
5457
rawReq.push_back(0x00);
5558

5659
std::vector<uint8_t> dat = res.toRaw();
5760

5861
uint32_t size = dat.size();
59-
rawReq.push_back(static_cast<const uint16_t&&>(reinterpret_cast<const uint16_t *>(&size)[1]));
62+
rawReq.push_back(
63+
static_cast<const uint16_t &&>(reinterpret_cast<const uint16_t *>(&size)[1]));
6064
rawReq.push_back(static_cast<uint16_t>(size));
6165

6266
rawReq.insert(rawReq.end(), dat.begin(), dat.end());
@@ -70,15 +74,17 @@ std::vector<uint8_t> Connection::sendException(const MB::ModbusException &ex) {
7074
std::vector<uint8_t> rawReq;
7175
rawReq.reserve(6);
7276

73-
rawReq.push_back(static_cast<const uint8_t&&>(reinterpret_cast<const uint8_t *>(&_messageID)[1]));
77+
rawReq.push_back(
78+
static_cast<const uint8_t &&>(reinterpret_cast<const uint8_t *>(&_messageID)[1]));
7479
rawReq.push_back(static_cast<uint8_t>(_messageID));
7580
rawReq.push_back(0x00);
7681
rawReq.push_back(0x00);
7782

7883
std::vector<uint8_t> dat = ex.toRaw();
7984

8085
uint32_t size = dat.size();
81-
rawReq.push_back(static_cast<const uint16_t&&>(reinterpret_cast<const uint16_t *>(&size)[1]));
86+
rawReq.push_back(
87+
static_cast<const uint16_t &&>(reinterpret_cast<const uint16_t *>(&size)[1]));
8288
rawReq.push_back(static_cast<uint16_t>(size));
8389

8490
rawReq.insert(rawReq.end(), dat.begin(), dat.end());
@@ -90,8 +96,8 @@ std::vector<uint8_t> Connection::sendException(const MB::ModbusException &ex) {
9096

9197
std::vector<uint8_t> Connection::awaitRawMessage() {
9298
pollfd pfd;
93-
pfd.fd = this->_sockfd;
94-
pfd.events = POLLIN;
99+
pfd.fd = this->_sockfd;
100+
pfd.events = POLLIN;
95101
pfd.revents = POLLIN;
96102
if (::poll(&pfd, 1, 60 * 1000 /* 1 minute means the connection has died */) <= 0) {
97103
throw MB::ModbusException(MB::utils::ConnectionClosed);
@@ -115,8 +121,8 @@ std::vector<uint8_t> Connection::awaitRawMessage() {
115121

116122
MB::ModbusRequest Connection::awaitRequest() {
117123
pollfd pfd;
118-
pfd.fd = this->_sockfd;
119-
pfd.events = POLLIN;
124+
pfd.fd = this->_sockfd;
125+
pfd.events = POLLIN;
120126
pfd.revents = POLLIN;
121127
if (::poll(&pfd, 1, 60 * 1000 /* 1 minute means the connection has died */) <= 0) {
122128
throw MB::ModbusException(MB::utils::Timeout);
@@ -146,8 +152,8 @@ MB::ModbusRequest Connection::awaitRequest() {
146152

147153
MB::ModbusResponse Connection::awaitResponse() {
148154
pollfd pfd;
149-
pfd.fd = this->_sockfd;
150-
pfd.events = POLLIN;
155+
pfd.fd = this->_sockfd;
156+
pfd.events = POLLIN;
151157
pfd.revents = POLLIN;
152158

153159
if (::poll(&pfd, 1, this->_timeout) <= 0) {
@@ -195,8 +201,8 @@ Connection Connection::with(std::string addr, int port) {
195201

196202
sockaddr_in server;
197203
server.sin_family = AF_INET;
198-
server.sin_port = ::htons(port);
199-
server.sin_addr = { inet_addr(addr.c_str()) };
204+
server.sin_port = ::htons(port);
205+
server.sin_addr = {inet_addr(addr.c_str())};
200206

201207
if (::connect(sock, reinterpret_cast<struct sockaddr *>(&server), sizeof(server)) < 0)
202208
throw std::runtime_error("Cannot connect, errno = " + std::to_string(errno));

src/modbusException.cpp

+15-6
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,22 @@
33
// Licensed under: MIT License <http://opensource.org/licenses/MIT>
44

55
#include "modbusException.hpp"
6+
#include "modbusUtils.hpp"
7+
8+
#include <cstddef>
9+
#include <cstdint>
10+
#include <vector>
611

712
using namespace MB;
813

914
// Construct Modbus exception from raw data
1015
ModbusException::ModbusException(const std::vector<uint8_t> &inputData,
11-
bool CRC) noexcept {
12-
if (inputData.size() != ((CRC) ? 5 : 3)) {
16+
bool checkCRC) noexcept {
17+
const std::size_t PACKET_SIZE_WITHOUT_CRC = 3;
18+
const std::size_t PACKET_SIZE_WITH_CRC = 5;
19+
20+
if (inputData.size() !=
21+
((checkCRC) ? PACKET_SIZE_WITH_CRC : PACKET_SIZE_WITHOUT_CRC)) {
1322
_slaveId = 0xFF;
1423
_functionCode = utils::Undefined;
1524
_validSlave = false;
@@ -22,11 +31,11 @@ ModbusException::ModbusException(const std::vector<uint8_t> &inputData,
2231
_validSlave = true;
2332
_errorCode = static_cast<utils::MBErrorCode>(inputData[2]);
2433

25-
if (CRC) {
26-
auto CRC = *reinterpret_cast<const uint16_t *>(&inputData[3]);
27-
auto calculatedCRC = utils::calculateCRC(inputData.begin().base(), 3);
34+
if (checkCRC) {
35+
const auto actualCrc = *reinterpret_cast<const uint16_t *>(&inputData[3]);
36+
const uint16_t calculatedCRC = MB::CRC::calculateCRC(inputData, PACKET_SIZE_WITHOUT_CRC);
2837

29-
if (CRC != calculatedCRC) {
38+
if (actualCrc != calculatedCRC) {
3039
_errorCode = utils::ErrorCodeCRCError;
3140
}
3241
}

0 commit comments

Comments
 (0)