Skip to content

Commit c691d75

Browse files
committed
Merge remote-tracking branch 'origin/dev'
2 parents 2e0b621 + 38ebaab commit c691d75

37 files changed

Lines changed: 2660 additions & 1066 deletions

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.sh text eol=lf
2+
*.ts text eol=lf

README.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,57 @@
11
# Open ModSim
22
Open ModSim is a free implimentation of modbus slave (server) utility for modbus-tcp and modbus-rtu protocols.
33

4-
![image](https://github.com/user-attachments/assets/cfa669f5-4018-4db4-bc43-ca060d469182)
5-
6-
![image](https://github.com/user-attachments/assets/16653017-d479-466a-8302-5960a2e47fc4)
4+
<img width="1292" height="759" alt="image" src="https://github.com/user-attachments/assets/993501d6-bb1e-4dee-91c4-6d9b7a53df8b" />
75

6+
<img width="1292" height="760" alt="image" src="https://github.com/user-attachments/assets/1383d93f-03f2-42f5-abb5-0ee1b5dbd10b" />
87

98

109
## Features
1110

1211
The following Modbus functions are available:
1312

14-
Discrete Coils/Flags
15-
13+
- Discrete Coils/Flags
14+
```
1615
0x01 - Read Coils
1716
0x02 - Read Discrete Inputs
1817
0x05 - Write Single Coil
1918
0x0F - Write Multiple Coils
19+
```
2020

21-
Registers
22-
21+
- Registers
22+
```
2323
0x03 - Read Holding Registers
2424
0x04 - Read Input Registers
2525
0x06 - Write Single Register
2626
0x10 - Write Multiple Registers
2727
0x16 - Mask Write Register
28+
```
2829

2930
The following simulations are available:
3031

31-
Discrete Coils/Flags
32-
32+
- Discrete Coils/Flags
33+
```
3334
Random - simulate flag randomly
3435
Toggle - simulate flag on/off periodicaly
35-
36-
Registers
36+
```
3737

38+
- Registers
39+
```
3840
Random - simulate register randomly
3941
Increment - simulate register from Low Limit to High Limit with a given Step
4042
Decrement - simulate register from High Limit to Low Limit with a given Step
43+
```
4144

4245
## Modbus Logging
4346

44-
![image](https://github.com/user-attachments/assets/f62d721f-dd0b-4db7-a239-2a22045e99cd)
47+
<img width="1292" height="759" alt="image" src="https://github.com/user-attachments/assets/b097a1b7-ee3f-4cd8-b0f2-c087cea25c00" />
4548

4649

4750
## Extended Featues
4851

4952
- Modbus Message Parser
5053

51-
![image](https://github.com/sanny32/OpenModSim/assets/13627951/7e9744b8-f4b3-439a-a312-79cbdc426dc2)
54+
<img width="674" height="463" alt="image" src="https://github.com/user-attachments/assets/774e3ff1-1bf2-46a6-a685-e6702e2e7fe5" />
5255

5356

5457
## Scripting

omodsim/CMakeLists.txt

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
cmake_minimum_required(VERSION 3.25)
1+
cmake_minimum_required(VERSION 3.16)
22

33
project(omodsim
4-
VERSION 1.8.2
4+
VERSION 1.9.0
5+
DESCRIPTION "An Open Source Modbus Slave (Server) Utility"
56
LANGUAGES CXX)
67

78
set(CMAKE_AUTOUIC ON)
@@ -10,13 +11,24 @@ set(CMAKE_AUTORCC ON)
1011
set(CMAKE_CXX_STANDARD 17)
1112
set(CMAKE_CXX_STANDARD_REQUIRED ON)
1213
set(PRODUCT_NAME "Open ModSim")
14+
set(EXECUTABLE_PATH "${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}")
15+
16+
# Split version to major, minor, patch
17+
string(REPLACE "." ";" VERSION_LIST ${PROJECT_VERSION})
18+
list(GET VERSION_LIST 0 VERSION_MAJOR)
19+
list(GET VERSION_LIST 1 VERSION_MINOR)
20+
list(GET VERSION_LIST 2 VERSION_PATCH)
1321

1422
# Find Qt6 or fallback to Qt5
1523
find_package(Qt6 COMPONENTS Core Gui Widgets Network PrintSupport SerialBus SerialPort Core5Compat Qml Help LinguistTools QUIET)
1624
if (NOT Qt6_FOUND)
1725
find_package(Qt5 COMPONENTS Core Gui Widgets Network PrintSupport SerialBus SerialPort Qml Help LinguistTools QUIET)
1826
endif()
1927

28+
if (NOT Qt6_FOUND AND NOT Qt5_FOUND)
29+
message(FATAL_ERROR "One or more Qt development packages not found. Please install Qt5 or Qt6 development packages.")
30+
endif()
31+
2032
if(Qt6_FOUND)
2133
get_target_property(QT_BINARY_DIR Qt6::qmake IMPORTED_LOCATION)
2234
get_filename_component(QT_BINARY_DIR "${QT_BINARY_DIR}" DIRECTORY)
@@ -28,15 +40,30 @@ else()
2840
endif()
2941

3042
# Define target
31-
add_executable(omodsim)
43+
add_executable(${PROJECT_NAME})
44+
45+
find_package(Git QUIET)
46+
if(GIT_FOUND)
47+
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
48+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/../.git
49+
OUTPUT_VARIABLE GIT_BRANCH
50+
OUTPUT_STRIP_TRAILING_WHITESPACE
51+
ERROR_QUIET)
52+
53+
if(${GIT_BRANCH} MATCHES dev)
54+
set(PROJECT_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}-dev)
55+
endif()
56+
else()
57+
message(STATUS "Git not found - skipping branch detection")
58+
endif()
3259

3360
# Define compile definitions
3461
add_compile_definitions(APP_NAME="${PRODUCT_NAME}")
3562
add_compile_definitions(APP_DESCRIPTION="${PROJECT_DESCRIPTION}")
3663
add_compile_definitions(APP_VERSION="${PROJECT_VERSION}")
3764

3865
# Include directories
39-
target_include_directories(omodsim PRIVATE
66+
target_include_directories(${PROJECT_NAME} PRIVATE
4067
${CMAKE_CURRENT_SOURCE_DIR}
4168
${CMAKE_CURRENT_SOURCE_DIR}/controls
4269
${CMAKE_CURRENT_SOURCE_DIR}/dialogs
@@ -70,6 +97,7 @@ set(SOURCES
7097
controls/scriptcontrol.cpp
7198
controls/searchlineedit.cpp
7299
controls/simulationmodecombobox.cpp
100+
controls/statisticwidget.cpp
73101
datasimulator.cpp
74102
dialogs/dialogautosimulation.cpp
75103
dialogs/dialogcoilsimulation.cpp
@@ -138,6 +166,7 @@ set(HEADERS
138166
controls/scriptcontrol.h
139167
controls/searchlineedit.h
140168
controls/simulationmodecombobox.h
169+
controls/statisticwidget.h
141170
datasimulator.h
142171
dialogs/dialogautosimulation.h
143172
dialogs/dialogcoilsimulation.h
@@ -155,6 +184,7 @@ set(HEADERS
155184
dialogs/dialogwritecoilregister.h
156185
dialogs/dialogwriteholdingregister.h
157186
dialogs/dialogwriteholdingregisterbits.h
187+
fontutils.h
158188
formatutils.h
159189
htmldelegate.h
160190
jscompleter.h
@@ -212,6 +242,7 @@ set(HEADERS
212242
set(UI_FILES
213243
controls/outputwidget.ui
214244
controls/scriptcontrol.ui
245+
controls/statisticwidget.ui
215246
dialogs/dialogautosimulation.ui
216247
dialogs/dialogcoilsimulation.ui
217248
dialogs/dialogabout.ui
@@ -257,15 +288,19 @@ else()
257288
endif()
258289

259290
# Link libraries
260-
target_sources(omodsim PRIVATE resources.qrc ${HEADERS} ${SOURCES} ${UI_FILES} ${TS_FILES})
261-
target_link_libraries(omodsim PRIVATE Qt::Widgets Qt::Network Qt::PrintSupport Qt::SerialBus Qt::SerialPort Qt::Qml Qt::Help)
291+
target_sources(${PROJECT_NAME} PRIVATE resources.qrc ${HEADERS} ${SOURCES} ${UI_FILES} ${TS_FILES})
292+
target_link_libraries(${PROJECT_NAME} PRIVATE Qt::Widgets Qt::Network Qt::PrintSupport Qt::SerialBus Qt::SerialPort Qt::Qml Qt::Help)
293+
294+
if(TARGET update_translations)
295+
add_dependencies(${PROJECT_NAME} update_translations)
296+
endif()
262297

263298
if(Qt6_FOUND)
264-
qt_add_lupdate(omodsim
299+
qt_add_lupdate(${PROJECT_NAME}
265300
TS_FILES ${TS_FILES}
266301
SOURCES ${SOURCES} ${HEADERS} ${UI_FILES}
267302
)
268-
target_link_libraries(omodsim PRIVATE Qt::Core5Compat)
303+
target_link_libraries(${PROJECT_NAME} PRIVATE Qt::Core5Compat)
269304
else()
270305
add_custom_command(
271306
OUTPUT ${TS_FILES}
@@ -277,24 +312,19 @@ else()
277312
COMMENT "Updating translation files..."
278313
)
279314
add_custom_target(update_translations ALL DEPENDS ${TS_FILES})
280-
281315
endif()
282316

283317
if(WIN32)
284-
string(REPLACE "." ";" VERSION_LIST ${PROJECT_VERSION})
285-
list(GET VERSION_LIST 0 VERSION_MAJOR)
286-
list(GET VERSION_LIST 1 VERSION_MINOR)
287-
list(GET VERSION_LIST 2 VERSION_PATCH)
288-
289-
set(EXECUTABLE_NAME "omodsim")
290318
set(ICON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/omodsim.ico")
291-
set(RC_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/omodsim.rc.in")
292-
set(GENERATED_RC "${CMAKE_BINARY_DIR}/omodsim.rc")
293319

294-
configure_file(${RC_TEMPLATE} ${GENERATED_RC} @ONLY)
320+
configure_file(
321+
"${CMAKE_CURRENT_SOURCE_DIR}/omodsim.rc.in"
322+
"${CMAKE_BINARY_DIR}/omodsim.rc"
323+
@ONLY
324+
)
295325

296-
target_sources(omodsim PRIVATE ${ICON_PATH} ${GENERATED_RC})
297-
set_target_properties(omodsim PROPERTIES WIN32_EXECUTABLE ON)
326+
target_sources(${PROJECT_NAME} PRIVATE ${ICON_PATH} "${CMAKE_BINARY_DIR}/omodsim.rc")
327+
set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE ON)
298328
endif()
299329

300330
add_custom_command(
@@ -310,5 +340,4 @@ add_custom_command(
310340
)
311341

312342
add_custom_target(helpgenerator ALL DEPENDS ${JSHELP_QCH} ${JSHELP_QHC})
313-
add_dependencies(omodsim helpgenerator)
314-
add_dependencies(omodsim update_translations)
343+
add_dependencies(${PROJECT_NAME} helpgenerator)

omodsim/controls/bytelisttextedit.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,27 @@
11
#include <QRegularExpressionValidator>
22
#include <QMimeData>
3+
#include "fontutils.h"
34
#include "formatutils.h"
45
#include "bytelisttextedit.h"
56

7+
///
8+
/// \brief splitBySep
9+
/// \param str
10+
/// \param sep
11+
/// \return
12+
///
13+
QString splitBySep(const QString& str, QChar sep)
14+
{
15+
QString s;
16+
for(int i = 0; i < str.length() - 1; i+=2)
17+
{
18+
s.append(str[i]);
19+
s.append(str[i+1]);
20+
if(i + 3 < str.length()) s.append(sep);
21+
}
22+
return s;
23+
}
24+
625
///
726
/// \brief ByteListTextEdit::ByteListTextEdit
827
/// \param parent
@@ -13,6 +32,7 @@ ByteListTextEdit::ByteListTextEdit(QWidget* parent)
1332
,_validator(nullptr)
1433
{
1534
setInputMode(DecMode);
35+
setFont(defaultMonospaceFont());
1636
connect(this, &QPlainTextEdit::textChanged, this, &ByteListTextEdit::on_textChanged);
1737
}
1838

@@ -27,6 +47,7 @@ ByteListTextEdit::ByteListTextEdit(InputMode mode, QWidget *parent)
2747
,_validator(nullptr)
2848
{
2949
setInputMode(mode);
50+
setFont(defaultMonospaceFont());
3051
connect(this, &QPlainTextEdit::textChanged, this, &ByteListTextEdit::on_textChanged);
3152
}
3253

@@ -182,8 +203,11 @@ void ByteListTextEdit::keyPressEvent(QKeyEvent *e)
182203
///
183204
bool ByteListTextEdit::canInsertFromMimeData(const QMimeData* source) const
184205
{
206+
if (!source->hasText())
207+
return false;
208+
185209
int pos = 0;
186-
auto text = source->text().trimmed();
210+
auto text = source->text().remove("0x").trimmed();
187211
const auto state = _validator->validate(text, pos);
188212

189213
return state == QValidator::Acceptable;
@@ -195,13 +219,18 @@ bool ByteListTextEdit::canInsertFromMimeData(const QMimeData* source) const
195219
///
196220
void ByteListTextEdit::insertFromMimeData(const QMimeData* source)
197221
{
222+
if (!source->hasText())
223+
return;
224+
198225
int pos = 0;
199-
auto text = source->text().trimmed();
200-
const auto state = _validator->validate(text, pos);
226+
auto text = source->text().remove("0x").trimmed();
227+
if(text.length() > 2 && !text.contains(_separator))
228+
text = splitBySep(text, _separator);
201229

230+
const auto state = _validator->validate(text, pos);
202231
if(state == QValidator::Acceptable)
203232
{
204-
QPlainTextEdit::insertFromMimeData(source);
233+
textCursor().insertText(text);
205234
updateValue();
206235
}
207236
}

0 commit comments

Comments
 (0)