Skip to content

Commit fa0f308

Browse files
add option to send signal to other processes on values changed
1 parent b11fc0a commit fa0f308

File tree

6 files changed

+105
-13
lines changed

6 files changed

+105
-13
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,7 @@ target_sources(${Target} PRIVATE Modbus_TCP_Client_poll.cpp)
77
target_sources(${Target} PRIVATE license.cpp)
88
target_sources(${Target} PRIVATE sa_to_str.cpp)
99
target_sources(${Target} PRIVATE Print_Time.cpp)
10-
11-
12-
# ---------------------------------------- header files (*.jpp, *.h, ...) ----------------------------------------------
13-
# ======================================================================================================================
14-
target_sources(${Target} PRIVATE modbus_shm.hpp)
15-
target_sources(${Target} PRIVATE Modbus_TCP_Client_poll.hpp)
16-
target_sources(${Target} PRIVATE license.hpp)
17-
target_sources(${Target} PRIVATE sa_to_str.hpp)
18-
target_sources(${Target} PRIVATE Print_Time.hpp)
19-
10+
target_sources(${Target} PRIVATE Mb_Proc_Signal.cpp)
2011

2112
# ---------------------------------------- subdirectories --------------------------------------------------------------
2213
# ======================================================================================================================

src/Mb_Proc_Signal.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (C) 2024 Nikolas Koesling <nikolas@koesling.info>.
3+
* This program is free software. You can redistribute it and/or modify it under the terms of the GPLv3 License.
4+
*/
5+
6+
#include "Mb_Proc_Signal.hpp"
7+
8+
#include <cerrno>
9+
#include <modbus/modbus.h>
10+
#include <system_error>
11+
12+
Mb_Proc_Signal Mb_Proc_Signal::instance; // NOLINT
13+
14+
Mb_Proc_Signal &Mb_Proc_Signal::get_instance() {
15+
return instance;
16+
}
17+
18+
void Mb_Proc_Signal::add_process(pid_t process) {
19+
processes.insert(process);
20+
}
21+
22+
void Mb_Proc_Signal::send_signal() {
23+
for (auto proc : processes) {
24+
auto ret = kill(proc, SIGUSR1);
25+
if (ret == -1) {
26+
throw std::system_error(
27+
errno, std::generic_category(), "Failed to send signal to process " + std::to_string(proc));
28+
}
29+
}
30+
}
31+
32+
void mb_callback(uint8_t mb_funtion_code) {
33+
switch (mb_funtion_code) {
34+
case MODBUS_FC_WRITE_SINGLE_COIL:
35+
case MODBUS_FC_WRITE_SINGLE_REGISTER:
36+
case MODBUS_FC_WRITE_MULTIPLE_COILS:
37+
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
38+
case MODBUS_FC_WRITE_AND_READ_REGISTERS: Mb_Proc_Signal::get_instance().send_signal(); break;
39+
default:
40+
// do nothing
41+
break;
42+
}
43+
}

src/Mb_Proc_Signal.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (C) 2024 Nikolas Koesling <nikolas@koesling.info>.
3+
* This program is free software. You can redistribute it and/or modify it under the terms of the GPLv3 License.
4+
*/
5+
6+
#include <cstdint>
7+
#include <unistd.h>
8+
#include <unordered_set>
9+
10+
class Mb_Proc_Signal final {
11+
private:
12+
std::unordered_set<pid_t> processes;
13+
14+
Mb_Proc_Signal() = default;
15+
16+
static Mb_Proc_Signal instance;
17+
18+
public:
19+
Mb_Proc_Signal(const Mb_Proc_Signal &) = delete;
20+
Mb_Proc_Signal(Mb_Proc_Signal &&) = delete;
21+
Mb_Proc_Signal &operator=(const Mb_Proc_Signal &) = delete;
22+
Mb_Proc_Signal &operator=(Mb_Proc_Signal &&) = delete;
23+
~Mb_Proc_Signal() = default;
24+
25+
static Mb_Proc_Signal &get_instance();
26+
27+
void add_process(pid_t process);
28+
29+
void send_signal();
30+
};
31+
32+
void mb_callback(uint8_t mb_funtion_code);

