Skip to content

Commit 979273e

Browse files
committed
moved the MappedRegisterDataStore to the register controllers as they are unneccessary for the user to see
merging
1 parent c6edb35 commit 979273e

25 files changed

Lines changed: 808 additions & 1159 deletions

.github/workflows/cmake.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ jobs:
2020
- name: Checkout Submodules
2121
run: python3 $(pwd)/git_to_https.py .gitmodules && git submodule update --init && git submodule foreach --recursive python3 $(pwd)/git_to_https.py && git submodule update --init
2222

23+
- name: SetupFlatBuffers
24+
# Execute the build. You can specify a specific target with "--target <NAME>"
25+
run: cd $(pwd)/include/flatbuffers && cmake ./ && sudo make install
26+
2327
- name: Create Build Environment
2428
# Some projects don't allow in-source building, so create a separate build directory
2529
# We'll use this as our working directory for all subsequent commands
2630
run: cmake -E make_directory ${{runner.workspace}}/build
27-
31+
2832
- name: SetupLibs
2933
working-directory: ${{runner.workspace}}/build
3034
shell: bash

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,17 @@ cmake_install.cmake
33
Makefile
44
build
55
/.metadata/
6+
7+
CMakeCache.txt
8+
9+
CMakeFiles
10+
11+
build.ninja
12+
13+
*_generated.h
14+
15+
*modbus_basic_tests
16+
17+
*modbus_client
18+
19+
*.ninja*

.gitmodules

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,12 @@
77
[submodule "examples/pymodbus_tests/pymodbus"]
88
path = examples/pymodbus_tests/pymodbus
99
url = git@github.com:riptideio/pymodbus.git
10-
[submodule "libs/DataStores"]
11-
path = include/DataStores
12-
url = git@github.com:snhobbs/DataStores.git
1310
[submodule "include/CppUtilities"]
1411
path = include/CppUtilities
1512
url = git@github.com:snhobbs/CppUtilities.git
16-
[submodule "include/HardwareInterfaces"]
17-
path = include/HardwareInterfaces
18-
url = git@github.com:snhobbs/BareMetalHardwareAbstraction.git
1913
[submodule "tests/cmake/CMakeStaticAnalysis"]
2014
path = tests/CMakeStaticAnalysis
2115
url = git@github.com:snhobbs/CMakeStaticAnalysis.git
16+
[submodule "include/flatbuffers"]
17+
path = include/flatbuffers
18+
url = git@github.com:snhobbs/flatbuffers.git
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
2+
3+
SET(CMAKE_CXX_COMPILER g++-8)
4+
add_compile_options(-fsanitize=address, -fno-omit-frame-pointer)
5+
add_compile_options(-fsanitize=undefined)
6+
7+
set (TargetName modbus_client)
8+
project(modbus_client)
9+
10+
SET(CMAKE_VERBOSE_MAKEFILE ON)
11+
12+
ADD_EXECUTABLE(${PROJECT_NAME} main.cpp)
13+
target_link_libraries( ${PROJECT_NAME} asan)
14+
#target_link_libraries( ${PROJECT_NAME} tsan)
15+
target_link_libraries( ${PROJECT_NAME} ubsan)
16+
#target_link_libraries( ${PROJECT_NAME} msan)
17+
18+
#find_package(Modbus 1.0.1 REQUIRED)
19+
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
20+
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../common)
21+
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
22+
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR}/DataStores/include)
23+
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR}/CppUtilities/include)
24+
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR}/HardwareInterfaces/include)
25+
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR}/ModbusBasic/include)
26+
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR}/Modbus)
27+
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR})
28+
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR}/../../flatbuffers/include)
29+
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../posix)
30+
31+
target_compile_options(
32+
${PROJECT_NAME}
33+
PUBLIC
34+
-Wall
35+
-Wextra
36+
-Wpedantic
37+
-Wfatal-errors
38+
)
39+
set(source_files "InputRegisterMappedDataStore_generated.h;HoldingRegisterMappedDataStore_generated.h")
40+
list(TRANSFORM source_files PREPEND ${directory}/)
41+
42+
set(script "${ScriptsDirectory}/RegistersMapping.py")
43+
44+
target_sources(${TargetName} PUBLIC ${source_files})
45+
set_source_files_properties(${source_files} GENERATED)
46+
47+
add_custom_target(
48+
flatbuffers
49+
)
50+
51+
set(name "HoldingRegisterMappedDataStore")
52+
add_custom_command(
53+
TARGET flatbuffers
54+
COMMENT "Generating Modbus Source ${source_files}"
55+
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
56+
DEPENDS "${name}.fbs"
57+
BYPRODUCTS "${name}_generated.h"
58+
COMMAND /home/simon/software/flatbuffers/flatc --cpp --grpc --cpp-std=c++17 --cpp-ptr-type naked --gen-mutable --scoped-enums --gen-name-strings --cpp-static-reflection --gen-object-api
59+
ARGS ${name}.fbs
60+
)
61+
set(name "InputRegisterMappedDataStore")
62+
add_custom_command(
63+
TARGET flatbuffers
64+
COMMENT "Generating Modbus Source ${source_files}"
65+
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
66+
DEPENDS "${name}.fbs"
67+
BYPRODUCTS "${name}_generated.h"
68+
COMMAND /home/simon/software/flatbuffers/flatc --cpp --grpc --cpp-std=c++17 --cpp-ptr-type naked --gen-mutable --scoped-enums --gen-name-strings --cpp-static-reflection --gen-object-api
69+
ARGS ${name}.fbs
70+
)
71+
72+
73+
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 17)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
struct HoldingRegisters {
3+
u32_0 : uint32;
4+
u32_1 : uint32;
5+
u32_2 : uint32;
6+
u32_3 : uint32;
7+
u32_4 : uint32;
8+
u16_0 : uint16;
9+
U32_5 : uint32;
10+
u32_6 : uint32;
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
struct InputRegisters {
3+
string_0: [uint8:64];
4+
string_1: [uint8:64];
5+
string_2: [uint8:64];
6+
string_3: [uint8:40];
7+
u16_0: uint16;
8+
u16_1: uint16;
9+
u16_2: uint16;
10+
i32_0: int32;
11+
u32_0: uint32;
12+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#pragma once
2+
3+
#include <Modbus/Modbus.h>
4+
#include <Modbus/DataCommand.h>
5+
#include <Modbus/RegisterControl.h>
6+
#include <Utilities/Crc.h>
7+
#include <sys/time.h>
8+
#include <cstdint>
9+
#include <cstdio> // standard input / output functions
10+
#include <string>
11+
12+
inline int64_t GetMicroSecondsSince(const timeval &first, const timeval &second) {
13+
return (second.tv_sec - first.tv_sec) * 1000000 +
14+
(second.tv_usec - first.tv_usec);
15+
}
16+
17+
inline uint16_t crc16(const ArrayView<uint8_t> &array, std::size_t length) {
18+
assert(length <= array.size());
19+
return Utilities::crc16(array.data(), length);
20+
}
21+
22+
23+
inline timeval GetTimeStamp(void) {
24+
timeval tv;
25+
gettimeofday(&tv, NULL);
26+
return tv;
27+
}
28+
29+
30+
namespace Modbus {
31+
inline std::string GetFunctionName(const Modbus::Function function) {
32+
switch (function) {
33+
case Modbus::Function::kReadCoils:
34+
return "Read Coils";
35+
case Modbus::Function::kReadDiscreteInputs:
36+
return "Read Discrete Inputs";
37+
case Modbus::Function::kReadMultipleHoldingRegisters:
38+
return "Read Multiple Holding Registers";
39+
case Modbus::Function::kReadInputRegisters:
40+
return "Read Input Registers";
41+
case Modbus::Function::kWriteSingleCoil:
42+
return "Read Single Coil";
43+
case Modbus::Function::kWriteSingleHoldingRegister:
44+
return "Write Single Holding Register";
45+
case Modbus::Function::kWriteMultipleHoldingRegisters:
46+
return "Write Multiple Holding Registers";
47+
case Modbus::Function::kWriteMultipleCoils:
48+
return "Write Multiple Coils";
49+
case Modbus::Function::kReadDeviceIdentification:
50+
return "Read Device Information";
51+
default:
52+
break;
53+
}
54+
char buff[256]{};
55+
snprintf(buff, sizeof(buff), "Unknown Command %d", static_cast<int>(function));
56+
return buff;
57+
}
58+
59+
60+
inline void PrintPacketData(const Modbus::Frame& frame) {
61+
printf("Slave Address %d: %s ", frame.address, GetFunctionName(frame.function).c_str());
62+
switch (frame.function) {
63+
case Modbus::Function::kReadMultipleHoldingRegisters: {
64+
const uint16_t address = Modbus::DataCommand::ReadAddressStart(frame.data_array);
65+
const uint16_t register_count = Modbus::ReadMultipleHoldingRegistersCommand::ReadRegisterCount(frame.data_array);
66+
printf("Address: 0x%x, Count: %d", address, register_count);
67+
break;
68+
}
69+
case Modbus::Function::kWriteMultipleHoldingRegisters: {
70+
const uint16_t address = Modbus::DataCommand::ReadAddressStart(frame.data_array);
71+
const uint16_t register_count = Modbus::WriteMultipleHoldingRegistersCommand::ReadRegisterCount(frame.data_array);
72+
printf("Address: 0x%x, Count: %d", address, register_count);
73+
break;
74+
}
75+
default:
76+
break;
77+
}
78+
79+
printf(" [");
80+
for (std::size_t i = 0; i < frame.data_length; i++) {
81+
printf("0x%x ", frame.data_array[i]);
82+
}
83+
printf("]");
84+
}
85+
86+
} // namespace Modbus
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/* Copyright (C) 2020 Electrooptical Innovations
2+
* ----------------------------------------------------------------------
3+
* Project: Modbus
4+
* Title: LinuxSlave.h
5+
* Description: Linux modbus slave
6+
*
7+
* $Date: 13. May 2020
8+
* $Revision: V.1.0.1
9+
* ----------------------------------------------------------------------
10+
*/
11+
12+
#pragma once
13+
#include "LinuxModbusTools.h"
14+
#include <Modbus/flat_buffers_register_wrapper.h>
15+
#include "InputRegisterMappedDataStore_generated.h"
16+
#include "HoldingRegisterMappedDataStore_generated.h"
17+
#include <Modbus/../../examples/posix/PosixSerial.h>
18+
#include <Modbus/Modbus.h>
19+
#include <Modbus/BitControl.h>
20+
#include <Modbus/DataStore.h>
21+
#include <Modbus/ModbusRtu/ModbusRtuSlave.h>
22+
#include <Modbus/RegisterControl.h>
23+
#include <Modbus/MappedRegisterDataStore.h>
24+
#include <Modbus/DataStore.h>
25+
#include <Utilities/TypeConversion.h>
26+
#include <cassert>
27+
#include <cstdint>
28+
#include <sys/time.h>
29+
#include <vector>
30+
inline const constexpr std::size_t kCoilCount = 1;
31+
using CoilController =
32+
Modbus::CoilController<Modbus::BitFieldDataStore<kCoilCount>>;
33+
using DiscreteInputController =
34+
Modbus::DiscreteInputController<Modbus::BitFieldDataStore<kCoilCount>>;
35+
36+
37+
using HoldingRegisterMemoryMap = Modbus::FlatBufferRegisterStore<HoldingRegisters>;
38+
using HoldingRegisterController =
39+
Modbus::HoldingRegisterController<Modbus::MappedRegisterDataStore<HoldingRegisterMemoryMap>>;
40+
using InputRegisterMemoryMap = Modbus::FlatBufferRegisterStore<InputRegisters>;
41+
using InputRegisterController =
42+
Modbus::InputRegisterController<Modbus::MappedRegisterDataStore<InputRegisterMemoryMap>>;
43+
using SlaveBase =
44+
Modbus::ProtocolRtuSlave<CoilController, HoldingRegisterController,
45+
DiscreteInputController, InputRegisterController>;
46+
47+
48+
class LinuxSlave : public SlaveBase {
49+
public:
50+
51+
CoilController coils_;
52+
//HoldingRegisterController& holding_register_controller_;
53+
DiscreteInputController dins_;
54+
55+
static const constexpr uint8_t kSlaveAddress = 0x03;
56+
57+
static const constexpr int kBaudRateHz = 9600;
58+
static const constexpr speed_t kBaudRate = B9600;
59+
static const constexpr int kCharacterClocks = 8 + 1;
60+
61+
const char *const device_name; // = "/tmp/ttyp0";
62+
timeval last_character_time_ = GetTimeStamp();
63+
static const constexpr int64_t kFrameDelay_us =
64+
(1e6 * (kCharacterClocks * 3.5)) / (static_cast<double>(kBaudRateHz));
65+
UartController iodev_;
66+
int byte_counter_ = 0;
67+
68+
timeval GetTimeStamp(void) {
69+
timeval tv;
70+
gettimeofday(&tv, NULL);
71+
return tv;
72+
}
73+
74+
void ProcessPacket(void) {
75+
ProcessMessage();
76+
77+
const auto& frame = GetFrameIn();
78+
Modbus::PrintPacketData(frame);
79+
printf("\n");
80+
#if 0
81+
if (frame.address == 246 || frame.function == Modbus::Function::kWriteMultipleHoldingRegisters) {
82+
printf("\n");
83+
PrintPacketData(frame);
84+
printf("\n");
85+
} else {
86+
printf(".");
87+
fflush(stdout);
88+
}
89+
#endif
90+
if (GetResponseValid()) {
91+
iodev_.write(GetResponse().data(), GetResponse().GetLength());
92+
printf("Response: [");
93+
const auto response = GetResponse();
94+
std::size_t cnt = 0;
95+
for (auto pt : response) {
96+
cnt++;
97+
printf("%d ", pt);
98+
}
99+
printf("]\n");
100+
assert(cnt == response.GetLength());
101+
}
102+
Reset();
103+
}
104+
105+
bool RxCharacterTimeout(const timeval &timestamp) const {
106+
const bool character_timeout = GetMicroSecondsSince(last_character_time_, timestamp) >=
107+
10 * kFrameDelay_us;
108+
return character_timeout;
109+
}
110+
111+
public:
112+
void Run(void) {
113+
//sleep(0.005);
114+
iodev_.SendTxBuff();
115+
iodev_.ReadIntoRxBuff();
116+
117+
if (slave_.ctx_.PacketReceived()) {
118+
// check slave address
119+
ProcessPacket();
120+
}
121+
if (!iodev_.rxEmpty()) {
122+
last_character_time_ = GetTimeStamp();
123+
uint8_t data = 0;
124+
iodev_.read(&data, 1);
125+
slave_.ProcessCharacter(data);
126+
} else if (RxCharacterTimeout(GetTimeStamp())) {
127+
Reset();
128+
}
129+
}
130+
131+
public:
132+
133+
explicit LinuxSlave(const char *const port,
134+
HoldingRegisterController& holding_register_controller,
135+
InputRegisterController& input_register_controller)
136+
: SlaveBase{&crc16, kSlaveAddress, coils_,
137+
holding_register_controller, dins_, input_register_controller},
138+
device_name{port}, iodev_{port, kBaudRate} {}
139+
};

0 commit comments

Comments
 (0)