src/Modbus_TCP_Client_poll.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,10 @@ void Client_Poll::set_response_timeout(double timeout) {
263263
return static_cast<double>(timeout.sec) + (static_cast<double>(timeout.usec) / (1000.0 * 1000.0)); // NOLINT
264264
}
265265

266-
Client_Poll::run_t Client_Poll::run(int signal_fd, bool reconnect, int timeout) {
266+
Client_Poll::run_t Client_Poll::run(int signal_fd,
267+
bool reconnect,
268+
int timeout,
269+
void (*mb_function_callback)(uint8_t mb_function_code)) {
267270
std::size_t i = 0;
268271

269272
// poll signal fd
@@ -418,6 +421,13 @@ Client_Poll::run_t Client_Poll::run(int signal_fd, bool reconnect, int timeout)
418421
<< std::endl; // NOLINT
419422
close_con(client_addrs);
420423
}
424+
425+
// function code callback
426+
if (mb_function_callback) {
427+
const auto FUNCTION_CODE = query[7];
428+
mb_function_callback(FUNCTION_CODE);
429+
}
430+
421431
} else if (rc == -1) {
422432
if (errno != ECONNRESET) {
423433
std::cerr << Print_Time::iso << " ERROR: modbus_receive failed: " << modbus_strerror(errno)

src/Modbus_TCP_Client_poll.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,15 @@ class Client_Poll {
144144
* true: continue listening for new connections if there is no client (Mosbus Server) left
145145
* @param timeout timeout valoue for call of poll (see: man 2 poll)
146146
* @param signal_fd signal file descriptor for termination signals
147+
* @param mb_function_callback callback function that is called with the modbus function code on each modbus
148+
* telegram
147149
* @return true continue
148150
* @return false terminate
149151
*/
150-
run_t run(int signal_fd, bool reconnect = true, int timeout = -1);
152+
run_t run(int signal_fd,
153+
bool reconnect = true,
154+
int timeout = -1,
155+
void (*mb_function_callback)(uint8_t mb_function_code) = nullptr);
151156

152157
private:
153158
#ifdef OS_LINUX

src/main.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* This program is free software. You can redistribute it and/or modify it under the terms of the GPLv3 License.
44
*/
55

6+
#include "Mb_Proc_Signal.hpp"
67
#include "Modbus_TCP_Client_poll.hpp"
78
#include "Print_Time.hpp"
89
#include "generated/version_info.hpp"
@@ -188,6 +189,8 @@ int main(int argc, char **argv) {
188189
options.add_options("version information")("git-hash", "print git hash");
189190
options.add_options("other")("license", "show licences (short)");
190191
options.add_options("other")("license-full", "show licences (full license text)");
192+
options.add_options("signal")(
193+
"k,signal", "send SIGUSR to process on writing modbus commands", cxxopts::value<std::vector<pid_t>>());
191194

192195
// parse arguments
193196
cxxopts::ParseResult args;
@@ -440,6 +443,14 @@ int main(int argc, char **argv) {
440443
}
441444
}
442445

446+
bool SIGNAL_PROCESS = args.count("signal") > 0;
447+
if (SIGNAL_PROCESS) {
448+
auto &processes = args["signal"].as<std::vector<pid_t>>();
449+
for (auto proc : processes) {
450+
Mb_Proc_Signal::get_instance().add_process(proc);
451+
}
452+
}
453+
443454

444455
// create modbus client
445456
std::unique_ptr<Modbus::TCP::Client_Poll> client;
@@ -487,7 +498,7 @@ int main(int argc, char **argv) {
487498
try {
488499
[&]() {
489500
while (true) {
490-
auto ret = client->run(signal_fd, RECONNECT, -1);
501+
auto ret = client->run(signal_fd, RECONNECT, -1, SIGNAL_PROCESS ? &mb_callback : nullptr);
491502

492503
switch (ret) {
493504
case Modbus::TCP::Client_Poll::run_t::ok: continue;

0 commit comments

Comments
 (0)