mirror of
https://github.com/emqx/neuron.git
synced 2026-10-30 16:09:02 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccb6a62366 | ||
|
|
0a21862ac6 | ||
|
|
36cb4f6f3d | ||
|
|
1efcf861fe | ||
|
|
70c3f60ca3 | ||
|
|
525723ce2b | ||
|
|
835cb6bef0 | ||
|
|
563b9152bc | ||
|
|
7088a3a1fc | ||
|
|
87e967b75c | ||
|
|
be841977b9 | ||
|
|
65fff4f60a | ||
|
|
d8edb81d5a | ||
|
|
1d3e929cd8 | ||
|
|
43f3f482ee | ||
|
|
66aa3f96d3 | ||
|
|
f24b7c0ae5 | ||
|
|
6a8eb564be | ||
|
|
03fa5acf45 | ||
|
|
bfc14549a9 | ||
|
|
b2647cc091 | ||
|
|
de5a085339 | ||
|
|
19d8cb10ca | ||
|
|
971b1cf621 | ||
|
|
ad733be727 | ||
|
|
adc131570a | ||
|
|
8fe052364d | ||
|
|
3f1595c8c1 | ||
|
|
695c17627e | ||
|
|
aa293a7c56 | ||
|
|
e30d9599a8 | ||
|
|
4ba50cfc7c | ||
|
|
3c176bc0c5 | ||
|
|
5427c304c8 | ||
|
|
454a49f7fb | ||
|
|
738c406e06 | ||
|
|
49c0253909 | ||
|
|
e57f141606 | ||
|
|
cee2260cfd | ||
|
|
2f2fc27b49 | ||
|
|
8d8afa3c84 | ||
|
|
d868b77154 | ||
|
|
71bf03badb | ||
|
|
18bb90b3cf | ||
|
|
49257b850b | ||
|
|
96f98d15b9 | ||
|
|
b87fee91c1 | ||
|
|
b8a49073ca | ||
|
|
746e010e7e | ||
|
|
2a292c11f1 | ||
|
|
b7c35347e2 | ||
|
|
8dfdcee740 | ||
|
|
7166b68293 | ||
|
|
c48aebce8d | ||
|
|
7dd05b453b | ||
|
|
c88b60c8c3 | ||
|
|
0b75c2afb0 | ||
|
|
58960f4be6 | ||
|
|
c9c35e02c6 | ||
|
|
e5e421f257 | ||
|
|
4d4887a6e3 | ||
|
|
d57b95b0a1 | ||
|
|
c1cafe3fc7 | ||
|
|
cdbb511140 | ||
|
|
d2b96f5ca8 | ||
|
|
6bdf31b660 | ||
|
|
369e49f7ce | ||
|
|
a2c81d3572 | ||
|
|
d3f0b52fb2 | ||
|
|
82fe13876f | ||
|
|
ed01dd060a | ||
|
|
f69328e01a | ||
|
|
e33d331ee3 | ||
|
|
542624189a | ||
|
|
90e7b0ec03 | ||
|
|
30579ef578 | ||
|
|
bc44bfeda1 | ||
|
|
73efd03cfa | ||
|
|
60c707cdde | ||
|
|
10b317c0d7 | ||
|
|
3d9ac43d42 | ||
|
|
3605e132cc | ||
|
|
163475f9a9 | ||
|
|
d2cd9267bc | ||
|
|
6d6af8be93 | ||
|
|
fddad11a5f | ||
|
|
56e45ae77e | ||
|
|
edd1d5eee0 | ||
|
|
ebf9d92315 | ||
|
|
5fcd8d2d03 | ||
|
|
6ad096315f | ||
|
|
8f98ab9d6f | ||
|
|
ebfb31d672 | ||
|
|
e691099640 | ||
|
|
e9505e14cd | ||
|
|
2555525445 | ||
|
|
ab8da34a6d | ||
|
|
899081fc03 | ||
|
|
ebb969af8f | ||
|
|
4a56ba1a3a | ||
|
|
069786f6c0 | ||
|
|
a548a57d11 | ||
|
|
37f45d4b3a | ||
|
|
3a1a0fab3a | ||
|
|
10eec9446a | ||
|
|
2df3f79536 | ||
|
|
f23c5a5cb8 | ||
|
|
eadcdf5fa1 | ||
|
|
d1dd7008e6 | ||
|
|
b0b6a08702 | ||
|
|
77e25d532b | ||
|
|
d1d5b95a6a | ||
|
|
125324546f | ||
|
|
0556e30343 | ||
|
|
97e8febf91 | ||
|
|
97e986e14f | ||
|
|
64e265770e | ||
|
|
e919af04b0 | ||
|
|
5b00c22e70 | ||
|
|
c83b0498d6 | ||
|
|
b2c1c45c01 | ||
|
|
f1db3782b9 | ||
|
|
5e19ff78ff | ||
|
|
8fce63ae7b | ||
|
|
dc16ca62d3 | ||
|
|
76bbb2cbce | ||
|
|
1079af396e |
@@ -12,3 +12,4 @@ PointerAlignment: Right
|
||||
SpaceAfterCStyleCast: true
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
BreakBeforeBinaryOperators: None
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ on:
|
||||
- published
|
||||
|
||||
env:
|
||||
VERSION: 2.4.3
|
||||
UI_VERSION: 2.4.2
|
||||
VERSION: 2.4.10
|
||||
UI_VERSION: 2.4.8
|
||||
BRANCH: v2.4
|
||||
|
||||
jobs:
|
||||
|
||||
+4
-1
@@ -16,4 +16,7 @@ tmp
|
||||
*.deb
|
||||
*.rpm
|
||||
neuron-sdk
|
||||
.vscode
|
||||
.vscode
|
||||
log.html
|
||||
output.xml
|
||||
report.html
|
||||
+1
-1
@@ -32,7 +32,7 @@ if(NOT DISABLE_WERROR)
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -g")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O1")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O0")
|
||||
|
||||
if(NOT DISABLE_ASAN)
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -fsanitize=address")
|
||||
|
||||
@@ -17,3 +17,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
link_directories(${CMAKE_STAGING_PREFIX})
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "mips32")
|
||||
link_libraries(atomic)
|
||||
endif()
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
"libplugin-mqtt.so",
|
||||
"libplugin-ekuiper.so",
|
||||
"libplugin-monitor.so",
|
||||
"libplugin-modbus-tcp.so",
|
||||
"libplugin-modbus-rtu.so",
|
||||
"libplugin-modbus-qh-tcp.so",
|
||||
"libplugin-modbus-tcp-comm.so",
|
||||
"libplugin-file.so"
|
||||
]
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
*** Settings ***
|
||||
Resource resource/api.resource
|
||||
Resource resource/common.resource
|
||||
Resource resource/error.resource
|
||||
Resource resource/driver.resource
|
||||
Suite Setup Modbus Test Setup
|
||||
Suite Teardown Modbus Test Teardown
|
||||
|
||||
*** Variables ***
|
||||
${modbus_rtu_node} modbus_rtu_node
|
||||
${PLUGIN-MODBUS-RTU} Modbus RTU
|
||||
|
||||
${MODBUS_RTU_CONFIG} {"link": 1, "timeout": 3000, "interval": 10, "device": "", "stop": 0, "parity": 0, "baud": 4,"data": 3, "host": "127.0.0.1", "port": 60503, "connection_mode": 0}
|
||||
${MODBUS_RTU_CONFIG_WRANING} {"link": 1, "host": "127.0.0.1","port": 60503,"connection_mode": 0}
|
||||
|
||||
${hold_bit} {"name": "hold_bit", "address": "1!400001.15", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
|
||||
${hold_int16} {"name": "hold_int16", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
|
||||
${hold_uint16} {"name": "hold_uint16", "address": "1!400002", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_UINT16}}
|
||||
${hold_int32} {"name": "hold_int32", "address": "1!400003", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT32}}
|
||||
${hold_uint32} {"name": "hold_uint32", "address": "1!400015", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_UINT32}}
|
||||
${hold_float} {"name": "hold_float", "address": "1!400017", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_FLOAT}}
|
||||
${hold_string} {"name": "hold_string", "address": "1!400020.10", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_STRING}}
|
||||
|
||||
${coil_bit_1} {"name": "coil_bit_1", "address": "1!000001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
|
||||
${coil_bit_2} {"name": "coil_bit_2", "address": "1!000002", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
|
||||
${coil_bit_3} {"name": "coil_bit_3", "address": "1!000003", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
|
||||
${coil_bit_4} {"name": "coil_bit_4", "address": "1!000005", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
|
||||
${coil_bit_5} {"name": "coil_bit_5", "address": "1!000010", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
|
||||
|
||||
${input_bit_1} {"name": "input_bit_1", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
|
||||
${input_bit_2} {"name": "input_bit_2", "address": "1!100002", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
|
||||
${input_bit_3} {"name": "input_bit_3", "address": "1!100003", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
|
||||
${input_bit_4} {"name": "input_bit_4", "address": "1!100005", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
|
||||
${input_bit_5} {"name": "input_bit_5", "address": "1!100010", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
|
||||
|
||||
${input_register_bit} {"name": "input_register_bit", "address": "1!30101.15", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
|
||||
${input_register_int16} {"name": "input_register_int16", "address": "1!30101", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
|
||||
${input_register_uint16} {"name": "input_register_uint16", "address": "1!30102", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_UINT16}}
|
||||
${input_register_int32} {"name": "input_register_int32", "address": "1!30103", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT32}}
|
||||
${input_register_uint32} {"name": "input_register_uint32", "address": "1!30115", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_UINT32}}
|
||||
${input_register_float} {"name": "input_register_float", "address": "1!30117", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_FLOAT}}
|
||||
${input_register_string} {"name": "input_register_string", "address": "1!30120.10", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_STRING}}
|
||||
|
||||
${hold_int16_address_update} {"name": "hold_int16", "address": "1!400100", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
|
||||
${hold_int16_type_update} {"name": "hold_int16", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT32}}
|
||||
|
||||
${input_bit_1_name_wrong} {"name": "input_bit", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
|
||||
${input_bit_1_attribute_unmatch} {"name": "input_bit_1", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
|
||||
${input_bit_1_type_unmatch} {"name": "input_bit_1", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
|
||||
|
||||
*** Test Cases ***
|
||||
Set a node with right settings, it should be success.
|
||||
[Template] Set a ${node} with right ${node_settings}, it will be success.
|
||||
${modbus_rtu_node} ${MODBUS_RTU_CONFIG}
|
||||
|
||||
Set a node with wrong settings, it should be failure.
|
||||
[Template] Set a ${node} with wrong ${node_settings}, it will be failure.
|
||||
${modbus_rtu_node} ${MODBUS_RTU_CONFIG_WRANING}
|
||||
|
||||
Set tags with multiple address and types and attribute, it should be success.
|
||||
[Template] Add a ${tag} with right address and type and attribute from ${node}, it will be success.
|
||||
${hold_int16} ${modbus_rtu_node}
|
||||
${hold_uint16} ${modbus_rtu_node}
|
||||
${hold_int32} ${modbus_rtu_node}
|
||||
${hold_uint32} ${modbus_rtu_node}
|
||||
${hold_float} ${modbus_rtu_node}
|
||||
${hold_string} ${modbus_rtu_node}
|
||||
|
||||
${coil_bit_1} ${modbus_rtu_node}
|
||||
${coil_bit_2} ${modbus_rtu_node}
|
||||
${coil_bit_3} ${modbus_rtu_node}
|
||||
${coil_bit_4} ${modbus_rtu_node}
|
||||
${coil_bit_5} ${modbus_rtu_node}
|
||||
|
||||
${input_register_int16} ${modbus_rtu_node}
|
||||
${input_register_uint16} ${modbus_rtu_node}
|
||||
${input_register_int32} ${modbus_rtu_node}
|
||||
${input_register_uint32} ${modbus_rtu_node}
|
||||
${input_register_float} ${modbus_rtu_node}
|
||||
${input_register_string} ${modbus_rtu_node}
|
||||
|
||||
${input_bit_1} ${modbus_rtu_node}
|
||||
${input_bit_2} ${modbus_rtu_node}
|
||||
${input_bit_3} ${modbus_rtu_node}
|
||||
${input_bit_4} ${modbus_rtu_node}
|
||||
${input_bit_5} ${modbus_rtu_node}
|
||||
|
||||
Set tags with unmatch address, type or attribute, it should be failure.
|
||||
[Template] Set a ${tag} with unmatch address, type or attribute from ${node}, it will be failure and return ${resp_status} and ${error_code}.
|
||||
${input_bit_1_type_unmatch} ${modbus_rtu_node} 200 ${NEU_ERR_TAG_TYPE_NOT_SUPPORT}
|
||||
${input_bit_1_attribute_unmatch} ${modbus_rtu_node} 200 ${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT}
|
||||
|
||||
Write and Read all type tag with same slave id in hold register and coil, it should be success.
|
||||
[Template] Write and Read a ${tag} named ${tag_name} from ${node}, using ${check} to check the ${value}, it will be success.
|
||||
${hold_int16} hold_int16 ${modbus_rtu_node} Compare Tag Value As Int 120
|
||||
${hold_uint16} hold_uint16 ${modbus_rtu_node} Compare Tag Value As Int 65535
|
||||
${hold_int32} hold_int32 ${modbus_rtu_node} Compare Tag Value As Int 77889912
|
||||
${hold_uint32} hold_uint32 ${modbus_rtu_node} Compare Tag Value As Int 88991232
|
||||
${hold_float} hold_float ${modbus_rtu_node} Compare Tag Value As Float 12.34
|
||||
${hold_string} hold_string ${modbus_rtu_node} Compare Tag Value As Strings "abc123"
|
||||
|
||||
${coil_bit_1} coil_bit_1 ${modbus_rtu_node} Compare Tag Value As Int 1
|
||||
${coil_bit_2} coil_bit_2 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
${coil_bit_3} coil_bit_3 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
${coil_bit_4} coil_bit_4 ${modbus_rtu_node} Compare Tag Value As Int 1
|
||||
${coil_bit_5} coil_bit_5 ${modbus_rtu_node} Compare Tag Value As Int 1
|
||||
|
||||
Read all type tag with same slave id in input register and input, it should be success.
|
||||
[Template] Read a ${tag} named ${tag_name} from ${node}, using ${check} to check the ${value}, it will be success.
|
||||
${input_register_int16} input_register_int16 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
${input_register_uint16} input_register_uint16 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
${input_register_int32} input_register_int32 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
${input_register_uint32} input_register_uint32 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
${input_register_float} input_register_float ${modbus_rtu_node} Compare Tag Value As Float 0
|
||||
${input_register_string} input_register_string ${modbus_rtu_node} Compare Tag Value As Strings ""
|
||||
|
||||
${input_bit_1} input_bit_1 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
${input_bit_2} input_bit_2 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
${input_bit_3} input_bit_3 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
${input_bit_4} input_bit_4 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
${input_bit_5} input_bit_5 ${modbus_rtu_node} Compare Tag Value As Int 0
|
||||
|
||||
Read some tags at time, it will be success.
|
||||
[Template] Read some ${tags} from ${node}, it will be success.
|
||||
${input_register_int16},${input_register_uint16},${input_register_int32},${input_register_uint32},${input_register_float},${input_register_string},${input_register_bit} ${modbus_rtu_node}
|
||||
${hold_int16},${hold_uint16},${hold_int32},${hold_uint32},${hold_float},${hold_string},${hold_bit} ${modbus_rtu_node}
|
||||
${coil_bit_1},${coil_bit_2},${coil_bit_3},${coil_bit_4},${coil_bit_5} ${modbus_rtu_node}
|
||||
${input_bit_1},${input_bit_2},${input_bit_3},${input_bit_4},${input_bit_5} ${modbus_rtu_node}
|
||||
|
||||
Write and read a tag with same name and same address that in different groups, it should be success.
|
||||
${groups}= Create List group-1 group-2 group-3
|
||||
Write and read a ${hold_int16} with same hold_int16 and same address in different ${groups} that from ${modbus_rtu_node}, using Compare Tag Value As Int to check the 2, it will be success.
|
||||
|
||||
Write and read a tag with same name but different address that in different groups, it should be success.
|
||||
${groups}= Create List group-1 group-2 group-3
|
||||
Write and read ${hold_int16} ${hold_int16_address_update} with same hold_int16 but different address in different ${groups} that from ${modbus_rtu_node}, using Compare Tag Value As Int to check the 2, it will be success.
|
||||
|
||||
Update a tag with right address and types and attribute, it will be success
|
||||
[Template] Update a ${tag} by a ${tag_update} named ${tag_name} from ${node} , it can read and write, using ${check} to check the ${value}, it will be success.
|
||||
${hold_int16} ${hold_int16_address_update} hold_int16 ${modbus_rtu_node} Compare Tag Value As Int 120
|
||||
${hold_int16} ${hold_int16_type_update} hold_int16 ${modbus_rtu_node} Compare Tag Value As Int 120
|
||||
|
||||
Update a tag with unmatch address and types and attribute, it should be failure.
|
||||
[Template] Update a ${tag} by a ${tag_update} with the unmatch settings from ${node} , it will be failure and return ${resp_status} and ${error_code}.
|
||||
${input_bit_1} ${input_bit_1_attribute_unmatch} ${modbus_rtu_node} 200 ${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT}
|
||||
${input_bit_1} ${input_bit_1_type_unmatch} ${modbus_rtu_node} 200 ${NEU_ERR_TAG_TYPE_NOT_SUPPORT}
|
||||
${input_bit_1} ${input_bit_1_name_wrong} ${modbus_rtu_node} 200 ${NEU_ERR_TAG_NOT_EXIST}
|
||||
|
||||
Write a value to a tag that don't exit in plc or neuron, it will be failure.
|
||||
[Template] Write a ${value} to a ${tag} with named ${tag_name} that don't exist in neuron or plc from ${node}, it will be failure.
|
||||
12 ${input_bit_1} input ${modbus_rtu_node}
|
||||
|
||||
Write value to a tag without write attribute, it will be failure.
|
||||
[Template] Write a ${value} to a ${tag} named ${tag_name} that without write attribute from ${node}, it will be failure.
|
||||
1 ${input_bit_1} input_bit_1 ${modbus_rtu_node}
|
||||
|
||||
Write and read a value to a tag when the node is stoped, it will be failure.
|
||||
[Template] Write and read a ${value} to a ${tag} named ${tag_name} when the ${node} is stoped, it will be failure.
|
||||
1 ${hold_int16} hold_int16 ${modbus_rtu_node}
|
||||
|
||||
*** Keywords ***
|
||||
Modbus Test Setup
|
||||
Start Modbus-RTU Simulator
|
||||
|
||||
Start Neuronx
|
||||
|
||||
${res}= Add Node ${modbus_rtu_node} ${PLUGIN-MODBUS-RTU}
|
||||
Check Response Status ${res} 200
|
||||
|
||||
${res}= Node Setting ${modbus_rtu_node} ${MODBUS_RTU_CONFIG}
|
||||
Check Response Status ${res} 200
|
||||
|
||||
${state}= Get Node State ${modbus_rtu_node}
|
||||
Should Be Equal As Integers ${state}[running] ${NODE_STATE_RUNNING}
|
||||
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_DISCONNECTED}
|
||||
|
||||
Modbus Test Teardown
|
||||
Del Node ${modbus_rtu_node}
|
||||
Stop Neuronx
|
||||
Terminate All Processes kill=false
|
||||
|
||||
Start Modbus-RTU Simulator
|
||||
${handle} = Start Process ${MODBUS_TCP_SERVER_SIMULATOR} rtu 60503 cwd=build/simulator
|
||||
[Return] ${handle}
|
||||
+90
-77
@@ -1,7 +1,4 @@
|
||||
*** Settings ***
|
||||
Library Process
|
||||
Library OperatingSystem
|
||||
|
||||
Resource resource/api.resource
|
||||
Resource resource/common.resource
|
||||
Resource resource/error.resource
|
||||
@@ -10,13 +7,9 @@ Suite Setup Modbus Test Setup
|
||||
Suite Teardown Modbus Test Teardown
|
||||
|
||||
*** Variables ***
|
||||
${PLUGIN-MODBUS-TCP} Modbus TCP
|
||||
${modbus_node} modbus_node
|
||||
|
||||
${modbus_tcp_node} modbus_tcp_node
|
||||
|
||||
${MODBUS_TCP_CONFIG} {"connection_mode": 0,"interval": 0, "host": "127.0.0.1","port": 60502,"timeout": 3000}
|
||||
|
||||
${MODBUS_TCP_CONFIG_WRONG} {"connection_mode": 0,"host": "127.0.0.1", "port": 60502}
|
||||
${MODBUS_TCP_CONFIG_WRONG} {"host": "127.0.0.1", "port": 60502}
|
||||
|
||||
${hold_bit} {"name": "hold_bit", "address": "1!400001.15", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
|
||||
${hold_int16} {"name": "hold_int16", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
|
||||
@@ -53,115 +46,135 @@ ${input_bit_1_name_wrong} {"name": "input_bit", "address": "1!100001", "att
|
||||
${input_bit_1_attribute_unmatch} {"name": "input_bit_1", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
|
||||
${input_bit_1_type_unmatch} {"name": "input_bit_1", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
|
||||
|
||||
${hold_int16_static} {"name": "hold_int16", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_STATIC_RW}, "type": ${TAG_TYPE_INT16}, "value": 1}
|
||||
|
||||
*** Test Cases ***
|
||||
Set a node with right settings, it should be success.
|
||||
[Template] Set a ${node} with right ${node_settings}, it will be success.
|
||||
${modbus_tcp_node} ${MODBUS_TCP_CONFIG}
|
||||
${modbus_node} ${MODBUS_TCP_CONFIG}
|
||||
|
||||
Set a node with wrong settings, it should be failure.
|
||||
[Template] Set a ${node} with wrong ${node_settings}, it will be failure.
|
||||
${modbus_tcp_node} ${MODBUS_TCP_CONFIG_WRONG}
|
||||
${modbus_node} ${MODBUS_TCP_CONFIG_WRONG}
|
||||
|
||||
Set tags with multiple address and types and attribute, it should be success.
|
||||
[Template] Add a ${tag} with right address and type and attribute from ${node}, it will be success.
|
||||
${hold_int16} ${modbus_tcp_node}
|
||||
${hold_uint16} ${modbus_tcp_node}
|
||||
${hold_int32} ${modbus_tcp_node}
|
||||
${hold_uint32} ${modbus_tcp_node}
|
||||
${hold_float} ${modbus_tcp_node}
|
||||
${hold_string} ${modbus_tcp_node}
|
||||
${hold_int16} ${modbus_node}
|
||||
${hold_uint16} ${modbus_node}
|
||||
${hold_int32} ${modbus_node}
|
||||
${hold_uint32} ${modbus_node}
|
||||
${hold_float} ${modbus_node}
|
||||
${hold_string} ${modbus_node}
|
||||
|
||||
${coil_bit_1} ${modbus_tcp_node}
|
||||
${coil_bit_2} ${modbus_tcp_node}
|
||||
${coil_bit_3} ${modbus_tcp_node}
|
||||
${coil_bit_4} ${modbus_tcp_node}
|
||||
${coil_bit_5} ${modbus_tcp_node}
|
||||
${coil_bit_1} ${modbus_node}
|
||||
${coil_bit_2} ${modbus_node}
|
||||
${coil_bit_3} ${modbus_node}
|
||||
${coil_bit_4} ${modbus_node}
|
||||
${coil_bit_5} ${modbus_node}
|
||||
|
||||
${input_register_int16} ${modbus_tcp_node}
|
||||
${input_register_uint16} ${modbus_tcp_node}
|
||||
${input_register_int32} ${modbus_tcp_node}
|
||||
${input_register_uint32} ${modbus_tcp_node}
|
||||
${input_register_float} ${modbus_tcp_node}
|
||||
${input_register_string} ${modbus_tcp_node}
|
||||
${input_register_int16} ${modbus_node}
|
||||
${input_register_uint16} ${modbus_node}
|
||||
${input_register_int32} ${modbus_node}
|
||||
${input_register_uint32} ${modbus_node}
|
||||
${input_register_float} ${modbus_node}
|
||||
${input_register_string} ${modbus_node}
|
||||
|
||||
${input_bit_1} ${modbus_tcp_node}
|
||||
${input_bit_2} ${modbus_tcp_node}
|
||||
${input_bit_3} ${modbus_tcp_node}
|
||||
${input_bit_4} ${modbus_tcp_node}
|
||||
${input_bit_5} ${modbus_tcp_node}
|
||||
${input_bit_1} ${modbus_node}
|
||||
${input_bit_2} ${modbus_node}
|
||||
${input_bit_3} ${modbus_node}
|
||||
${input_bit_4} ${modbus_node}
|
||||
${input_bit_5} ${modbus_node}
|
||||
|
||||
Set tags with unmatch address, type or attribute, it should be failure.
|
||||
[Template] Set a ${tag} with unmatch address, type or attribute from ${node}, it will be failure and return ${resp_status} and ${error_code}.
|
||||
${input_bit_1_type_unmatch} ${modbus_tcp_node} 200 ${NEU_ERR_TAG_TYPE_NOT_SUPPORT}
|
||||
${input_bit_1_attribute_unmatch} ${modbus_tcp_node} 200 ${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT}
|
||||
${input_bit_1_type_unmatch} ${modbus_node} 200 ${NEU_ERR_TAG_TYPE_NOT_SUPPORT}
|
||||
${input_bit_1_attribute_unmatch} ${modbus_node} 200 ${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT}
|
||||
|
||||
Write and Read all type tag with same slave id in hold register and coil, it should be success.
|
||||
[Template] Write and Read a ${tag} named ${tag_name} from ${node}, using ${check} to check the ${value}, it will be success.
|
||||
${hold_int16} hold_int16 ${modbus_tcp_node} Compare Tag Value As Int 120
|
||||
${hold_uint16} hold_uint16 ${modbus_tcp_node} Compare Tag Value As Int 65535
|
||||
${hold_int32} hold_int32 ${modbus_tcp_node} Compare Tag Value As Int 77889912
|
||||
${hold_uint32} hold_uint32 ${modbus_tcp_node} Compare Tag Value As Int 88991232
|
||||
${hold_float} hold_float ${modbus_tcp_node} Compare Tag Value As Float 12.34
|
||||
${hold_string} hold_string ${modbus_tcp_node} Compare Tag Value As Strings "abc123"
|
||||
${hold_int16} hold_int16 ${modbus_node} Compare Tag Value As Int 120
|
||||
${hold_uint16} hold_uint16 ${modbus_node} Compare Tag Value As Int 65535
|
||||
${hold_int32} hold_int32 ${modbus_node} Compare Tag Value As Int 77889912
|
||||
${hold_uint32} hold_uint32 ${modbus_node} Compare Tag Value As Int 88991232
|
||||
${hold_float} hold_float ${modbus_node} Compare Tag Value As Float 12.34
|
||||
${hold_string} hold_string ${modbus_node} Compare Tag Value As Strings "abc123"
|
||||
|
||||
${coil_bit_1} coil_bit_1 ${modbus_tcp_node} Compare Tag Value As Int 1
|
||||
${coil_bit_2} coil_bit_2 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${coil_bit_3} coil_bit_3 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${coil_bit_4} coil_bit_4 ${modbus_tcp_node} Compare Tag Value As Int 1
|
||||
${coil_bit_5} coil_bit_5 ${modbus_tcp_node} Compare Tag Value As Int 1
|
||||
${coil_bit_1} coil_bit_1 ${modbus_node} Compare Tag Value As Int 1
|
||||
${coil_bit_2} coil_bit_2 ${modbus_node} Compare Tag Value As Int 0
|
||||
${coil_bit_3} coil_bit_3 ${modbus_node} Compare Tag Value As Int 0
|
||||
${coil_bit_4} coil_bit_4 ${modbus_node} Compare Tag Value As Int 1
|
||||
${coil_bit_5} coil_bit_5 ${modbus_node} Compare Tag Value As Int 1
|
||||
|
||||
Read all type tag with same slave id in input register and input, it should be success.
|
||||
[Template] Read a ${tag} named ${tag_name} from ${node}, using ${check} to check the ${value}, it will be success.
|
||||
${input_register_int16} input_register_int16 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${input_register_uint16} input_register_uint16 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${input_register_int32} input_register_int32 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${input_register_uint32} input_register_uint32 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${input_register_float} input_register_float ${modbus_tcp_node} Compare Tag Value As Float 0
|
||||
${input_register_string} input_register_string ${modbus_tcp_node} Compare Tag Value As Strings ""
|
||||
${input_register_int16} input_register_int16 ${modbus_node} Compare Tag Value As Int 0
|
||||
${input_register_uint16} input_register_uint16 ${modbus_node} Compare Tag Value As Int 0
|
||||
${input_register_int32} input_register_int32 ${modbus_node} Compare Tag Value As Int 0
|
||||
${input_register_uint32} input_register_uint32 ${modbus_node} Compare Tag Value As Int 0
|
||||
${input_register_float} input_register_float ${modbus_node} Compare Tag Value As Float 0
|
||||
${input_register_string} input_register_string ${modbus_node} Compare Tag Value As Strings ""
|
||||
|
||||
${input_bit_1} input_bit_1 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${input_bit_2} input_bit_2 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${input_bit_3} input_bit_3 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${input_bit_4} input_bit_4 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${input_bit_5} input_bit_5 ${modbus_tcp_node} Compare Tag Value As Int 0
|
||||
${input_bit_1} input_bit_1 ${modbus_node} Compare Tag Value As Int 0
|
||||
${input_bit_2} input_bit_2 ${modbus_node} Compare Tag Value As Int 0
|
||||
${input_bit_3} input_bit_3 ${modbus_node} Compare Tag Value As Int 0
|
||||
${input_bit_4} input_bit_4 ${modbus_node} Compare Tag Value As Int 0
|
||||
${input_bit_5} input_bit_5 ${modbus_node} Compare Tag Value As Int 0
|
||||
|
||||
Read some tags at time, it will be success.
|
||||
[Template] Read some ${tags} from ${node}, it will be success.
|
||||
${input_register_int16},${input_register_uint16},${input_register_int32},${input_register_uint32},${input_register_float},${input_register_string},${input_register_bit} ${modbus_tcp_node}
|
||||
${hold_int16},${hold_uint16},${hold_int32},${hold_uint32},${hold_float},${hold_string},${hold_bit} ${modbus_tcp_node}
|
||||
${coil_bit_1},${coil_bit_2},${coil_bit_3},${coil_bit_4},${coil_bit_5} ${modbus_tcp_node}
|
||||
${input_bit_1},${input_bit_2},${input_bit_3},${input_bit_4},${input_bit_5} ${modbus_tcp_node}
|
||||
${input_register_tags}= Create List ${input_register_int16} ${input_register_uint16} ${input_register_int32} ${input_register_uint32} ${input_register_float} ${input_register_string} ${input_register_bit}
|
||||
Read some ${input_register_tags} from ${modbus_node}, it will be success.
|
||||
|
||||
${hold_tags}= Create List ${hold_int16} ${hold_uint16} ${hold_int32} ${hold_uint32} ${hold_float} ${hold_string} ${hold_bit}
|
||||
Read some ${hold_tags} from ${modbus_node}, it will be success.
|
||||
|
||||
${coil_tags}= Create List ${coil_bit_1} ${coil_bit_2} ${coil_bit_3} ${coil_bit_4} ${coil_bit_5}
|
||||
Read some ${coil_tags} from ${modbus_node}, it will be success.
|
||||
|
||||
${input_tags}= Create List ${input_bit_1} ${input_bit_2} ${input_bit_3} ${input_bit_4} ${input_bit_5}
|
||||
Read some ${input_tags} from ${modbus_node}, it will be success.
|
||||
|
||||
Read static tag, it should be success.
|
||||
[Template] Read a ${tag} named ${tag_name} from ${node}, using ${check} to check the ${value}, it will be success.
|
||||
${hold_int16_static} hold_int16 ${modbus_node} Compare Tag Value As Int 1
|
||||
|
||||
Write a static tag, it should be success.
|
||||
[Template] Write and Read a ${tag} named ${tag_name} from ${node}, using ${check} to check the ${value}, it will be success.
|
||||
${hold_int16_static} hold_int16 ${modbus_node} Compare Tag Value As Int 2
|
||||
|
||||
Write and read a tag with same name and same address that in different groups, it should be success.
|
||||
${groups}= Create List group-1 group-2 group-3
|
||||
Write and read a ${hold_int16} with same hold_int16 and same address in different ${groups} that from ${modbus_tcp_node}, using Compare Tag Value As Int to check the 2, it will be success.
|
||||
Write and read a ${hold_int16} with same hold_int16 and same address in different ${groups} that from ${modbus_node}, using Compare Tag Value As Int to check the 2, it will be success.
|
||||
|
||||
Write and read a tag with same name but different address that in different groups, it should be success.
|
||||
${groups}= Create List group-1 group-2 group-3
|
||||
Write and read ${hold_int16} ${hold_int16_address_update} with same hold_int16 but different address in different ${groups} that from ${modbus_tcp_node}, using Compare Tag Value As Int to check the 2, it will be success.
|
||||
Write and read ${hold_int16} ${hold_int16_address_update} with same hold_int16 but different address in different ${groups} that from ${modbus_node}, using Compare Tag Value As Int to check the 2, it will be success.
|
||||
|
||||
Update a tag with right address and types and attribute, it will be success
|
||||
[Template] Update a ${tag} by a ${tag_update} named ${tag_name} from ${node} , it can read and write, using ${check} to check the ${value}, it will be success.
|
||||
${hold_int16} ${hold_int16_address_update} hold_int16 ${modbus_tcp_node} Compare Tag Value As Int 120
|
||||
${hold_int16} ${hold_int16_type_update} hold_int16 ${modbus_tcp_node} Compare Tag Value As Int 120
|
||||
${hold_int16} ${hold_int16_address_update} hold_int16 ${modbus_node} Compare Tag Value As Int 120
|
||||
${hold_int16} ${hold_int16_type_update} hold_int16 ${modbus_node} Compare Tag Value As Int 120
|
||||
|
||||
Update a tag with unmatch address and types and attribute, it should be failure.
|
||||
[Template] Update a ${tag} by a ${tag_update} with the unmatch settings from ${node} , it will be failure and return ${resp_status} and ${error_code}.
|
||||
${input_bit_1} ${input_bit_1_attribute_unmatch} ${modbus_tcp_node} 200 ${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT}
|
||||
${input_bit_1} ${input_bit_1_type_unmatch} ${modbus_tcp_node} 200 ${NEU_ERR_TAG_TYPE_NOT_SUPPORT}
|
||||
${input_bit_1} ${input_bit_1_name_wrong} ${modbus_tcp_node} 200 ${NEU_ERR_TAG_NOT_EXIST}
|
||||
${input_bit_1} ${input_bit_1_attribute_unmatch} ${modbus_node} 200 ${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT}
|
||||
${input_bit_1} ${input_bit_1_type_unmatch} ${modbus_node} 200 ${NEU_ERR_TAG_TYPE_NOT_SUPPORT}
|
||||
${input_bit_1} ${input_bit_1_name_wrong} ${modbus_node} 200 ${NEU_ERR_TAG_NOT_EXIST}
|
||||
|
||||
Update to be a static, it will be success
|
||||
[Template] Update a ${tag} by a ${tag_update} named ${tag_name} from ${node} , it can read and write, using ${check} to check the ${value}, it will be success.
|
||||
${hold_int16} ${hold_int16_static} hold_int16 ${modbus_node} Compare Tag Value As Int 42
|
||||
|
||||
Write a value to a tag that don't exit in plc or neuron, it will be failure.
|
||||
[Template] Write a ${value} to a ${tag} with named ${tag_name} that don't exist in neuron or plc from ${node}, it will be failure.
|
||||
12 ${input_bit_1} input ${modbus_tcp_node}
|
||||
12 ${input_bit_1} input ${modbus_node}
|
||||
|
||||
Write value to a tag without write attribute, it will be failure.
|
||||
[Template] Write a ${value} to a ${tag} named ${tag_name} that without write attribute from ${node}, it will be failure.
|
||||
1 ${input_bit_1} input_bit_1 ${modbus_tcp_node}
|
||||
1 ${input_bit_1} input_bit_1 ${modbus_node}
|
||||
|
||||
Write and read a value to a tag when the node is stoped, it will be failure.
|
||||
[Template] Write and read a ${value} to a ${tag} named ${tag_name} when the ${node} is stoped, it will be failure.
|
||||
1 ${hold_int16} hold_int16 ${modbus_tcp_node}
|
||||
1 ${hold_int16} hold_int16 ${modbus_node}
|
||||
|
||||
*** Keywords ***
|
||||
Modbus Test Setup
|
||||
@@ -169,17 +182,17 @@ Modbus Test Setup
|
||||
|
||||
Start Neuronx
|
||||
|
||||
${res}= Add Node ${modbus_tcp_node} ${PLUGIN-MODBUS-TCP}
|
||||
${res}= Add Node ${modbus_node} ${PLUGIN-MODBUS-TCP}
|
||||
Check Response Status ${res} 200
|
||||
|
||||
${res}= Node Setting ${modbus_tcp_node} ${MODBUS_TCP_CONFIG}
|
||||
${res}= Node Setting ${modbus_node} ${MODBUS_TCP_CONFIG}
|
||||
Check Response Status ${res} 200
|
||||
|
||||
${state}= Get Node State ${modbus_tcp_node}
|
||||
${state}= Get Node State ${modbus_node}
|
||||
Should Be Equal As Integers ${state}[running] ${NODE_STATE_RUNNING}
|
||||
# Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_CONNECTED}
|
||||
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_DISCONNECTED}
|
||||
|
||||
Modbus Test Teardown
|
||||
Del Node ${modbus_tcp_node}
|
||||
Del Node ${modbus_node}
|
||||
Stop Neuronx
|
||||
Terminate All Processes kill=false
|
||||
|
||||
@@ -72,8 +72,8 @@ Get the deleted adapter after stopping and restarting Neuron, it should return f
|
||||
Get the setted adapters information after stopping and restarting Neuron, it should return the correct information
|
||||
${process} = Neuron Start Running
|
||||
|
||||
Node Setting ${modbus-tcp-1} {"host": "127.0.0.1", "port": 502, "timeout": 3000, "connection_mode": 0, "interval": 20}
|
||||
Node Setting ${modbus-tcp-2} {"host": "127.0.0.1", "port": 502, "timeout": 3000, "connection_mode": 0, "interval": 20}
|
||||
Node Setting ${modbus-tcp-1} {"host": "127.0.0.1", "port": 502, "timeout": 3000}
|
||||
Node Setting ${modbus-tcp-2} {"host": "127.0.0.1", "port": 502, "timeout": 3000}
|
||||
Node Setting ${mqtt-1} {"client-id":"123456", "upload-topic":"/neuron/mqtt-1/upload", "heartbeat-topic": "/neuron/mqtt-1/heartbeat","format": 0,"cache-mem-size": 10,"cache-disk-size": 10,"ssl":false,"host":"127.0.0.1","port":1883,"username":"admin","password":"0000","ca":"", "cert":"", "key":"", "keypass":""}
|
||||
|
||||
Neuron Stop Running ${process}
|
||||
@@ -117,7 +117,7 @@ Get the setted adapters information after stopping and restarting Neuron, it sho
|
||||
Get the updated adapters settings information after stopping and restarting Neuron, it should return the correct information
|
||||
${process} = Neuron Start Running
|
||||
|
||||
Node Setting ${modbus-tcp-2} {"host": "127.0.0.1", "port": 502, "timeout": 3000, "connection_mode": 0, "interval": 20}
|
||||
Node Setting ${modbus-tcp-2} {"host": "127.0.0.1", "port": 502, "timeout": 3000}
|
||||
|
||||
Neuron Stop Running ${process}
|
||||
${process} = Neuron Start Running
|
||||
|
||||
@@ -3,7 +3,7 @@ Library REST http://127.0.0.1:7000
|
||||
Resource common.resource
|
||||
|
||||
*** Variables ***
|
||||
${PLUGIN-MODBUS-TCP} Modbus TCP
|
||||
${PLUGIN-MODBUS-TCP} Modbus TCP community
|
||||
${PLUGIN-MQTT} MQTT
|
||||
${PLUGIN-EKUIPER} eKuiper
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Resource simulator.resource
|
||||
${test_data_dir} ft/data
|
||||
|
||||
|
||||
${PLUGIN_MODBUS_TCP} Modbus TCP
|
||||
${PLUGIN_MODBUS_TCP} Modbus TCP community
|
||||
${PLUGIN_MQTT} MQTT
|
||||
|
||||
${MQTT_CMD_NONE}
|
||||
@@ -39,7 +39,7 @@ ${MQTT_CONFIG} {"client-id": "${MQTT_CLIENTID}", "u
|
||||
... "ssl": false, "host": "${MQTT_CONFIG_HOST}", "port": ${MQTT_CONFIG_PORT},
|
||||
... "username": "", "password": "", "ca":"", "cert":"", "key":"", "keypass":""}
|
||||
|
||||
${MODBUS_TCP_CONFIG} {"host": "127.0.0.1", "port": 60502, "connection_mode": 0, "timeout": 3000, "interval": 20}
|
||||
${MODBUS_TCP_CONFIG} {"host": "127.0.0.1", "port": 60502, "timeout": 3000}
|
||||
|
||||
*** Variables ***
|
||||
${neuron_process}
|
||||
|
||||
@@ -70,9 +70,13 @@ Read some ${tags} from ${node}, it will be success.
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res}= Add Tags ${node} group ${tags}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
Log ${tags}
|
||||
|
||||
FOR ${tag} IN @{tags}
|
||||
${res}= Add Tags ${node} group ${tag}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
END
|
||||
|
||||
Sleep 290ms
|
||||
${res}= Read Tags ${node} group
|
||||
@@ -234,7 +238,7 @@ Write a ${value} to a ${tag} with named ${tag_name} that don't exist in neuron o
|
||||
|
||||
[Teardown] Del Group ${node} group
|
||||
|
||||
Read a ${tag} with named ${tag_name} that don't exist in plc form ${node}, it will be failure ${error}.
|
||||
Read a ${tag} with named ${tag_name} that don't exist in plc form ${node}, it will be failure.
|
||||
[Tags] Driver 15
|
||||
|
||||
${res}= Add Group ${node} group 100
|
||||
@@ -248,7 +252,7 @@ Read a ${tag} with named ${tag_name} that don't exist in plc form ${node}, it wi
|
||||
Sleep 290ms
|
||||
${res}= Read Tags ${node} group
|
||||
Check Response Status ${res} 200
|
||||
Check Tag Error As Int ${res}[tags] ${tag_name} ${error}
|
||||
Check Tag Error As Int ${res} ${tag_name} ${NEU_ERR_TAG_NOT_EXIST}
|
||||
|
||||
[Teardown] Del Group ${node} group
|
||||
|
||||
|
||||
@@ -71,4 +71,7 @@ ${NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED} 3008
|
||||
${NEU_ERR_PLUGIN_PROTOCOL_DECODE_FAILURE} 3009
|
||||
${NEU_ERR_PLUGIN_NOT_RUNNING} 3010
|
||||
${NEU_ERR_PLUGIN_TAG_NOT_READY} 3011
|
||||
${NEU_ERR_PLUGIN_PACKET_OUT_OF_ORDER} 3012
|
||||
${NEU_ERR_PLUGIN_PACKET_OUT_OF_ORDER} 3012
|
||||
${NEU_ERR_PLUGIN_NAME_TOO_LONG} 3013
|
||||
${NEU_ERR_PLUGIN_NOT_FOUND} 3014
|
||||
${NEU_ERR_PLUGIN_DEVICE_NOT_RESPONSE} 3015
|
||||
@@ -207,8 +207,8 @@ typedef struct neu_resp_error {
|
||||
} neu_resp_error_t;
|
||||
|
||||
typedef struct {
|
||||
char node[NEU_NODE_NAME_LEN];
|
||||
bool auto_start;
|
||||
char node[NEU_NODE_NAME_LEN];
|
||||
neu_node_running_state_e state;
|
||||
} neu_req_node_init_t, neu_req_node_uninit_t, neu_resp_node_uninit_t;
|
||||
|
||||
typedef struct neu_req_add_plugin {
|
||||
|
||||
@@ -114,6 +114,8 @@ int neu_mqtt_client_subscribe(neu_mqtt_client_t *client, neu_mqtt_qos_e qos,
|
||||
const char *topic, void *data,
|
||||
neu_mqtt_client_subscribe_cb_t cb);
|
||||
|
||||
int neu_mqtt_client_unsubscribe(neu_mqtt_client_t *client, const char *topic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -113,6 +113,7 @@ typedef enum {
|
||||
NEU_ERR_PLUGIN_PACKET_OUT_OF_ORDER = 3012,
|
||||
NEU_ERR_PLUGIN_NAME_TOO_LONG = 3013,
|
||||
NEU_ERR_PLUGIN_NOT_FOUND = 3014,
|
||||
NEU_ERR_PLUGIN_DEVICE_NOT_RESPONSE = 3015,
|
||||
|
||||
NEU_ERR_MQTT_FAILURE = 4000,
|
||||
NEU_ERR_MQTT_NO_CERTFILESET = 4001,
|
||||
@@ -132,7 +133,7 @@ typedef enum {
|
||||
NEU_ERR_MQTT_SUSPENDED = 4015,
|
||||
NEU_ERR_MQTT_PUBLISH_OVER_LENGTH = 4016,
|
||||
|
||||
NEU_ERR_FILE_TOO_LONG = 4100,
|
||||
NEU_ERR_STRING_TOO_LONG = 4100,
|
||||
NEU_ERR_FILE_OPEN_FAILURE = 4101,
|
||||
NEU_ERR_FILE_READ_FAILURE = 4102,
|
||||
NEU_ERR_FILE_WRITE_FAILURE = 4103,
|
||||
|
||||
@@ -95,6 +95,8 @@ int neu_persister_create(const char *schema_dir);
|
||||
void neu_persister_destroy();
|
||||
|
||||
sqlite3 *neu_persister_get_db();
|
||||
int neu_persister_node_count();
|
||||
int neu_persister_tag_count();
|
||||
|
||||
/**
|
||||
* Persist nodes.
|
||||
|
||||
+203
-1
@@ -28,6 +28,7 @@ extern "C" {
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {
|
||||
NEU_TYPE_INT8 = 1,
|
||||
@@ -109,7 +110,80 @@ typedef union {
|
||||
double d64;
|
||||
char str[NEU_VALUE_SIZE];
|
||||
uint8_t bytes[NEU_VALUE_SIZE];
|
||||
} neu_value_u;
|
||||
} __attribute__((packed)) neu_value_u;
|
||||
|
||||
static inline char *neu_value_str(neu_type_e type, neu_value_u value)
|
||||
{
|
||||
static __thread char str[32] = { 0 };
|
||||
|
||||
switch (type) {
|
||||
case NEU_TYPE_INT8:
|
||||
snprintf(str, sizeof(str), "type: %s, value: %i", neu_type_string(type),
|
||||
value.i8);
|
||||
break;
|
||||
case NEU_TYPE_UINT8:
|
||||
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
|
||||
value.u8);
|
||||
break;
|
||||
case NEU_TYPE_INT16:
|
||||
snprintf(str, sizeof(str), "type: %s, value: %i", neu_type_string(type),
|
||||
value.i16);
|
||||
break;
|
||||
case NEU_TYPE_WORD:
|
||||
case NEU_TYPE_UINT16:
|
||||
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
|
||||
value.u16);
|
||||
break;
|
||||
case NEU_TYPE_INT32:
|
||||
snprintf(str, sizeof(str), "type: %s, value: %i", neu_type_string(type),
|
||||
value.i32);
|
||||
break;
|
||||
case NEU_TYPE_DWORD:
|
||||
case NEU_TYPE_UINT32:
|
||||
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
|
||||
value.u32);
|
||||
break;
|
||||
case NEU_TYPE_INT64: {
|
||||
long long int i = value.i64;
|
||||
snprintf(str, sizeof(str), "type: %s, value: %lld",
|
||||
neu_type_string(type), i);
|
||||
break;
|
||||
}
|
||||
case NEU_TYPE_LWORD:
|
||||
case NEU_TYPE_UINT64: {
|
||||
long long unsigned int i = value.u64;
|
||||
snprintf(str, sizeof(str), "type: %s, value: %llu",
|
||||
neu_type_string(type), i);
|
||||
break;
|
||||
}
|
||||
case NEU_TYPE_FLOAT:
|
||||
snprintf(str, sizeof(str), "type: %s, value: %f", neu_type_string(type),
|
||||
value.f32);
|
||||
break;
|
||||
case NEU_TYPE_DOUBLE:
|
||||
snprintf(str, sizeof(str), "type: %s, value: %f", neu_type_string(type),
|
||||
value.d64);
|
||||
break;
|
||||
case NEU_TYPE_BIT:
|
||||
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
|
||||
value.u8);
|
||||
break;
|
||||
case NEU_TYPE_BOOL:
|
||||
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
|
||||
value.boolean);
|
||||
break;
|
||||
case NEU_TYPE_STRING: {
|
||||
snprintf(str, sizeof(str), "type: %s, value: %c%c%c",
|
||||
neu_type_string(type), value.str[0], value.str[1],
|
||||
value.str[2]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
neu_type_e type;
|
||||
@@ -443,6 +517,134 @@ static inline void neu_htons_p(uint16_t *pu)
|
||||
neu_ntohs_p(pu);
|
||||
}
|
||||
|
||||
static inline uint16_t neu_get_u16(uint8_t *bytes)
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int16_t neu_get_i16(uint8_t *bytes)
|
||||
{
|
||||
int16_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t neu_get_u32(uint8_t *bytes)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int32_t neu_get_i32(uint8_t *bytes)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline float neu_get_f32(uint8_t *bytes)
|
||||
{
|
||||
float ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_get_u64(uint8_t *bytes)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
t[4] = bytes[4];
|
||||
t[5] = bytes[5];
|
||||
t[6] = bytes[6];
|
||||
t[7] = bytes[7];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int64_t neu_get_i64(uint8_t *bytes)
|
||||
{
|
||||
int64_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
t[4] = bytes[4];
|
||||
t[5] = bytes[5];
|
||||
t[6] = bytes[6];
|
||||
t[7] = bytes[7];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline double neu_get_f64(uint8_t *bytes)
|
||||
{
|
||||
double ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
t[4] = bytes[4];
|
||||
t[5] = bytes[5];
|
||||
t[6] = bytes[6];
|
||||
t[7] = bytes[7];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -192,4 +192,16 @@ neu_protocol_unpack_buf_used_size(neu_protocol_unpack_buf_t *buf)
|
||||
return buf->offset;
|
||||
}
|
||||
|
||||
inline static void
|
||||
neu_protocol_unpack_buf_use_all(neu_protocol_unpack_buf_t *buf)
|
||||
{
|
||||
buf->offset = buf->size;
|
||||
}
|
||||
|
||||
inline static uint16_t
|
||||
neu_protocol_unpack_buf_size(neu_protocol_unpack_buf_t *buf)
|
||||
{
|
||||
return buf->size;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@ extern "C" {
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
static inline int64_t neu_time_ms()
|
||||
{
|
||||
@@ -34,6 +35,15 @@ static inline int64_t neu_time_ms()
|
||||
return (int64_t) tv.tv_sec * 1000 + (int64_t) tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
static inline void neu_msleep(unsigned msec)
|
||||
{
|
||||
struct timespec tv = {
|
||||
.tv_sec = msec / 1000,
|
||||
.tv_nsec = (msec % 1000) * 1000000,
|
||||
};
|
||||
nanosleep(&tv, NULL);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'MQTT'
|
||||
WHERE plugin_name = 'mqtt';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'eKuiper'
|
||||
WHERE plugin_name = 'ekuiper';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'SparkPlugB'
|
||||
WHERE plugin_name = 'sparkplugb';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Beckhoff ADS'
|
||||
WHERE plugin_name = 'ads';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Modbus TCP community'
|
||||
WHERE plugin_name = 'modbus-tcp';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Modbus RTU'
|
||||
WHERE plugin_name = 'modbus-rtu';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Modbus TCP'
|
||||
WHERE plugin_name = 'modbus-plus-tcp';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Modbus TCP QH'
|
||||
WHERE plugin_name = 'modbus-qh-tcp';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Siemens S7 ISOTCP'
|
||||
WHERE plugin_name = 's7comm';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Siemens S7 ISOTCP for 300/400'
|
||||
WHERE plugin_name = 's7comm_for_300';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'OPC UA'
|
||||
WHERE plugin_name = 'opcua';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Omron FINS TCP'
|
||||
WHERE plugin_name = 'fins';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Mitsubishi 3E'
|
||||
WHERE plugin_name = 'qna3e';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Mitsubishi 1E'
|
||||
WHERE plugin_name = 'a1e';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'IEC60870-5-104'
|
||||
WHERE plugin_name = 'iec104';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'BACnet/IP'
|
||||
WHERE plugin_name = 'bacnet';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'KNXnet/IP'
|
||||
WHERE plugin_name = 'knx';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'DLT645-2007'
|
||||
WHERE plugin_name = 'dlt645';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'NON A11'
|
||||
WHERE plugin_name = 'nona11';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'EtherNet/IP(CIP)'
|
||||
WHERE plugin_name = 'EtherNet-IP';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Fanuc Focas Ethernet'
|
||||
WHERE plugin_name = 'focas';
|
||||
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'File'
|
||||
WHERE plugin_name = 'file';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
-- for backward compatibility with version 2.3,
|
||||
-- migrate MQTT plugin upload-topic to subscription parameters.
|
||||
WITH
|
||||
topics AS (
|
||||
SELECT
|
||||
name AS app,
|
||||
json_extract(json(setting), '$.params.upload-topic') AS topic
|
||||
FROM
|
||||
nodes
|
||||
JOIN settings
|
||||
WHERE
|
||||
name = node_name
|
||||
AND plugin_name = 'MQTT'
|
||||
)
|
||||
UPDATE
|
||||
subscriptions
|
||||
SET
|
||||
params = (
|
||||
SELECT
|
||||
json_object('params', json_object('topic', topic)) AS params
|
||||
FROM
|
||||
topics
|
||||
WHERE
|
||||
topics.app = subscriptions.app_name
|
||||
AND topics.topic NOT NULL
|
||||
)
|
||||
WHERE
|
||||
EXISTS (
|
||||
SELECT
|
||||
topic
|
||||
FROM
|
||||
topics
|
||||
WHERE
|
||||
topics.app = subscriptions.app_name
|
||||
AND topics.topic NOT NULL
|
||||
AND subscriptions.params IS NULL
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
@@ -34,8 +34,8 @@ static neu_plugin_t *ekuiper_plugin_open(void)
|
||||
|
||||
neu_plugin_common_init(&plugin->common);
|
||||
|
||||
zlog_info(neuron, "success to create plugin: %s",
|
||||
neu_plugin_module.module_name);
|
||||
zlog_notice(neuron, "success to create plugin: %s",
|
||||
neu_plugin_module.module_name);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ static int ekuiper_plugin_close(neu_plugin_t *plugin)
|
||||
int rv = 0;
|
||||
|
||||
free(plugin);
|
||||
zlog_info(neuron, "success to free plugin: %s",
|
||||
neu_plugin_module.module_name);
|
||||
zlog_notice(neuron, "success to free plugin: %s",
|
||||
neu_plugin_module.module_name);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ static int ekuiper_plugin_init(neu_plugin_t *plugin)
|
||||
|
||||
plugin->recv_aio = recv_aio;
|
||||
|
||||
plog_info(plugin, "plugin initialized");
|
||||
plog_notice(plugin, "plugin initialized");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ static int ekuiper_plugin_uninit(neu_plugin_t *plugin)
|
||||
free(plugin->host);
|
||||
free(plugin->url);
|
||||
|
||||
plog_info(plugin, "plugin uninitialized");
|
||||
plog_notice(plugin, "plugin uninitialized");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ static int parse_config(neu_plugin_t *plugin, const char *setting,
|
||||
*host_p = host.v.val_str;
|
||||
*port_p = port.v.val_int;
|
||||
|
||||
plog_info(plugin, "config host:%s port:%" PRIu16, *host_p, *port_p);
|
||||
plog_notice(plugin, "config host:%s port:%" PRIu16, *host_p, *port_p);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -201,7 +201,7 @@ static int ekuiper_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
goto error;
|
||||
}
|
||||
|
||||
plog_info(plugin, "config success");
|
||||
plog_notice(plugin, "config success");
|
||||
|
||||
free(plugin->host);
|
||||
plugin->host = host;
|
||||
@@ -220,7 +220,7 @@ static int ekuiper_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
error:
|
||||
free(url);
|
||||
free(host);
|
||||
plog_info(plugin, "config failure");
|
||||
plog_error(plugin, "config failure");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ static int ekuiper_plugin_request(neu_plugin_t * plugin,
|
||||
switch (header->type) {
|
||||
case NEU_RESP_ERROR: {
|
||||
neu_resp_error_t *error = (neu_resp_error_t *) data;
|
||||
plog_info(plugin, "receive resp errcode: %d", error->error);
|
||||
plog_debug(plugin, "receive resp errcode: %d", error->error);
|
||||
break;
|
||||
}
|
||||
case NEU_REQRESP_TRANS_DATA: {
|
||||
@@ -259,7 +259,7 @@ static int ekuiper_plugin_request(neu_plugin_t * plugin,
|
||||
case NEU_REQ_UNSUBSCRIBE_GROUP:
|
||||
break;
|
||||
default:
|
||||
plog_notice(plugin, "unsupported request type: %d", header->type);
|
||||
plog_warn(plugin, "unsupported request type: %d", header->type);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"type": "int",
|
||||
"default": 512,
|
||||
"valid": {
|
||||
"min": 1
|
||||
"min": 1,
|
||||
"max": 512
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
-10
@@ -74,6 +74,9 @@ static neu_plugin_t *driver_open(void)
|
||||
|
||||
static int driver_close(neu_plugin_t *plugin)
|
||||
{
|
||||
plog_notice(plugin, "close and free `%s` plugin success",
|
||||
plugin->common.name);
|
||||
|
||||
free(plugin);
|
||||
|
||||
return 0;
|
||||
@@ -81,8 +84,9 @@ static int driver_close(neu_plugin_t *plugin)
|
||||
|
||||
static int driver_init(neu_plugin_t *plugin)
|
||||
{
|
||||
plugin->events = neu_event_new();
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_CONNECTED;
|
||||
plugin->events = neu_event_new();
|
||||
|
||||
plog_notice(plugin, "initialize `%s` plugin success", plugin->common.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -90,21 +94,27 @@ static int driver_init(neu_plugin_t *plugin)
|
||||
static int driver_uninit(neu_plugin_t *plugin)
|
||||
{
|
||||
neu_event_close(plugin->events);
|
||||
plog_info(plugin, "node; file uininit ok");
|
||||
|
||||
plog_notice(plugin, "uninitialize `%s` plugin success",
|
||||
plugin->common.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_start(neu_plugin_t *plugin)
|
||||
{
|
||||
(void) plugin;
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_CONNECTED;
|
||||
|
||||
plog_notice(plugin, "start `%s` plugin success", plugin->common.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_stop(neu_plugin_t *plugin)
|
||||
{
|
||||
(void) plugin;
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
|
||||
|
||||
plog_notice(plugin, "stop `%s` plugin success", plugin->common.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -116,12 +126,13 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
|
||||
int ret = neu_parse_param((char *) config, &err_param, 1, &file_length);
|
||||
if (ret != 0) {
|
||||
plog_warn(plugin, "config:%s, decode error: %s", config, err_param);
|
||||
plog_error(plugin, "config:%s, decode error: %s", config, err_param);
|
||||
free(err_param);
|
||||
return -1;
|
||||
}
|
||||
|
||||
plugin->file_length = file_length.v.val_int;
|
||||
plugin->file_length = file_length.v.val_int;
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_CONNECTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -138,8 +149,8 @@ static int driver_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
|
||||
|
||||
static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag)
|
||||
{
|
||||
plog_debug(plugin, "validate tag success, name:%s, address:%s,type:%d ",
|
||||
tag->name, tag->address, tag->type);
|
||||
plog_notice(plugin, "validate tag success, name:%s, address:%s, type:%d ",
|
||||
tag->name, tag->address, tag->type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -152,5 +163,10 @@ static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
|
||||
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value)
|
||||
{
|
||||
return file_write(plugin, req, tag, value);
|
||||
int ret = file_write(plugin, req, tag, value);
|
||||
|
||||
plog_notice(plugin, "write response, ret: %d, tag_name: %s, type: %d", ret,
|
||||
tag->name, tag->type);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+46
-17
@@ -60,34 +60,50 @@ int file_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
|
||||
dvalue.value.i32 = NEU_ERR_FILE_NOT_EXIST;
|
||||
goto dvalue_result;
|
||||
}
|
||||
|
||||
if ((f = fopen(tag->address, "rb+")) == NULL) {
|
||||
nlog_error("open file:%s", tag->address);
|
||||
nlog_warn("fail open to read and write file: %s", tag->address);
|
||||
dvalue.type = NEU_TYPE_ERROR;
|
||||
dvalue.value.i32 = NEU_ERR_FILE_OPEN_FAILURE;
|
||||
goto dvalue_result;
|
||||
}
|
||||
|
||||
int ret = fread(buf, sizeof(char), length, f);
|
||||
if (ret == 0) {
|
||||
nlog_error("read file failed:%s", tag->address);
|
||||
fseek(f, 0, SEEK_END);
|
||||
int size = ftell(f);
|
||||
if (size >= length) {
|
||||
nlog_warn(
|
||||
"the file length exceeds the set value, file: %s, length: %d",
|
||||
tag->address, size);
|
||||
dvalue.type = NEU_TYPE_ERROR;
|
||||
dvalue.value.i32 = NEU_ERR_FILE_READ_FAILURE;
|
||||
dvalue.value.i32 = NEU_ERR_STRING_TOO_LONG;
|
||||
|
||||
fclose(f);
|
||||
goto dvalue_result;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
int size = ftell(f);
|
||||
if (size > length) {
|
||||
fseek(f, 0, SEEK_SET);
|
||||
int ret = fread(buf, sizeof(char), length, f);
|
||||
if (ret == 0) {
|
||||
nlog_warn("read file failed:%s", tag->address);
|
||||
dvalue.type = NEU_TYPE_ERROR;
|
||||
dvalue.value.i32 = NEU_ERR_FILE_TOO_LONG;
|
||||
dvalue.value.i32 = NEU_ERR_FILE_READ_FAILURE;
|
||||
|
||||
fclose(f);
|
||||
goto dvalue_result;
|
||||
} else if (ret >= NEU_VALUE_SIZE) {
|
||||
nlog_warn("the file length exceeds the maximum, file: %s, ret: %d",
|
||||
tag->address, ret);
|
||||
dvalue.type = NEU_TYPE_ERROR;
|
||||
dvalue.value.i32 = NEU_ERR_STRING_TOO_LONG;
|
||||
|
||||
fclose(f);
|
||||
goto dvalue_result;
|
||||
}
|
||||
|
||||
dvalue.type = NEU_TYPE_STRING;
|
||||
strncpy(dvalue.value.str, buf, strlen(buf));
|
||||
fclose(f);
|
||||
|
||||
rtt = 1;
|
||||
fclose(f);
|
||||
|
||||
dvalue_result:
|
||||
plugin->common.adapter_callbacks->driver.update(
|
||||
@@ -116,19 +132,32 @@ static void plugin_group_free(neu_plugin_group_t *pgp)
|
||||
int file_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value)
|
||||
{
|
||||
FILE *fp = fopen(tag->address, "w");
|
||||
int ret = 0;
|
||||
FILE *fp = NULL;
|
||||
int ret = 0;
|
||||
int length = strlen(value.str);
|
||||
|
||||
if (length >= NEU_VALUE_SIZE) {
|
||||
nlog_warn("write file exceeds the maximum value, file: %s, length: %d",
|
||||
tag->address, length);
|
||||
ret = NEU_ERR_STRING_TOO_LONG;
|
||||
|
||||
if (0 == fwrite(value.str, sizeof(char), strlen(value.str), fp)) {
|
||||
nlog_error("write file failed:%s", tag->address);
|
||||
ret = NEU_ERR_FILE_WRITE_FAILURE;
|
||||
goto dvalue_result;
|
||||
}
|
||||
|
||||
fp = fopen(tag->address, "w");
|
||||
|
||||
if (0 == fwrite(value.str, sizeof(char), strlen(value.str), fp)) {
|
||||
nlog_warn("write file failed: %s", tag->address);
|
||||
ret = NEU_ERR_FILE_WRITE_FAILURE;
|
||||
|
||||
fclose(fp);
|
||||
goto dvalue_result;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
neu_datatag_string_ltoh(value.str, strlen(value.str));
|
||||
|
||||
dvalue_result:
|
||||
fclose(fp);
|
||||
plugin->common.adapter_callbacks->driver.write_response(
|
||||
plugin->common.adapter, req, ret);
|
||||
|
||||
|
||||
@@ -3,33 +3,13 @@ set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/plugins")
|
||||
set(MODBUS_SRC modbus.c modbus_point.c modbus_req.c modbus_stack.c)
|
||||
|
||||
set(CMAKE_BUILD_RPATH ./)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/plugins/modbus/modbus-tcp.json DESTINATION ${CMAKE_BINARY_DIR}/plugins/schema/)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/plugins/modbus/modbus-rtu.json DESTINATION ${CMAKE_BINARY_DIR}/plugins/schema/)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/plugins/modbus/modbus-qh-tcp.json DESTINATION ${CMAKE_BINARY_DIR}/plugins/schema/)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/plugins/modbus/modbus-tcp-community.json DESTINATION ${CMAKE_BINARY_DIR}/plugins/schema/)
|
||||
|
||||
# modbus rtu plugin
|
||||
set(MODBUS_RTU_PLUGIN plugin-modbus-rtu)
|
||||
set(MODBUS_RTU_PLUGIN_SOURCES modbus_rtu.c
|
||||
${MODBUS_SRC})
|
||||
add_library(${MODBUS_RTU_PLUGIN} SHARED)
|
||||
target_include_directories(${MODBUS_RTU_PLUGIN} PRIVATE ${CMAKE_SOURCE_DIR}/include/neuron)
|
||||
target_sources(${MODBUS_RTU_PLUGIN} PRIVATE ${MODBUS_RTU_PLUGIN_SOURCES})
|
||||
target_link_libraries(${MODBUS_RTU_PLUGIN} neuron-base)
|
||||
|
||||
# modbus tcp plugin
|
||||
set(MODBUS_TCP_PLUS_PLUGIN plugin-modbus-tcp)
|
||||
set(MODBUS_TCP_PLUS_PLUGIN_SOURCES modbus_tcp.c
|
||||
set(MODBUS_TCP_PLUGIN plugin-modbus-tcp-comm)
|
||||
set(MODBUS_TCP_PLUGIN_SOURCES modbus_tcp.c
|
||||
${MODBUS_SRC})
|
||||
add_library(${MODBUS_TCP_PLUS_PLUGIN} SHARED)
|
||||
target_include_directories(${MODBUS_TCP_PLUS_PLUGIN} PRIVATE ${CMAKE_SOURCE_DIR}/include/neuron)
|
||||
target_sources(${MODBUS_TCP_PLUS_PLUGIN} PRIVATE ${MODBUS_TCP_PLUS_PLUGIN_SOURCES})
|
||||
target_link_libraries(${MODBUS_TCP_PLUS_PLUGIN} neuron-base)
|
||||
|
||||
# modbus qh tcp plugin
|
||||
set(MODBUS_TCP_QH_PLUGIN plugin-modbus-qh-tcp)
|
||||
set(MODBUS_TCP_QH_PLUGIN_SOURCES modbus_qh_tcp.c
|
||||
${MODBUS_SRC})
|
||||
add_library(${MODBUS_TCP_QH_PLUGIN} SHARED)
|
||||
target_include_directories(${MODBUS_TCP_QH_PLUGIN} PRIVATE ${CMAKE_SOURCE_DIR}/include/neuron)
|
||||
target_sources(${MODBUS_TCP_QH_PLUGIN} PRIVATE ${MODBUS_TCP_QH_PLUGIN_SOURCES})
|
||||
target_link_libraries(${MODBUS_TCP_QH_PLUGIN} neuron-base)
|
||||
|
||||
add_library(${MODBUS_TCP_PLUGIN} SHARED)
|
||||
target_include_directories(${MODBUS_TCP_PLUGIN} PRIVATE ${CMAKE_SOURCE_DIR}/include/neuron)
|
||||
target_sources(${MODBUS_TCP_PLUGIN} PRIVATE ${MODBUS_TCP_PLUGIN_SOURCES})
|
||||
target_link_libraries(${MODBUS_TCP_PLUGIN} neuron-base)
|
||||
@@ -1,104 +0,0 @@
|
||||
{
|
||||
"tag_regex": [
|
||||
{
|
||||
"type": 3,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 5,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 6,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 8,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 10,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
"regex": "^[0-9]+!([0-1][0-9]+|[3-4][0-9]+\\.([0-9]|[0-1][0-5]))$"
|
||||
},
|
||||
{
|
||||
"type": 13,
|
||||
"regex": "^[0-9]+![3-4][0-9]+\\.[0-9]+(H|L|)$"
|
||||
}
|
||||
],
|
||||
"group_interval": 100,
|
||||
"host": {
|
||||
"name": "IP Address",
|
||||
"name_zh": "IP地址",
|
||||
"description": "Local IP in server mode, remote device IP in client mode",
|
||||
"description_zh": "服务端模式中填写本地 IP,客户端模式中填写目标设备 IP",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"valid": {
|
||||
"regex": "/^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$/",
|
||||
"length": 30
|
||||
}
|
||||
},
|
||||
"port": {
|
||||
"name": "Port",
|
||||
"name_zh": "端口号",
|
||||
"description": "Local port in server mode, remote device port in client mode",
|
||||
"description_zh": "服务端模式中填写本地端口号,客户端模式中填写远程设备端口号",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 502,
|
||||
"valid": {
|
||||
"min": 1,
|
||||
"max": 65535
|
||||
}
|
||||
},
|
||||
"timeout": {
|
||||
"name": "Connection Timeout",
|
||||
"name_zh": "连接超时时间",
|
||||
"description": "Connection timeout(ms)",
|
||||
"description_zh": "连接超时时间,单位为毫秒",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 3000,
|
||||
"valid": {
|
||||
"min": 1000,
|
||||
"max": 65535
|
||||
}
|
||||
},
|
||||
"connection_mode": {
|
||||
"name": "Connection Mode",
|
||||
"name_zh": "连接模式",
|
||||
"description": "Neuron as the client, or as the server",
|
||||
"description_zh": "Neuron 作为客户端或服务端",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "Client",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "Server",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,305 +0,0 @@
|
||||
{
|
||||
"tag_regex": [
|
||||
{
|
||||
"type": 3,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 5,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 6,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 8,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 10,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
"regex": "^[0-9]+!([0-1][0-9]+|[3-4][0-9]+\\.([0-9]|[0-1][0-5]))$"
|
||||
},
|
||||
{
|
||||
"type": 13,
|
||||
"regex": "^[0-9]+![3-4][0-9]+\\.[0-9]+(H|L|)$"
|
||||
}
|
||||
],
|
||||
"group_interval": 1000,
|
||||
"link": {
|
||||
"name": "Physical Link",
|
||||
"name_zh": "物理链路",
|
||||
"description": "Serial or Ethernet",
|
||||
"description_zh": "串口连接或以太网连接",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "Serial",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "TCP",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"timeout": {
|
||||
"name": "Connection Timeout",
|
||||
"name_zh": "连接超时时间",
|
||||
"description": "Connection timeout(ms)",
|
||||
"description_zh": "连接超时时间,单位为毫秒",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 3000,
|
||||
"valid": {
|
||||
"min": 1000,
|
||||
"max": 30000
|
||||
}
|
||||
},
|
||||
"interval": {
|
||||
"name": "Send Interval",
|
||||
"name_zh": "指令发送间隔",
|
||||
"description": "Send reading instruction interval(ms)",
|
||||
"description_zh": "发送读指令时间间隔,单位为毫秒",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 20,
|
||||
"valid": {
|
||||
"min": 0,
|
||||
"max": 3000
|
||||
}
|
||||
},
|
||||
"device": {
|
||||
"name": "Serial Device",
|
||||
"name_zh": "串口设备",
|
||||
"description": "Serial device path",
|
||||
"description_zh": "串口设备路径",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"condition": {
|
||||
"field": "link",
|
||||
"value": 0
|
||||
},
|
||||
"valid": {
|
||||
"length": 30
|
||||
}
|
||||
},
|
||||
"stop": {
|
||||
"name": "Stop Bits",
|
||||
"name_zh": "停止位",
|
||||
"description": "Stop bits",
|
||||
"description_zh": "停止位",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "1",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"field": "link",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"parity": {
|
||||
"name": "Parity",
|
||||
"name_zh": "校验位",
|
||||
"description": "Parity",
|
||||
"description_zh": "校验位",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "none",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "odd",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "even",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"key": "mark",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"key": "space",
|
||||
"value": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"field": "link",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"baud": {
|
||||
"name": "Baud Rate",
|
||||
"name_zh": "波特率",
|
||||
"description": "Baud rate",
|
||||
"description_zh": "波特率",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 4,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "2400",
|
||||
"value": 6
|
||||
},
|
||||
{
|
||||
"key": "4800",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"key": "9600",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"key": "19200",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"key": "38400",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"key": "57600",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "115200",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"field": "link",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"name": "Data Bits",
|
||||
"name_zh": "数据位",
|
||||
"description": "Data bits",
|
||||
"description_zh": "数据位",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 3,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "5",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "6",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "7",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"key": "8",
|
||||
"value": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"field": "link",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"name": "IP Address",
|
||||
"name_zh": "IP地址",
|
||||
"description": "Local IP in server mode, remote device IP in client mode",
|
||||
"description_zh": "服务端模式中填写本地 IP,客户端模式中填写目标设备 IP",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"valid": {
|
||||
"regex": "/^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$/",
|
||||
"length": 30
|
||||
},
|
||||
"condition": {
|
||||
"field": "link",
|
||||
"value": 1
|
||||
}
|
||||
},
|
||||
"port": {
|
||||
"name": "Port",
|
||||
"name_zh": "端口号",
|
||||
"description": "Local port in server mode, remote device port in client mode",
|
||||
"description_zh": "服务端模式中填写本地端口号,客户端模式中填写远程设备端口号",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 502,
|
||||
"valid": {
|
||||
"min": 1,
|
||||
"max": 65535
|
||||
},
|
||||
"condition": {
|
||||
"field": "link",
|
||||
"value": 1
|
||||
}
|
||||
},
|
||||
"connection_mode": {
|
||||
"name": "Connection Mode",
|
||||
"name_zh": "连接模式",
|
||||
"description": "Neuron as the client, or as the server",
|
||||
"description_zh": "Neuron 作为客户端或服务端",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "Client",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "Server",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"field": "link",
|
||||
"value": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"tag_regex": [
|
||||
{
|
||||
"type": 3,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 5,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 6,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
"regex": "^[0-9]+!([0-1][0-9]+|[3-4][0-9]+\\.([0-9]|[0-1][0-5]))$"
|
||||
}
|
||||
],
|
||||
"group_interval": 1000,
|
||||
"host": {
|
||||
"name": "Device IP Address",
|
||||
"name_zh": "设备IP地址",
|
||||
"description": "Target device IPv4 address",
|
||||
"description_zh": "目标设备IPv4地址",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"valid": {
|
||||
"regex": "/^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$/",
|
||||
"length": 30
|
||||
}
|
||||
},
|
||||
"port": {
|
||||
"name": "Device Port",
|
||||
"name_zh": "设备端口",
|
||||
"description": "Target device port number",
|
||||
"description_zh": "目标设备端口号",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 502,
|
||||
"valid": {
|
||||
"min": 1,
|
||||
"max": 65535
|
||||
}
|
||||
},
|
||||
"timeout": {
|
||||
"name": "Recv Timeout",
|
||||
"name_zh": "接收超时时间",
|
||||
"description": "Recv msg timeout(ms)",
|
||||
"description_zh": "接收消息超时时间(毫秒)",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 3000,
|
||||
"valid": {
|
||||
"min": 1000,
|
||||
"max": 65535
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
{
|
||||
"tag_regex": [
|
||||
{
|
||||
"type": 3,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 5,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 6,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 8,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 10,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
"regex": "^[0-9]+!([0-1][0-9]+|[3-4][0-9]+\\.([0-9]|[0-1][0-5]))$"
|
||||
},
|
||||
{
|
||||
"type": 13,
|
||||
"regex": "^[0-9]+![3-4][0-9]+\\.[0-9]+(H|L|)$"
|
||||
}
|
||||
],
|
||||
"group_interval": 1000,
|
||||
"connection_mode": {
|
||||
"name": "Connection Mode",
|
||||
"name_zh": "连接模式",
|
||||
"description": "Neuron as the client, or as the server",
|
||||
"description_zh": "Neuron 作为客户端或服务端",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "Client",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "Server",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"interval": {
|
||||
"name": "Send Interval",
|
||||
"name_zh": "指令发送间隔",
|
||||
"description": "Send reading instruction interval(ms)",
|
||||
"description_zh": "发送读指令时间间隔,单位为毫秒",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 20,
|
||||
"valid": {
|
||||
"min": 0,
|
||||
"max": 3000
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"name": "IP Address",
|
||||
"name_zh": "IP地址",
|
||||
"description": "Local IP in server mode, remote device IP in client mode",
|
||||
"description_zh": "服务端模式中填写本地 IP,客户端模式中填写目标设备 IP",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"valid": {
|
||||
"regex": "/^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$/",
|
||||
"length": 30
|
||||
}
|
||||
},
|
||||
"port": {
|
||||
"name": "Port",
|
||||
"name_zh": "端口号",
|
||||
"description": "Local port in server mode, remote device port in client mode",
|
||||
"description_zh": "服务端模式中填写本地端口号,客户端模式中填写远程设备端口号",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 502,
|
||||
"valid": {
|
||||
"min": 1,
|
||||
"max": 65535
|
||||
}
|
||||
},
|
||||
"timeout": {
|
||||
"name": "Connection Timeout",
|
||||
"name_zh": "连接超时时间",
|
||||
"description": "Connection timeout(ms)",
|
||||
"description_zh": "连接超时时间,单位为毫秒",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 3000,
|
||||
"valid": {
|
||||
"min": 1000,
|
||||
"max": 65535
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,25 +23,6 @@
|
||||
|
||||
#include "modbus.h"
|
||||
|
||||
static uint16_t calcrc(uint8_t *buf, int len)
|
||||
{
|
||||
uint16_t crc = 0xffff;
|
||||
uint16_t crcpoly = 0xa001;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
uint8_t x = buf[i];
|
||||
crc ^= x;
|
||||
for (int k = 0; k < 8; k++) {
|
||||
uint16_t usepoly = crc & 0x1;
|
||||
crc >>= 1;
|
||||
if (usepoly)
|
||||
crc ^= crcpoly;
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
void modbus_header_wrap(neu_protocol_pack_buf_t *buf, uint16_t seq)
|
||||
{
|
||||
assert(neu_protocol_pack_buf_unused_size(buf) >=
|
||||
@@ -168,40 +149,6 @@ int modbus_data_unwrap(neu_protocol_unpack_buf_t *buf,
|
||||
return sizeof(struct modbus_data);
|
||||
}
|
||||
|
||||
void modbus_crc_set(neu_protocol_pack_buf_t *buf)
|
||||
{
|
||||
uint16_t crc = calcrc(neu_protocol_pack_buf_get(buf),
|
||||
neu_protocol_pack_buf_used_size(buf) - 2);
|
||||
uint16_t *p_crc = (uint16_t *) neu_protocol_pack_buf_set(
|
||||
buf, neu_protocol_pack_buf_used_size(buf) - 2, 2);
|
||||
|
||||
*p_crc = crc;
|
||||
}
|
||||
|
||||
void modbus_crc_wrap(neu_protocol_pack_buf_t *buf)
|
||||
{
|
||||
assert(neu_protocol_pack_buf_unused_size(buf) >= sizeof(struct modbus_crc));
|
||||
struct modbus_crc *crc = (struct modbus_crc *) neu_protocol_pack_buf(
|
||||
buf, sizeof(struct modbus_crc));
|
||||
|
||||
crc->crc = 0;
|
||||
}
|
||||
|
||||
int modbus_crc_unwrap(neu_protocol_unpack_buf_t *buf,
|
||||
struct modbus_crc * out_crc)
|
||||
{
|
||||
struct modbus_crc *crc = (struct modbus_crc *) neu_protocol_unpack_buf(
|
||||
buf, sizeof(struct modbus_crc));
|
||||
|
||||
if (crc == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_crc = *crc;
|
||||
|
||||
return sizeof(struct modbus_crc);
|
||||
}
|
||||
|
||||
const char *modbus_area_to_str(modbus_area_e area)
|
||||
{
|
||||
switch (area) {
|
||||
|
||||
@@ -92,15 +92,6 @@ void modbus_data_wrap(neu_protocol_pack_buf_t *buf, uint8_t n_byte,
|
||||
int modbus_data_unwrap(neu_protocol_unpack_buf_t *buf,
|
||||
struct modbus_data * out_data);
|
||||
|
||||
struct modbus_crc {
|
||||
uint16_t crc;
|
||||
} __attribute__((packed));
|
||||
|
||||
void modbus_crc_set(neu_protocol_pack_buf_t *buf);
|
||||
void modbus_crc_wrap(neu_protocol_pack_buf_t *buf);
|
||||
int modbus_crc_unwrap(neu_protocol_unpack_buf_t *buf,
|
||||
struct modbus_crc * out_crc);
|
||||
|
||||
const char *modbus_area_to_str(modbus_area_e area);
|
||||
|
||||
#endif
|
||||
@@ -123,16 +123,6 @@ int modbus_tag_to_point(neu_datatag_t *tag, modbus_point_t *point)
|
||||
point->n_register = 2;
|
||||
}
|
||||
break;
|
||||
case NEU_TYPE_UINT64:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_DOUBLE:
|
||||
if (point->area == MODBUS_AREA_COIL ||
|
||||
point->area == MODBUS_AREA_INPUT) {
|
||||
ret = NEU_ERR_TAG_TYPE_NOT_SUPPORT;
|
||||
} else {
|
||||
point->n_register = 4;
|
||||
}
|
||||
break;
|
||||
case NEU_TYPE_STRING:
|
||||
if (point->area == MODBUS_AREA_COIL ||
|
||||
point->area == MODBUS_AREA_INPUT) {
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <neuron.h>
|
||||
|
||||
#include "errcodes.h"
|
||||
|
||||
#include "modbus_point.h"
|
||||
#include "modbus_req.h"
|
||||
#include "modbus_stack.h"
|
||||
|
||||
static neu_plugin_t *driver_open(void);
|
||||
|
||||
static int driver_close(neu_plugin_t *plugin);
|
||||
static int driver_init(neu_plugin_t *plugin);
|
||||
static int driver_uninit(neu_plugin_t *plugin);
|
||||
static int driver_start(neu_plugin_t *plugin);
|
||||
static int driver_stop(neu_plugin_t *plugin);
|
||||
static int driver_config(neu_plugin_t *plugin, const char *config);
|
||||
static int driver_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
|
||||
void *data);
|
||||
|
||||
static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag);
|
||||
static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group);
|
||||
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value);
|
||||
|
||||
static const neu_plugin_intf_funs_t plugin_intf_funs = {
|
||||
.open = driver_open,
|
||||
.close = driver_close,
|
||||
.init = driver_init,
|
||||
.uninit = driver_uninit,
|
||||
.start = driver_start,
|
||||
.stop = driver_stop,
|
||||
.setting = driver_config,
|
||||
.request = driver_request,
|
||||
|
||||
.driver.validate_tag = driver_validate_tag,
|
||||
.driver.group_timer = driver_group_timer,
|
||||
.driver.write_tag = driver_write,
|
||||
};
|
||||
|
||||
const neu_plugin_module_t neu_plugin_module = {
|
||||
.version = NEURON_PLUGIN_VER_1_0,
|
||||
.schema = "modbus-qh-tcp",
|
||||
.module_name = "Modbus TCP QH",
|
||||
.module_descr =
|
||||
"The modbus-qh-tcp plugin is an optimized version of modbus tcp, which "
|
||||
"expands the packet description field to two bytes, limiting the "
|
||||
"maximum length of Modbus tcp packets to 64KB",
|
||||
.module_descr_zh =
|
||||
"该插件是 modbus-tcp 插件的优化版,数据包描述字段扩展为连个字节,限制 "
|
||||
"Modbus TCP 数据包的最大长度为 64KB。",
|
||||
.intf_funs = &plugin_intf_funs,
|
||||
.kind = NEU_PLUGIN_KIND_SYSTEM,
|
||||
.type = NEU_NA_TYPE_DRIVER,
|
||||
.display = true,
|
||||
.single = false,
|
||||
.timer_type = NEU_EVENT_TIMER_NOBLOCK,
|
||||
};
|
||||
|
||||
static neu_plugin_t *driver_open(void)
|
||||
{
|
||||
neu_plugin_t *plugin = calloc(1, sizeof(neu_plugin_t));
|
||||
|
||||
neu_plugin_common_init(&plugin->common);
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
static int driver_close(neu_plugin_t *plugin)
|
||||
{
|
||||
free(plugin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_init(neu_plugin_t *plugin)
|
||||
{
|
||||
plugin->protocol = MODBUS_PROTOCOL_TCP;
|
||||
plugin->events = neu_event_new();
|
||||
plugin->stack = modbus_stack_create((void *) plugin, MODBUS_PROTOCOL_TCP,
|
||||
modbus_send_msg, modbus_value_handle,
|
||||
modbus_write_resp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_uninit(neu_plugin_t *plugin)
|
||||
{
|
||||
if (plugin->conn != NULL) {
|
||||
neu_conn_destory(plugin->conn);
|
||||
}
|
||||
|
||||
if (plugin->stack) {
|
||||
modbus_stack_destroy(plugin->stack);
|
||||
}
|
||||
|
||||
neu_event_close(plugin->events);
|
||||
|
||||
plog_info(plugin, "node: modbus uninit ok");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_start(neu_plugin_t *plugin)
|
||||
{
|
||||
neu_conn_start(plugin->conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_stop(neu_plugin_t *plugin)
|
||||
{
|
||||
neu_conn_stop(plugin->conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
{
|
||||
int ret = 0;
|
||||
char * err_param = NULL;
|
||||
neu_json_elem_t port = { .name = "port", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t timeout = { .name = "timeout", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t host = { .name = "host", .t = NEU_JSON_STR };
|
||||
neu_json_elem_t mode = { .name = "connection_mode", .t = NEU_JSON_INT };
|
||||
neu_conn_param_t param = { 0 };
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 4, &port, &host, &mode,
|
||||
&timeout);
|
||||
|
||||
if (ret != 0) {
|
||||
plog_info(plugin, "config: %s, decode error: %s", config, err_param);
|
||||
free(err_param);
|
||||
return -1;
|
||||
}
|
||||
|
||||
param.log = plugin->common.log;
|
||||
if (mode.v.val_int == 1) {
|
||||
param.type = NEU_CONN_TCP_SERVER;
|
||||
param.params.tcp_server.ip = host.v.val_str;
|
||||
param.params.tcp_server.port = port.v.val_int;
|
||||
param.params.tcp_server.start_listen = modbus_tcp_server_listen;
|
||||
param.params.tcp_server.stop_listen = modbus_tcp_server_stop;
|
||||
param.params.tcp_server.timeout = timeout.v.val_int;
|
||||
param.params.tcp_server.max_link = 1;
|
||||
plugin->is_server = true;
|
||||
} else {
|
||||
param.type = NEU_CONN_TCP_CLIENT;
|
||||
param.params.tcp_client.ip = host.v.val_str;
|
||||
param.params.tcp_client.port = port.v.val_int;
|
||||
param.params.tcp_client.timeout = timeout.v.val_int;
|
||||
plugin->is_server = false;
|
||||
}
|
||||
|
||||
plog_info(plugin, "config: host: %s, port: %" PRId64 ", mode: %" PRId64 "",
|
||||
host.v.val_str, port.v.val_int, mode.v.val_int);
|
||||
|
||||
if (plugin->conn != NULL) {
|
||||
plugin->conn = neu_conn_reconfig(plugin->conn, ¶m);
|
||||
} else {
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
|
||||
plugin->conn =
|
||||
neu_conn_new(¶m, (void *) plugin, modbus_conn_connected,
|
||||
modbus_conn_disconnected);
|
||||
}
|
||||
|
||||
free(host.v.val_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
|
||||
void *data)
|
||||
{
|
||||
(void) plugin;
|
||||
(void) head;
|
||||
(void) data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag)
|
||||
{
|
||||
modbus_point_t point = { 0 };
|
||||
|
||||
int ret = modbus_tag_to_point(tag, &point);
|
||||
if (ret == 0) {
|
||||
plog_info(
|
||||
plugin,
|
||||
"validate tag success, name: %s, address: %s, type: %d, slave id: "
|
||||
"%d, start address: %d, n register: %d, area: %s",
|
||||
tag->name, tag->address, tag->type, point.slave_id,
|
||||
point.start_address, point.n_register,
|
||||
modbus_area_to_str(point.area));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
|
||||
{
|
||||
return modbus_group_timer(plugin, group, 0xffff);
|
||||
}
|
||||
|
||||
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value)
|
||||
{
|
||||
return modbus_write(plugin, req, tag, value);
|
||||
}
|
||||
+29
-108
@@ -16,16 +16,14 @@
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
#include <time.h>
|
||||
|
||||
#include "modbus_point.h"
|
||||
#include "modbus_stack.h"
|
||||
|
||||
#include "modbus_req.h"
|
||||
|
||||
struct modbus_group_data {
|
||||
UT_array * tags;
|
||||
char * group;
|
||||
UT_array * tags;
|
||||
modbus_read_cmd_sort_t *cmd_sort;
|
||||
};
|
||||
|
||||
@@ -48,76 +46,22 @@ void modbus_conn_disconnected(void *data, int fd)
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
void modbus_tcp_server_listen(void *data, int fd)
|
||||
{
|
||||
struct neu_plugin * plugin = (struct neu_plugin *) data;
|
||||
neu_event_io_param_t param = {
|
||||
.cb = modbus_tcp_server_io_callback,
|
||||
.fd = fd,
|
||||
.usr_data = (void *) plugin,
|
||||
};
|
||||
|
||||
plugin->tcp_server_io = neu_event_add_io(plugin->events, param);
|
||||
}
|
||||
|
||||
void modbus_tcp_server_stop(void *data, int fd)
|
||||
{
|
||||
struct neu_plugin *plugin = (struct neu_plugin *) data;
|
||||
(void) fd;
|
||||
|
||||
neu_event_del_io(plugin->events, plugin->tcp_server_io);
|
||||
}
|
||||
|
||||
int modbus_tcp_server_io_callback(enum neu_event_io_type type, int fd,
|
||||
void *usr_data)
|
||||
{
|
||||
neu_plugin_t *plugin = (neu_plugin_t *) usr_data;
|
||||
|
||||
switch (type) {
|
||||
case NEU_EVENT_IO_READ: {
|
||||
int client_fd = neu_conn_tcp_server_accept(plugin->conn);
|
||||
if (client_fd > 0) {
|
||||
plugin->client_fd = client_fd;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NEU_EVENT_IO_CLOSED:
|
||||
case NEU_EVENT_IO_HUP:
|
||||
plog_warn(plugin, "tcp server recv: %d, conn closed, fd: %d", type, fd);
|
||||
neu_event_del_io(plugin->events, plugin->tcp_server_io);
|
||||
neu_conn_disconnect(plugin->conn);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int modbus_send_msg(void *ctx, uint16_t n_byte, uint8_t *bytes)
|
||||
{
|
||||
neu_plugin_t *plugin = (neu_plugin_t *) ctx;
|
||||
int ret = 0;
|
||||
|
||||
plog_send_protocol(plugin, bytes, n_byte);
|
||||
|
||||
if (plugin->is_server) {
|
||||
ret = neu_conn_tcp_server_send(plugin->conn, plugin->client_fd, bytes,
|
||||
n_byte);
|
||||
} else {
|
||||
ret = neu_conn_send(plugin->conn, bytes, n_byte);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return neu_conn_send(plugin->conn, bytes, n_byte);
|
||||
}
|
||||
|
||||
int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
|
||||
uint16_t max_byte)
|
||||
{
|
||||
neu_conn_state_t state = { 0 };
|
||||
neu_adapter_update_metric_cb_t update_metric =
|
||||
plugin->common.adapter_callbacks->update_metric;
|
||||
struct modbus_group_data *gd = NULL;
|
||||
int64_t rtt = NEU_METRIC_LAST_RTT_MS_MAX;
|
||||
struct modbus_group_data *gd = NULL;
|
||||
neu_conn_state_t state = { 0 };
|
||||
int64_t rtt = NEU_METRIC_LAST_RTT_MS_MAX;
|
||||
|
||||
if (group->user_data == NULL) {
|
||||
gd = calloc(1, sizeof(struct modbus_group_data));
|
||||
@@ -137,39 +81,32 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
|
||||
|
||||
gd->group = strdup(group->group_name);
|
||||
gd->cmd_sort = modbus_tag_sort(gd->tags, max_byte);
|
||||
} else {
|
||||
gd = (struct modbus_group_data *) group->user_data;
|
||||
}
|
||||
|
||||
gd = (struct modbus_group_data *) group->user_data;
|
||||
plugin->plugin_group_data = gd;
|
||||
|
||||
for (uint16_t i = 0; i < gd->cmd_sort->n_cmd; i++) {
|
||||
plugin->cmd_idx = i;
|
||||
uint16_t response_size = 0;
|
||||
uint64_t read_tms = neu_time_ms();
|
||||
int64_t start = neu_time_ms();
|
||||
plugin->cmd_idx = i;
|
||||
|
||||
int ret = modbus_stack_read(
|
||||
plugin->stack, gd->cmd_sort->cmd[i].slave_id,
|
||||
gd->cmd_sort->cmd[i].area, gd->cmd_sort->cmd[i].start_address,
|
||||
gd->cmd_sort->cmd[i].n_register, &response_size);
|
||||
if (ret > 0) {
|
||||
ret = process_protocol_buf(plugin, response_size);
|
||||
rtt = neu_time_ms() - read_tms;
|
||||
}
|
||||
if (ret <= 0) {
|
||||
modbus_value_handle(plugin, gd->cmd_sort->cmd[i].slave_id, 0, NULL,
|
||||
NEU_ERR_PLUGIN_DISCONNECTED);
|
||||
rtt = NEU_METRIC_LAST_RTT_MS_MAX;
|
||||
}
|
||||
if (plugin->interval > 0) {
|
||||
struct timespec t1 = { .tv_sec = plugin->interval / 1000,
|
||||
.tv_nsec = 1000 * 1000 *
|
||||
(plugin->interval % 1000) };
|
||||
struct timespec t2 = { 0 };
|
||||
nanosleep(&t1, &t2);
|
||||
process_protocol_buf(plugin, response_size);
|
||||
|
||||
int64_t end = neu_time_ms();
|
||||
if (end - start < rtt) {
|
||||
rtt = end - start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state = neu_conn_state(plugin->conn);
|
||||
|
||||
update_metric(plugin->common.adapter, NEU_METRIC_SEND_BYTES,
|
||||
state.send_bytes, NULL);
|
||||
update_metric(plugin->common.adapter, NEU_METRIC_RECV_BYTES,
|
||||
@@ -177,11 +114,12 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
|
||||
update_metric(plugin->common.adapter, NEU_METRIC_LAST_RTT_MS, rtt, NULL);
|
||||
update_metric(plugin->common.adapter, NEU_METRIC_GROUP_LAST_SEND_MSGS,
|
||||
gd->cmd_sort->n_cmd, group->group_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
uint8_t *bytes, int error)
|
||||
uint8_t *bytes)
|
||||
{
|
||||
neu_plugin_t * plugin = (neu_plugin_t *) ctx;
|
||||
struct modbus_group_data *gd =
|
||||
@@ -189,11 +127,11 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
uint16_t start_address = gd->cmd_sort->cmd[plugin->cmd_idx].start_address;
|
||||
uint16_t n_register = gd->cmd_sort->cmd[plugin->cmd_idx].n_register;
|
||||
|
||||
if (error != NEU_ERR_SUCCESS) {
|
||||
if (bytes == NULL) {
|
||||
neu_dvalue_t dvalue = { 0 };
|
||||
|
||||
dvalue.type = NEU_TYPE_ERROR;
|
||||
dvalue.value.i32 = error;
|
||||
dvalue.value.i32 = NEU_ERR_PLUGIN_DISCONNECTED;
|
||||
plugin->common.adapter_callbacks->driver.update(
|
||||
plugin->common.adapter, gd->group, NULL, dvalue);
|
||||
return 0;
|
||||
@@ -244,11 +182,6 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
case NEU_TYPE_UINT32:
|
||||
dvalue.value.u32 = ntohl(dvalue.value.u32);
|
||||
break;
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
dvalue.value.u64 = neu_ntohll(dvalue.value.u64);
|
||||
break;
|
||||
case NEU_TYPE_BIT: {
|
||||
switch ((*p_tag)->area) {
|
||||
case MODBUS_AREA_HOLD_REGISTER:
|
||||
@@ -263,6 +196,7 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
case MODBUS_AREA_INPUT:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NEU_TYPE_STRING: {
|
||||
@@ -284,6 +218,7 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
dvalue.value.str[0] = '?';
|
||||
dvalue.value.str[1] = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -307,23 +242,18 @@ int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
|
||||
switch (tag->type) {
|
||||
case NEU_TYPE_UINT16:
|
||||
case NEU_TYPE_INT16:
|
||||
case NEU_TYPE_INT16: {
|
||||
value.u16 = htons(value.u16);
|
||||
n_byte = sizeof(uint16_t);
|
||||
break;
|
||||
case NEU_TYPE_FLOAT:
|
||||
}
|
||||
case NEU_TYPE_UINT32:
|
||||
case NEU_TYPE_INT32:
|
||||
case NEU_TYPE_FLOAT: {
|
||||
value.u32 = htonl(value.u32);
|
||||
n_byte = sizeof(uint32_t);
|
||||
break;
|
||||
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
value.u64 = neu_htonll(value.u64);
|
||||
n_byte = sizeof(uint64_t);
|
||||
break;
|
||||
}
|
||||
case NEU_TYPE_BIT: {
|
||||
n_byte = sizeof(uint8_t);
|
||||
break;
|
||||
@@ -388,21 +318,12 @@ static int process_protocol_buf(neu_plugin_t *plugin, uint16_t response_size)
|
||||
neu_protocol_unpack_buf_t pbuf = { 0 };
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (plugin->is_server) {
|
||||
ret = neu_conn_tcp_server_recv(plugin->conn, plugin->client_fd,
|
||||
recv_buf, response_size);
|
||||
} else {
|
||||
ret = neu_conn_recv(plugin->conn, recv_buf, response_size);
|
||||
}
|
||||
ret = neu_conn_recv(plugin->conn, recv_buf, response_size);
|
||||
|
||||
if (ret == response_size) {
|
||||
if (response_size < 512) {
|
||||
plog_recv_protocol(plugin, recv_buf, ret);
|
||||
}
|
||||
if (ret > 0) {
|
||||
neu_protocol_unpack_buf_init(&pbuf, recv_buf, ret);
|
||||
plog_recv_protocol(plugin, recv_buf, ret);
|
||||
ret = modbus_stack_recv(plugin->stack, &pbuf);
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
free(recv_buf);
|
||||
|
||||
@@ -33,28 +33,18 @@ struct neu_plugin {
|
||||
uint16_t cmd_idx;
|
||||
|
||||
neu_event_io_t *tcp_server_io;
|
||||
bool is_server;
|
||||
bool is_serial;
|
||||
int client_fd;
|
||||
neu_events_t * events;
|
||||
|
||||
modbus_protocol_e protocol;
|
||||
|
||||
uint16_t interval;
|
||||
};
|
||||
|
||||
void modbus_conn_connected(void *data, int fd);
|
||||
void modbus_conn_disconnected(void *data, int fd);
|
||||
void modbus_tcp_server_listen(void *data, int fd);
|
||||
void modbus_tcp_server_stop(void *data, int fd);
|
||||
int modbus_tcp_server_io_callback(enum neu_event_io_type type, int fd,
|
||||
void *usr_data);
|
||||
|
||||
int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
|
||||
uint16_t max_byte);
|
||||
int modbus_send_msg(void *ctx, uint16_t n_byte, uint8_t *bytes);
|
||||
int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
uint8_t *bytes, int error);
|
||||
uint8_t *bytes);
|
||||
int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value);
|
||||
int modbus_write_resp(void *ctx, void *req, int error);
|
||||
|
||||
@@ -1,276 +0,0 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <neuron.h>
|
||||
|
||||
#include "errcodes.h"
|
||||
|
||||
#include "modbus_point.h"
|
||||
#include "modbus_req.h"
|
||||
#include "modbus_stack.h"
|
||||
|
||||
static neu_plugin_t *driver_open(void);
|
||||
|
||||
static int driver_close(neu_plugin_t *plugin);
|
||||
static int driver_init(neu_plugin_t *plugin);
|
||||
static int driver_uninit(neu_plugin_t *plugin);
|
||||
static int driver_start(neu_plugin_t *plugin);
|
||||
static int driver_stop(neu_plugin_t *plugin);
|
||||
static int driver_config(neu_plugin_t *plugin, const char *config);
|
||||
static int driver_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
|
||||
void *data);
|
||||
|
||||
static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag);
|
||||
static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group);
|
||||
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value);
|
||||
|
||||
static const neu_plugin_intf_funs_t plugin_intf_funs = {
|
||||
.open = driver_open,
|
||||
.close = driver_close,
|
||||
.init = driver_init,
|
||||
.uninit = driver_uninit,
|
||||
.start = driver_start,
|
||||
.stop = driver_stop,
|
||||
.setting = driver_config,
|
||||
.request = driver_request,
|
||||
|
||||
.driver.validate_tag = driver_validate_tag,
|
||||
.driver.group_timer = driver_group_timer,
|
||||
.driver.write_tag = driver_write,
|
||||
};
|
||||
|
||||
const neu_plugin_module_t neu_plugin_module = {
|
||||
.version = NEURON_PLUGIN_VER_1_0,
|
||||
.schema = "modbus-rtu",
|
||||
.module_name = "Modbus RTU",
|
||||
.module_descr =
|
||||
"This plugin is used to connect devices using modbus rtu protocol. "
|
||||
"Support serial and TCP communication methods. When using TCP "
|
||||
"communication, it is necessary to use the pass-through function of "
|
||||
"DTU to convert serial data into IP data and transmit it through "
|
||||
"the network. Selecting client/server is also supported.",
|
||||
.module_descr_zh =
|
||||
"该插件用于连接使用 modbus rtu 协议的设备。支持串口和 TCP "
|
||||
"两种通信方式。使用 TCP 通信时,需要使用 DTU "
|
||||
"的透传功能,将串口数据转为 IP "
|
||||
"数据并通过网络传输。也支持选择客户端/服务端。",
|
||||
.intf_funs = &plugin_intf_funs,
|
||||
.kind = NEU_PLUGIN_KIND_SYSTEM,
|
||||
.type = NEU_NA_TYPE_DRIVER,
|
||||
.display = true,
|
||||
.single = false,
|
||||
};
|
||||
|
||||
static neu_plugin_t *driver_open(void)
|
||||
{
|
||||
neu_plugin_t *plugin = calloc(1, sizeof(neu_plugin_t));
|
||||
|
||||
neu_plugin_common_init(&plugin->common);
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
static int driver_close(neu_plugin_t *plugin)
|
||||
{
|
||||
free(plugin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_init(neu_plugin_t *plugin)
|
||||
{
|
||||
plugin->protocol = MODBUS_PROTOCOL_RTU;
|
||||
plugin->events = neu_event_new();
|
||||
plugin->stack = modbus_stack_create((void *) plugin, MODBUS_PROTOCOL_RTU,
|
||||
modbus_send_msg, modbus_value_handle,
|
||||
modbus_write_resp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_uninit(neu_plugin_t *plugin)
|
||||
{
|
||||
if (plugin->conn != NULL) {
|
||||
neu_conn_destory(plugin->conn);
|
||||
}
|
||||
|
||||
if (plugin->stack) {
|
||||
modbus_stack_destroy(plugin->stack);
|
||||
}
|
||||
|
||||
neu_event_close(plugin->events);
|
||||
|
||||
plog_info(plugin, "node: modbus uninit ok");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_start(neu_plugin_t *plugin)
|
||||
{
|
||||
neu_conn_start(plugin->conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_stop(neu_plugin_t *plugin)
|
||||
{
|
||||
neu_conn_stop(plugin->conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
{
|
||||
int ret = 0;
|
||||
char * err_param = NULL;
|
||||
neu_conn_param_t param = { 0 };
|
||||
|
||||
neu_json_elem_t link = { .name = "link", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t timeout = { .name = "timeout", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t interval = { .name = "interval", .t = NEU_JSON_INT };
|
||||
|
||||
neu_json_elem_t mode = { .name = "connection_mode", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t host = { .name = "host", .t = NEU_JSON_STR };
|
||||
neu_json_elem_t port = { .name = "port", .t = NEU_JSON_INT };
|
||||
|
||||
neu_json_elem_t device = { .name = "device", .t = NEU_JSON_STR };
|
||||
neu_json_elem_t stop = { .name = "stop", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t parity = { .name = "parity", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t baud = { .name = "baud", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t data = { .name = "data", .t = NEU_JSON_INT };
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 3, &link, &timeout,
|
||||
&interval);
|
||||
if (ret != 0) {
|
||||
plog_warn(plugin, "config: %s, decode link & timeout error: %s", config,
|
||||
err_param);
|
||||
free(err_param);
|
||||
return -1;
|
||||
}
|
||||
|
||||
plugin->interval = interval.v.val_int;
|
||||
if (link.v.val_int == 0) {
|
||||
ret = neu_parse_param((char *) config, &err_param, 5, &device, &stop,
|
||||
&parity, &baud, &data);
|
||||
} else {
|
||||
ret = neu_parse_param((char *) config, &err_param, 3, &mode, &host,
|
||||
&port);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
plog_warn(plugin, "config: %s, decode error: %s", config, err_param);
|
||||
free(err_param);
|
||||
return -1;
|
||||
}
|
||||
|
||||
param.log = plugin->common.log;
|
||||
if (link.v.val_int == 0) {
|
||||
param.type = NEU_CONN_TTY_CLIENT;
|
||||
|
||||
param.params.tty_client.device = device.v.val_str;
|
||||
param.params.tty_client.baud = baud.v.val_int;
|
||||
param.params.tty_client.data = data.v.val_int;
|
||||
param.params.tty_client.parity = parity.v.val_int;
|
||||
param.params.tty_client.stop = stop.v.val_int;
|
||||
param.params.tty_client.timeout = timeout.v.val_int;
|
||||
|
||||
plugin->is_serial = true;
|
||||
plog_info(plugin,
|
||||
"config: device: %s, baud: %" PRId64 ", data: %" PRId64
|
||||
", parity: %" PRId64 ", stop: %" PRId64 "",
|
||||
device.v.val_str, baud.v.val_int, data.v.val_int,
|
||||
parity.v.val_int, stop.v.val_int);
|
||||
} else {
|
||||
if (mode.v.val_int == 1) {
|
||||
param.type = NEU_CONN_TCP_SERVER;
|
||||
param.params.tcp_server.ip = host.v.val_str;
|
||||
param.params.tcp_server.port = port.v.val_int;
|
||||
param.params.tcp_server.start_listen = modbus_tcp_server_listen;
|
||||
param.params.tcp_server.stop_listen = modbus_tcp_server_stop;
|
||||
param.params.tcp_server.timeout = timeout.v.val_int;
|
||||
param.params.tcp_server.max_link = 1;
|
||||
plugin->is_server = true;
|
||||
} else {
|
||||
param.type = NEU_CONN_TCP_CLIENT;
|
||||
param.params.tcp_client.ip = host.v.val_str;
|
||||
param.params.tcp_client.port = port.v.val_int;
|
||||
param.params.tcp_client.timeout = timeout.v.val_int;
|
||||
plugin->is_server = false;
|
||||
}
|
||||
|
||||
plog_info(plugin,
|
||||
"config: host: %s, port: %" PRId64 ", mode: %" PRId64 "",
|
||||
host.v.val_str, port.v.val_int, mode.v.val_int);
|
||||
}
|
||||
|
||||
if (plugin->conn != NULL) {
|
||||
plugin->conn = neu_conn_reconfig(plugin->conn, ¶m);
|
||||
} else {
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
|
||||
plugin->conn =
|
||||
neu_conn_new(¶m, (void *) plugin, modbus_conn_connected,
|
||||
modbus_conn_disconnected);
|
||||
}
|
||||
|
||||
if (link.v.val_int == 0) {
|
||||
free(device.v.val_str);
|
||||
} else {
|
||||
free(host.v.val_str);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
|
||||
void *data)
|
||||
{
|
||||
(void) plugin;
|
||||
(void) head;
|
||||
(void) data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag)
|
||||
{
|
||||
modbus_point_t point = { 0 };
|
||||
|
||||
int ret = modbus_tag_to_point(tag, &point);
|
||||
if (ret == 0) {
|
||||
plog_debug(
|
||||
plugin,
|
||||
"validate tag success, name: %s, address: %s, type: %d, slave id: "
|
||||
"%d, start address: %d, n register: %d, area: %s",
|
||||
tag->name, tag->address, tag->type, point.slave_id,
|
||||
point.start_address, point.n_register,
|
||||
modbus_area_to_str(point.area));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
|
||||
{
|
||||
return modbus_group_timer(plugin, group, 0xfa);
|
||||
}
|
||||
|
||||
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value)
|
||||
{
|
||||
return modbus_write(plugin, req, tag, value);
|
||||
}
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include <neuron.h>
|
||||
|
||||
#include "modbus_req.h"
|
||||
#include "modbus_stack.h"
|
||||
|
||||
struct modbus_stack {
|
||||
@@ -29,16 +28,10 @@ struct modbus_stack {
|
||||
modbus_stack_value value_fn;
|
||||
modbus_stack_write_resp write_resp;
|
||||
|
||||
modbus_protocol_e protocol;
|
||||
uint16_t read_seq;
|
||||
uint16_t write_seq;
|
||||
|
||||
uint8_t *buf;
|
||||
uint16_t buf_size;
|
||||
uint16_t seq;
|
||||
};
|
||||
|
||||
modbus_stack_t *modbus_stack_create(void *ctx, modbus_protocol_e protocol,
|
||||
modbus_stack_send send_fn,
|
||||
modbus_stack_t *modbus_stack_create(void *ctx, modbus_stack_send send_fn,
|
||||
modbus_stack_value value_fn,
|
||||
modbus_stack_write_resp write_resp)
|
||||
{
|
||||
@@ -48,17 +41,12 @@ modbus_stack_t *modbus_stack_create(void *ctx, modbus_protocol_e protocol,
|
||||
stack->send_fn = send_fn;
|
||||
stack->value_fn = value_fn;
|
||||
stack->write_resp = write_resp;
|
||||
stack->protocol = protocol;
|
||||
|
||||
stack->buf_size = 256;
|
||||
stack->buf = calloc(stack->buf_size, 1);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
void modbus_stack_destroy(modbus_stack_t *stack)
|
||||
{
|
||||
free(stack->buf);
|
||||
free(stack);
|
||||
}
|
||||
|
||||
@@ -68,14 +56,9 @@ int modbus_stack_recv(modbus_stack_t *stack, neu_protocol_unpack_buf_t *buf)
|
||||
struct modbus_code code = { 0 };
|
||||
int ret = 0;
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_TCP) {
|
||||
ret = modbus_header_unwrap(buf, &header);
|
||||
if (ret < 0) {
|
||||
plog_warn((neu_plugin_t *) stack->ctx, "try modbus rtu driver");
|
||||
}
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = modbus_header_unwrap(buf, &header);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = modbus_code_unwrap(buf, &code);
|
||||
@@ -95,19 +78,8 @@ int modbus_stack_recv(modbus_stack_t *stack, neu_protocol_unpack_buf_t *buf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_TCP && data.n_byte == 0xff) {
|
||||
bytes = neu_protocol_unpack_buf(buf,
|
||||
header.len -
|
||||
sizeof(struct modbus_code) -
|
||||
sizeof(struct modbus_data));
|
||||
stack->value_fn(stack->ctx, code.slave_id,
|
||||
header.len - sizeof(struct modbus_code) -
|
||||
sizeof(struct modbus_data),
|
||||
bytes, 0);
|
||||
} else {
|
||||
bytes = neu_protocol_unpack_buf(buf, data.n_byte);
|
||||
stack->value_fn(stack->ctx, code.slave_id, data.n_byte, bytes, 0);
|
||||
}
|
||||
bytes = neu_protocol_unpack_buf(buf, data.n_byte);
|
||||
stack->value_fn(stack->ctx, code.slave_id, data.n_byte, bytes);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -123,14 +95,6 @@ int modbus_stack_recv(modbus_stack_t *stack, neu_protocol_unpack_buf_t *buf)
|
||||
break;
|
||||
}
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_RTU) {
|
||||
struct modbus_crc crc = { 0 };
|
||||
ret = modbus_crc_unwrap(buf, &crc);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return neu_protocol_unpack_buf_used_size(buf);
|
||||
}
|
||||
|
||||
@@ -144,9 +108,6 @@ int modbus_stack_read(modbus_stack_t *stack, uint8_t slave_id,
|
||||
|
||||
neu_protocol_pack_buf_init(&pbuf, buf, sizeof(buf));
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_RTU) {
|
||||
modbus_crc_wrap(&pbuf);
|
||||
}
|
||||
modbus_address_wrap(&pbuf, start_address, n_reg);
|
||||
|
||||
switch (area) {
|
||||
@@ -171,23 +132,14 @@ int modbus_stack_read(modbus_stack_t *stack, uint8_t slave_id,
|
||||
*response_size += sizeof(struct modbus_code);
|
||||
*response_size += sizeof(struct modbus_data);
|
||||
|
||||
switch (stack->protocol) {
|
||||
case MODBUS_PROTOCOL_TCP:
|
||||
modbus_header_wrap(&pbuf, stack->read_seq++);
|
||||
*response_size += sizeof(struct modbus_header);
|
||||
break;
|
||||
case MODBUS_PROTOCOL_RTU:
|
||||
modbus_crc_set(&pbuf);
|
||||
*response_size += 2;
|
||||
break;
|
||||
}
|
||||
modbus_header_wrap(&pbuf, stack->seq++);
|
||||
*response_size += sizeof(struct modbus_header);
|
||||
|
||||
ret = stack->send_fn(stack->ctx, neu_protocol_pack_buf_used_size(&pbuf),
|
||||
neu_protocol_pack_buf_get(&pbuf));
|
||||
if (ret <= 0) {
|
||||
stack->value_fn(stack->ctx, 0, 0, NULL, NEU_ERR_PLUGIN_DISCONNECTED);
|
||||
stack->value_fn(stack->ctx, 0, 0, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -196,14 +148,11 @@ int modbus_stack_write(modbus_stack_t *stack, void *req, uint8_t slave_id,
|
||||
uint16_t n_reg, uint8_t *bytes, uint8_t n_byte,
|
||||
uint16_t *response_size)
|
||||
{
|
||||
static __thread neu_protocol_pack_buf_t pbuf = { 0 };
|
||||
uint8_t * buf = calloc(256, 1);
|
||||
neu_protocol_pack_buf_t pbuf = { 0 };
|
||||
int ret = 0;
|
||||
|
||||
memset(stack->buf, 0, stack->buf_size);
|
||||
neu_protocol_pack_buf_init(&pbuf, stack->buf, stack->buf_size);
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_RTU) {
|
||||
modbus_crc_wrap(&pbuf);
|
||||
}
|
||||
neu_protocol_pack_buf_init(&pbuf, buf, 256);
|
||||
|
||||
switch (area) {
|
||||
case MODBUS_AREA_COIL:
|
||||
@@ -220,34 +169,22 @@ int modbus_stack_write(modbus_stack_t *stack, void *req, uint8_t slave_id,
|
||||
modbus_code_wrap(&pbuf, slave_id, MODBUS_WRITE_M_HOLD_REG);
|
||||
break;
|
||||
default:
|
||||
stack->write_resp(stack->ctx, req, NEU_ERR_PLUGIN_TAG_NOT_ALLOW_WRITE);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
*response_size += sizeof(struct modbus_code);
|
||||
*response_size += sizeof(struct modbus_address);
|
||||
|
||||
switch (stack->protocol) {
|
||||
case MODBUS_PROTOCOL_TCP:
|
||||
modbus_header_wrap(&pbuf, stack->write_seq++);
|
||||
*response_size += sizeof(struct modbus_header);
|
||||
break;
|
||||
case MODBUS_PROTOCOL_RTU:
|
||||
modbus_crc_set(&pbuf);
|
||||
*response_size += 2;
|
||||
break;
|
||||
}
|
||||
modbus_header_wrap(&pbuf, stack->seq++);
|
||||
*response_size += sizeof(struct modbus_header);
|
||||
|
||||
int ret = stack->send_fn(stack->ctx, neu_protocol_pack_buf_used_size(&pbuf),
|
||||
neu_protocol_pack_buf_get(&pbuf));
|
||||
ret = stack->send_fn(stack->ctx, neu_protocol_pack_buf_used_size(&pbuf),
|
||||
neu_protocol_pack_buf_get(&pbuf));
|
||||
if (ret > 0) {
|
||||
stack->write_resp(stack->ctx, req, NEU_ERR_SUCCESS);
|
||||
} else {
|
||||
stack->write_resp(stack->ctx, req, NEU_ERR_PLUGIN_DISCONNECTED);
|
||||
}
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool modbus_stack_is_rtu(modbus_stack_t *stack)
|
||||
{
|
||||
return stack->protocol == MODBUS_PROTOCOL_RTU;
|
||||
}
|
||||
@@ -29,29 +29,22 @@ typedef struct modbus_stack modbus_stack_t;
|
||||
|
||||
typedef int (*modbus_stack_send)(void *ctx, uint16_t n_byte, uint8_t *bytes);
|
||||
typedef int (*modbus_stack_value)(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
uint8_t *bytes, int error);
|
||||
uint8_t *bytes);
|
||||
typedef int (*modbus_stack_write_resp)(void *ctx, void *req, int error);
|
||||
|
||||
typedef enum modbus_protocol {
|
||||
MODBUS_PROTOCOL_TCP = 1,
|
||||
MODBUS_PROTOCOL_RTU = 2,
|
||||
} modbus_protocol_e;
|
||||
|
||||
modbus_stack_t *modbus_stack_create(void *ctx, modbus_protocol_e protocol,
|
||||
modbus_stack_send send_fn,
|
||||
modbus_stack_t *modbus_stack_create(void *ctx, modbus_stack_send send_fn,
|
||||
modbus_stack_value value_fn,
|
||||
modbus_stack_write_resp write_resp);
|
||||
void modbus_stack_destroy(modbus_stack_t *stack);
|
||||
|
||||
int modbus_stack_recv(modbus_stack_t *stack, neu_protocol_unpack_buf_t *buf);
|
||||
|
||||
int modbus_stack_read(modbus_stack_t *stack, uint8_t slave_id,
|
||||
int modbus_stack_read(modbus_stack_t *stack, uint8_t slave_id,
|
||||
enum modbus_area area, uint16_t start_address,
|
||||
uint16_t n_reg, uint16_t *response_size);
|
||||
int modbus_stack_write(modbus_stack_t *stack, void *req, uint8_t slave_id,
|
||||
enum modbus_area area, uint16_t start_address,
|
||||
uint16_t n_reg, uint16_t *response_size);
|
||||
int modbus_stack_write(modbus_stack_t *stack, void *req, uint8_t slave_id,
|
||||
enum modbus_area area, uint16_t start_address,
|
||||
uint16_t n_reg, uint8_t *bytes, uint8_t n_byte,
|
||||
uint16_t *response_size);
|
||||
bool modbus_stack_is_rtu(modbus_stack_t *stack);
|
||||
uint16_t n_reg, uint8_t *bytes, uint8_t n_byte,
|
||||
uint16_t *response_size);
|
||||
|
||||
#endif
|
||||
+45
-51
@@ -18,22 +18,19 @@
|
||||
**/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <neuron.h>
|
||||
|
||||
#include "errcodes.h"
|
||||
#include "neuron.h"
|
||||
|
||||
#include "modbus_point.h"
|
||||
#include "modbus_req.h"
|
||||
#include "modbus_stack.h"
|
||||
|
||||
static neu_plugin_t *driver_open(void);
|
||||
|
||||
static int driver_close(neu_plugin_t *plugin);
|
||||
static int driver_init(neu_plugin_t *plugin);
|
||||
static int driver_uninit(neu_plugin_t *plugin);
|
||||
static int driver_start(neu_plugin_t *plugin);
|
||||
static int driver_stop(neu_plugin_t *plugin);
|
||||
static int driver_config(neu_plugin_t *plugin, const char *config);
|
||||
static int driver_close(neu_plugin_t *plugin);
|
||||
static int driver_init(neu_plugin_t *plugin);
|
||||
static int driver_uninit(neu_plugin_t *plugin);
|
||||
static int driver_start(neu_plugin_t *plugin);
|
||||
static int driver_stop(neu_plugin_t *plugin);
|
||||
static int driver_config(neu_plugin_t *plugin, const char *config);
|
||||
static int driver_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
|
||||
void *data);
|
||||
|
||||
@@ -59,18 +56,18 @@ static const neu_plugin_intf_funs_t plugin_intf_funs = {
|
||||
|
||||
const neu_plugin_module_t neu_plugin_module = {
|
||||
.version = NEURON_PLUGIN_VER_1_0,
|
||||
.schema = "modbus-tcp",
|
||||
.module_name = "Modbus TCP",
|
||||
.schema = "modbus-tcp-community",
|
||||
.module_name = "Modbus TCP community",
|
||||
.module_descr =
|
||||
"The modbus tcp plugin is an enhanced version of the modbus tcp "
|
||||
"plugin, users can choose to connect as a client or a server.",
|
||||
.module_descr_zh = "该插件是 modbus tcp "
|
||||
"插件的加强版,用户可选择作为客户端连接,还是服务端连接",
|
||||
"The modbus-tcp community plugin is used for devices connected using "
|
||||
"the modbus protocol tcp mode.",
|
||||
.module_descr_zh =
|
||||
"modbus-tcp community 插件用于连接使用 modbus tcp 协议的设备",
|
||||
.intf_funs = &plugin_intf_funs,
|
||||
.kind = NEU_PLUGIN_KIND_SYSTEM,
|
||||
.type = NEU_NA_TYPE_DRIVER,
|
||||
.display = true,
|
||||
.single = false,
|
||||
.display = true,
|
||||
};
|
||||
|
||||
static neu_plugin_t *driver_open(void)
|
||||
@@ -91,17 +88,17 @@ static int driver_close(neu_plugin_t *plugin)
|
||||
|
||||
static int driver_init(neu_plugin_t *plugin)
|
||||
{
|
||||
plugin->protocol = MODBUS_PROTOCOL_TCP;
|
||||
plugin->events = neu_event_new();
|
||||
plugin->stack = modbus_stack_create((void *) plugin, MODBUS_PROTOCOL_TCP,
|
||||
modbus_send_msg, modbus_value_handle,
|
||||
modbus_write_resp);
|
||||
plugin->events = neu_event_new();
|
||||
plugin->stack = modbus_stack_create((void *) plugin, modbus_send_msg,
|
||||
modbus_value_handle, modbus_write_resp);
|
||||
plog_notice(plugin, "%s init success", plugin->common.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_uninit(neu_plugin_t *plugin)
|
||||
{
|
||||
plog_notice(plugin, "%s uninit start", plugin->common.name);
|
||||
if (plugin->conn != NULL) {
|
||||
neu_conn_destory(plugin->conn);
|
||||
}
|
||||
@@ -112,7 +109,7 @@ static int driver_uninit(neu_plugin_t *plugin)
|
||||
|
||||
neu_event_close(plugin->events);
|
||||
|
||||
plog_info(plugin, "node: modbus uninit ok");
|
||||
plog_notice(plugin, "%s uninit success", plugin->common.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -120,12 +117,14 @@ static int driver_uninit(neu_plugin_t *plugin)
|
||||
static int driver_start(neu_plugin_t *plugin)
|
||||
{
|
||||
neu_conn_start(plugin->conn);
|
||||
plog_notice(plugin, "%s start success", plugin->common.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_stop(neu_plugin_t *plugin)
|
||||
{
|
||||
neu_conn_stop(plugin->conn);
|
||||
plog_notice(plugin, "%s stop success", plugin->common.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -136,46 +135,33 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
neu_json_elem_t port = { .name = "port", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t timeout = { .name = "timeout", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t host = { .name = "host", .t = NEU_JSON_STR };
|
||||
neu_json_elem_t interval = { .name = "interval", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t mode = { .name = "connection_mode", .t = NEU_JSON_INT };
|
||||
neu_conn_param_t param = { 0 };
|
||||
neu_conn_param_t param = { 0 };
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 5, &port, &host, &mode,
|
||||
&timeout, &interval);
|
||||
ret =
|
||||
neu_parse_param((char *) config, &err_param, 3, &port, &host, &timeout);
|
||||
|
||||
if (ret != 0) {
|
||||
plog_warn(plugin, "config: %s, decode error: %s", config, err_param);
|
||||
plog_error(plugin, "config: %s, decode error: %s", (char *) config,
|
||||
err_param);
|
||||
free(err_param);
|
||||
free(host.v.val_str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
param.log = plugin->common.log;
|
||||
plugin->interval = interval.v.val_int;
|
||||
if (mode.v.val_int == 1) {
|
||||
param.type = NEU_CONN_TCP_SERVER;
|
||||
param.params.tcp_server.ip = host.v.val_str;
|
||||
param.params.tcp_server.port = port.v.val_int;
|
||||
param.params.tcp_server.start_listen = modbus_tcp_server_listen;
|
||||
param.params.tcp_server.stop_listen = modbus_tcp_server_stop;
|
||||
param.params.tcp_server.timeout = timeout.v.val_int;
|
||||
param.params.tcp_server.max_link = 1;
|
||||
plugin->is_server = true;
|
||||
} else {
|
||||
param.type = NEU_CONN_TCP_CLIENT;
|
||||
param.params.tcp_client.ip = host.v.val_str;
|
||||
param.params.tcp_client.port = port.v.val_int;
|
||||
param.params.tcp_client.timeout = timeout.v.val_int;
|
||||
plugin->is_server = false;
|
||||
}
|
||||
param.log = plugin->common.log;
|
||||
param.type = NEU_CONN_TCP_CLIENT;
|
||||
param.params.tcp_client.ip = host.v.val_str;
|
||||
param.params.tcp_client.port = port.v.val_int;
|
||||
param.params.tcp_client.timeout = timeout.v.val_int;
|
||||
|
||||
plog_info(plugin, "config: host: %s, port: %" PRId64 ", mode: %" PRId64 "",
|
||||
host.v.val_str, port.v.val_int, mode.v.val_int);
|
||||
plog_notice(plugin,
|
||||
"config: host: %s, port: %" PRId64 ", timeout: %" PRId64,
|
||||
host.v.val_str, port.v.val_int, timeout.v.val_int);
|
||||
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
|
||||
if (plugin->conn != NULL) {
|
||||
plugin->conn = neu_conn_reconfig(plugin->conn, ¶m);
|
||||
} else {
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
|
||||
plugin->conn =
|
||||
neu_conn_new(¶m, (void *) plugin, modbus_conn_connected,
|
||||
modbus_conn_disconnected);
|
||||
@@ -200,13 +186,21 @@ static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag)
|
||||
|
||||
int ret = modbus_tag_to_point(tag, &point);
|
||||
if (ret == 0) {
|
||||
plog_debug(
|
||||
plog_notice(
|
||||
plugin,
|
||||
"validate tag success, name: %s, address: %s, type: %d, slave id: "
|
||||
"%d, start address: %d, n register: %d, area: %s",
|
||||
tag->name, tag->address, tag->type, point.slave_id,
|
||||
point.start_address, point.n_register,
|
||||
modbus_area_to_str(point.area));
|
||||
} else {
|
||||
plog_error(
|
||||
plugin,
|
||||
"validate tag error, name: %s, address: %s, type: %d, slave id: "
|
||||
"%d, start address: %d, n register: %d, area: %s",
|
||||
tag->name, tag->address, tag->type, point.slave_id,
|
||||
point.start_address, point.n_register,
|
||||
modbus_area_to_str(point.area));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#define METRIC_GLOBAL_TMPL \
|
||||
"# HELP os_info OS distro and kernel version\n" \
|
||||
"# TYPE os_info gauge\n" \
|
||||
"os_info[version=\"%s\"] 0\n" \
|
||||
"os_info[kernel=\"%s\"] 0\n" \
|
||||
"os_info{version=\"%s\"} 0\n" \
|
||||
"os_info{kernel=\"%s\"} 0\n" \
|
||||
"# HELP cpu_percent Total CPU utilisation percentage\n" \
|
||||
"# TYPE cpu_percent gauge\n" \
|
||||
"cpu_percent %u\n" \
|
||||
@@ -109,8 +109,8 @@ static int response(nng_aio *aio, char *content, enum nng_http_status status)
|
||||
nng_http_res_set_status(res, status);
|
||||
|
||||
nng_http_req *nng_req = nng_aio_get_input(aio, 0);
|
||||
nlog_notice("%s %s [%d]", nng_http_req_get_method(nng_req),
|
||||
nng_http_req_get_uri(nng_req), status);
|
||||
nlog_info("%s %s [%d]", nng_http_req_get_method(nng_req),
|
||||
nng_http_req_get_uri(nng_req), status);
|
||||
|
||||
nng_aio_set_output(aio, 0, res);
|
||||
nng_aio_finish(aio, 0);
|
||||
@@ -159,7 +159,14 @@ static inline void gen_global_metrics(const neu_metrics_t *metrics,
|
||||
static inline void
|
||||
gen_single_node_metrics(const neu_node_metrics_t *node_metrics, FILE *stream)
|
||||
{
|
||||
fprintf(stream,
|
||||
"# HELP node_type Driver(1) or APP(2)\n"
|
||||
"# TYPE node_type gauge\n"
|
||||
"node_type{node=\"%s\"} %d\n",
|
||||
node_metrics->name, node_metrics->type);
|
||||
|
||||
neu_metric_entry_t *e = NULL;
|
||||
|
||||
HASH_LOOP(hh, node_metrics->entries, e)
|
||||
{
|
||||
fprintf(stream,
|
||||
@@ -208,9 +215,28 @@ static void gen_all_node_metrics(const neu_metrics_t *metrics, int type_filter,
|
||||
neu_group_metrics_t *g = NULL;
|
||||
neu_node_metrics_t * n = NULL;
|
||||
|
||||
bool commented = false;
|
||||
HASH_LOOP(hh, metrics->node_metrics, n)
|
||||
{
|
||||
if (!(type_filter & n->type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!commented) {
|
||||
commented = true;
|
||||
fprintf(stream,
|
||||
"# HELP node_type Driver(1) or APP(2)\n"
|
||||
"# TYPE node_type gauge\n");
|
||||
}
|
||||
|
||||
fprintf(stream, "node_type{node=\"%s\"} %d\n", n->name, n->type);
|
||||
}
|
||||
|
||||
n = NULL;
|
||||
|
||||
HASH_LOOP(hh, metrics->registered_metrics, r)
|
||||
{
|
||||
bool commented = false;
|
||||
commented = false;
|
||||
HASH_LOOP(hh, metrics->node_metrics, n)
|
||||
{
|
||||
if (!(type_filter & n->type)) {
|
||||
@@ -282,8 +308,8 @@ void handle_get_metric(nng_aio *aio)
|
||||
const char *cat_param = neu_http_get_param(aio, "category", &cat_param_len);
|
||||
if (NULL != cat_param &&
|
||||
!parse_metrics_catgory(cat_param, cat_param_len, &cat)) {
|
||||
plog_info(plugin, "invalid metrics category: %.*s", (int) cat_param_len,
|
||||
cat_param);
|
||||
plog_error(plugin, "invalid metrics category: %.*s",
|
||||
(int) cat_param_len, cat_param);
|
||||
status = NNG_HTTP_STATUS_BAD_REQUEST;
|
||||
goto end;
|
||||
}
|
||||
|
||||
+17
-16
@@ -37,15 +37,15 @@ static void connect_cb(void *data)
|
||||
{
|
||||
neu_plugin_t *plugin = data;
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_CONNECTED;
|
||||
plog_info(plugin, "plugin `%s` connected", neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "plugin `%s` connected", neu_plugin_module.module_name);
|
||||
}
|
||||
|
||||
static void disconnect_cb(void *data)
|
||||
{
|
||||
neu_plugin_t *plugin = data;
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
|
||||
plog_info(plugin, "plugin `%s` disconnected",
|
||||
neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "plugin `%s` disconnected",
|
||||
neu_plugin_module.module_name);
|
||||
}
|
||||
|
||||
static nng_http_server *server_init()
|
||||
@@ -54,7 +54,7 @@ static nng_http_server *server_init()
|
||||
nng_http_server *server = NULL;
|
||||
const char * host_port = "http://0.0.0.0:7000";
|
||||
|
||||
nlog_info("monitor bind url: %s", host_port);
|
||||
nlog_notice("monitor bind url: %s", host_port);
|
||||
|
||||
int ret = nng_url_parse(&url, host_port);
|
||||
if (0 != ret) {
|
||||
@@ -179,7 +179,7 @@ static inline void stop_heartbeart_timer(neu_plugin_t *plugin)
|
||||
if (plugin->heartbeat_timer) {
|
||||
neu_event_del_timer(plugin->events, plugin->heartbeat_timer);
|
||||
plugin->heartbeat_timer = NULL;
|
||||
plog_info(plugin, "heartbeat timer stopped");
|
||||
plog_notice(plugin, "heartbeat timer stopped");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ end:
|
||||
}
|
||||
plugin->heartbeat_timer = timer;
|
||||
|
||||
plog_info(plugin, "start_hearbeat_timer interval: %" PRIu64, interval);
|
||||
plog_notice(plugin, "start_hearbeat_timer interval: %" PRIu64, interval);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -286,8 +286,8 @@ static int monitor_plugin_close(neu_plugin_t *plugin)
|
||||
nng_http_server_stop(plugin->api_server);
|
||||
nng_http_server_release(plugin->api_server);
|
||||
pthread_mutex_destroy(&plugin->mutex);
|
||||
plog_info(plugin, "Success to free plugin: %s",
|
||||
neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "Success to free plugin: %s",
|
||||
neu_plugin_module.module_name);
|
||||
free(plugin);
|
||||
|
||||
return rv;
|
||||
@@ -298,7 +298,7 @@ static int monitor_plugin_init(neu_plugin_t *plugin)
|
||||
int rv = 0;
|
||||
(void) plugin;
|
||||
|
||||
plog_info(plugin, "Initialize plugin: %s", neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "Initialize plugin: %s", neu_plugin_module.module_name);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -308,7 +308,8 @@ static int monitor_plugin_uninit(neu_plugin_t *plugin)
|
||||
|
||||
uninit_timers_and_mqtt(plugin);
|
||||
|
||||
plog_info(plugin, "Uninitialize plugin: %s", neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "Uninitialize plugin: %s",
|
||||
neu_plugin_module.module_name);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -372,7 +373,7 @@ static int monitor_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
memmove(plugin->config, &config, sizeof(config));
|
||||
// `config` moved, do not call monitor_config_fini
|
||||
|
||||
plog_info(plugin, "config plugin `%s` success", plugin_name);
|
||||
plog_notice(plugin, "config plugin `%s` success", plugin_name);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
@@ -423,7 +424,7 @@ static int monitor_plugin_start(neu_plugin_t *plugin)
|
||||
const char *plugin_name = neu_plugin_module.module_name;
|
||||
|
||||
if (NULL == plugin->mqtt_client) {
|
||||
plog_info(plugin, "mqtt client is NULL");
|
||||
plog_notice(plugin, "mqtt client is NULL");
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -443,7 +444,7 @@ static int monitor_plugin_start(neu_plugin_t *plugin)
|
||||
end:
|
||||
if (0 == rv) {
|
||||
plugin->started = true;
|
||||
plog_info(plugin, "start plugin `%s` success", plugin_name);
|
||||
plog_notice(plugin, "start plugin `%s` success", plugin_name);
|
||||
} else {
|
||||
plog_error(plugin, "start plugin `%s` failed, error %d", plugin_name,
|
||||
rv);
|
||||
@@ -456,13 +457,13 @@ static int monitor_plugin_stop(neu_plugin_t *plugin)
|
||||
{
|
||||
if (plugin->mqtt_client) {
|
||||
neu_mqtt_client_close(plugin->mqtt_client);
|
||||
plog_info(plugin, "mqtt client closed");
|
||||
plog_notice(plugin, "mqtt client closed");
|
||||
}
|
||||
|
||||
stop_heartbeart_timer(plugin);
|
||||
plugin->started = false;
|
||||
plog_info(plugin, "stop plugin `%s` success",
|
||||
neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "stop plugin `%s` success",
|
||||
neu_plugin_module.module_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,12 +75,12 @@ static inline int parse_ssl_params(neu_plugin_t *plugin, const char *setting,
|
||||
// ssl, optional
|
||||
int ret = neu_parse_param(setting, NULL, 1, ssl);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no ssl");
|
||||
plog_notice(plugin, "setting no ssl");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (false == ssl->v.val_bool) {
|
||||
plog_info(plugin, "setting ssl disabled");
|
||||
plog_notice(plugin, "setting ssl disabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ static inline int parse_ssl_params(neu_plugin_t *plugin, const char *setting,
|
||||
// cert, optional
|
||||
ret = neu_parse_param(setting, NULL, 1, cert);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no cert");
|
||||
plog_notice(plugin, "setting no cert");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ static inline int parse_ssl_params(neu_plugin_t *plugin, const char *setting,
|
||||
// keypass, optional
|
||||
ret = neu_parse_param(setting, NULL, 1, keypass);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no keypass");
|
||||
plog_notice(plugin, "setting no keypass");
|
||||
} else if (0 == strlen(keypass->v.val_str)) {
|
||||
plog_error(plugin, "setting invalid keypass");
|
||||
return -1;
|
||||
@@ -280,13 +280,13 @@ int monitor_config_parse(neu_plugin_t *plugin, const char *setting,
|
||||
// username, optional
|
||||
ret = neu_parse_param(setting, NULL, 1, &username);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no username");
|
||||
plog_notice(plugin, "setting no username");
|
||||
}
|
||||
|
||||
// password, optional
|
||||
ret = neu_parse_param(setting, NULL, 1, &password);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no password");
|
||||
plog_notice(plugin, "setting no password");
|
||||
}
|
||||
|
||||
ret = parse_ssl_params(plugin, setting, &ssl, &ca, &cert, &key, &keypass);
|
||||
@@ -313,48 +313,54 @@ int monitor_config_parse(neu_plugin_t *plugin, const char *setting,
|
||||
config->key = key.v.val_str;
|
||||
config->keypass = keypass.v.val_str;
|
||||
|
||||
plog_info(plugin, "config client-id : %s", config->client_id);
|
||||
plog_info(plugin, "config event-topic-prefix: %s",
|
||||
config->event_topic_prefix);
|
||||
plog_info(plugin, "config heartbeat-interval: %" PRIu64,
|
||||
config->heartbeat_interval);
|
||||
plog_info(plugin, "config heartbeat-topic : %s", config->heartbeat_topic);
|
||||
plog_info(plugin, "config host : %s", config->host);
|
||||
plog_info(plugin, "config port : %" PRIu16, config->port);
|
||||
plog_notice(plugin, "config client-id : %s", config->client_id);
|
||||
plog_notice(plugin, "config event-topic-prefix: %s",
|
||||
config->event_topic_prefix);
|
||||
plog_notice(plugin, "config heartbeat-interval: %" PRIu64,
|
||||
config->heartbeat_interval);
|
||||
plog_notice(plugin, "config heartbeat-topic : %s",
|
||||
config->heartbeat_topic);
|
||||
plog_notice(plugin, "config host : %s", config->host);
|
||||
plog_notice(plugin, "config port : %" PRIu16, config->port);
|
||||
|
||||
if (config->username) {
|
||||
plog_info(plugin, "config username : %s", config->username);
|
||||
plog_notice(plugin, "config username : %s", config->username);
|
||||
}
|
||||
if (config->password) {
|
||||
plog_info(plugin, "config password : %s",
|
||||
0 == strlen(config->password) ? "" : placeholder);
|
||||
plog_notice(plugin, "config password : %s",
|
||||
0 == strlen(config->password) ? "" : placeholder);
|
||||
}
|
||||
if (config->ca) {
|
||||
plog_info(plugin, "config ca : %s", placeholder);
|
||||
plog_notice(plugin, "config ca : %s", placeholder);
|
||||
}
|
||||
if (config->cert) {
|
||||
plog_info(plugin, "config cert : %s", placeholder);
|
||||
plog_notice(plugin, "config cert : %s", placeholder);
|
||||
}
|
||||
if (config->key) {
|
||||
plog_info(plugin, "config key : %s", placeholder);
|
||||
plog_notice(plugin, "config key : %s", placeholder);
|
||||
}
|
||||
if (config->keypass) {
|
||||
plog_info(plugin, "config keypass : %s", placeholder);
|
||||
plog_notice(plugin, "config keypass : %s", placeholder);
|
||||
}
|
||||
|
||||
plog_info(plugin, "node add event topic : %s", config->node_add_topic);
|
||||
plog_info(plugin, "node del event topic : %s", config->node_del_topic);
|
||||
plog_info(plugin, "node ctl event topic : %s", config->node_ctl_topic);
|
||||
plog_info(plugin, "node setting event topic : %s",
|
||||
config->node_setting_topic);
|
||||
plog_info(plugin, "group add topic : %s", config->group_add_topic);
|
||||
plog_info(plugin, "group del topic : %s", config->group_del_topic);
|
||||
plog_info(plugin, "group update topic : %s",
|
||||
config->group_update_topic);
|
||||
plog_info(plugin, "tag add topic : %s", config->tag_add_topic);
|
||||
plog_info(plugin, "tag del topic : %s", config->tag_del_topic);
|
||||
plog_info(plugin, "tag update topic : %s",
|
||||
config->tag_update_topic);
|
||||
plog_notice(plugin, "node add event topic : %s",
|
||||
config->node_add_topic);
|
||||
plog_notice(plugin, "node del event topic : %s",
|
||||
config->node_del_topic);
|
||||
plog_notice(plugin, "node ctl event topic : %s",
|
||||
config->node_ctl_topic);
|
||||
plog_notice(plugin, "node setting event topic : %s",
|
||||
config->node_setting_topic);
|
||||
plog_notice(plugin, "group add topic : %s",
|
||||
config->group_add_topic);
|
||||
plog_notice(plugin, "group del topic : %s",
|
||||
config->group_del_topic);
|
||||
plog_notice(plugin, "group update topic : %s",
|
||||
config->group_update_topic);
|
||||
plog_notice(plugin, "tag add topic : %s", config->tag_add_topic);
|
||||
plog_notice(plugin, "tag del topic : %s", config->tag_del_topic);
|
||||
plog_notice(plugin, "tag update topic : %s",
|
||||
config->tag_update_topic);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
+25
-1
@@ -57,6 +57,30 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"write-req-topic": {
|
||||
"name": "Write Request Topic",
|
||||
"name_zh": "写请求主题",
|
||||
"description": "MQTT topic to receive write request messages.",
|
||||
"description_zh": "接收点位写入请求的 MQTT 主题。",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"default": "/neuron/${node-name}/write/req",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"write-resp-topic": {
|
||||
"name": "Write Response Topic",
|
||||
"name_zh": "写响应主题",
|
||||
"description": "MQTT topic to send write response messages.",
|
||||
"description_zh": "发送点位写入响应的 MQTT 主题。",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"default": "/neuron/${node-name}/write/resp",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"offline-cache": {
|
||||
"name": "Offline Data Caching",
|
||||
"name_zh": "离线缓存",
|
||||
@@ -218,4 +242,4 @@
|
||||
"length": 256
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+78
-39
@@ -17,6 +17,7 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
#include "utils/asprintf.h"
|
||||
#include "json/json.h"
|
||||
#include "json/neu_json_param.h"
|
||||
|
||||
@@ -71,12 +72,12 @@ static inline int parse_ssl_params(neu_plugin_t *plugin, const char *setting,
|
||||
// ssl, optional
|
||||
int ret = neu_parse_param(setting, NULL, 1, ssl);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no ssl");
|
||||
plog_notice(plugin, "setting no ssl");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (false == ssl->v.val_bool) {
|
||||
plog_info(plugin, "setting ssl disabled");
|
||||
plog_notice(plugin, "setting ssl disabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -89,7 +90,7 @@ static inline int parse_ssl_params(neu_plugin_t *plugin, const char *setting,
|
||||
// cert, optional
|
||||
ret = neu_parse_param(setting, NULL, 1, cert);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no cert");
|
||||
plog_notice(plugin, "setting no cert");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ static inline int parse_ssl_params(neu_plugin_t *plugin, const char *setting,
|
||||
// keypass, optional
|
||||
ret = neu_parse_param(setting, NULL, 1, keypass);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no keypass");
|
||||
plog_notice(plugin, "setting no keypass");
|
||||
} else if (0 == strlen(keypass->v.val_str)) {
|
||||
plog_error(plugin, "setting invalid keypass");
|
||||
return -1;
|
||||
@@ -127,7 +128,7 @@ static int parse_cache_params(neu_plugin_t *plugin, const char *setting,
|
||||
// offline-cache flag, optional
|
||||
ret = neu_parse_param(setting, NULL, 1, offline_cache);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no offline cache flag");
|
||||
plog_notice(plugin, "setting no offline cache flag");
|
||||
flag_present = false; // `offline-cache` not present in setting
|
||||
}
|
||||
|
||||
@@ -203,6 +204,18 @@ int mqtt_config_parse(neu_plugin_t *plugin, const char *setting,
|
||||
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL, // for backward compatibility
|
||||
};
|
||||
neu_json_elem_t format = { .name = "format", .t = NEU_JSON_INT };
|
||||
neu_json_elem_t write_req_topic = {
|
||||
.name = "write-req-topic",
|
||||
.t = NEU_JSON_STR,
|
||||
.v.val_str = NULL,
|
||||
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL, // for backward compatibility
|
||||
};
|
||||
neu_json_elem_t write_resp_topic = {
|
||||
.name = "write-resp-topic",
|
||||
.t = NEU_JSON_STR,
|
||||
.v.val_str = NULL,
|
||||
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL, // for backward compatibility
|
||||
};
|
||||
neu_json_elem_t offline_cache = { .name = "offline-cache",
|
||||
.t = NEU_JSON_BOOL };
|
||||
neu_json_elem_t cache_mem_size = { .name = "cache-mem-size",
|
||||
@@ -224,8 +237,8 @@ int mqtt_config_parse(neu_plugin_t *plugin, const char *setting,
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = neu_parse_param(setting, &err_param, 5, &client_id, &format, &qos,
|
||||
&host, &port);
|
||||
ret = neu_parse_param(setting, &err_param, 7, &client_id, &qos, &format,
|
||||
&write_req_topic, &write_resp_topic, &host, &port);
|
||||
if (0 != ret) {
|
||||
plog_error(plugin, "parsing setting fail, key: `%s`", err_param);
|
||||
goto error;
|
||||
@@ -251,6 +264,22 @@ int mqtt_config_parse(neu_plugin_t *plugin, const char *setting,
|
||||
goto error;
|
||||
}
|
||||
|
||||
// write request topic
|
||||
if (NULL == write_req_topic.v.val_str &&
|
||||
0 > neu_asprintf(&write_req_topic.v.val_str, "/neuron/%s/write/req",
|
||||
plugin->common.name)) {
|
||||
plog_error(plugin, "setting write request topic error");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// write response topic
|
||||
if (NULL == write_resp_topic.v.val_str &&
|
||||
0 > neu_asprintf(&write_resp_topic.v.val_str, "/neuron/%s/write/resp",
|
||||
plugin->common.name)) {
|
||||
plog_error(plugin, "setting write response topic error");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// offline cache
|
||||
ret = parse_cache_params(plugin, setting, &offline_cache, &cache_mem_size,
|
||||
&cache_disk_size);
|
||||
@@ -273,13 +302,13 @@ int mqtt_config_parse(neu_plugin_t *plugin, const char *setting,
|
||||
// username, optional
|
||||
ret = neu_parse_param(setting, NULL, 1, &username);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no username");
|
||||
plog_notice(plugin, "setting no username");
|
||||
}
|
||||
|
||||
// password, optional
|
||||
ret = neu_parse_param(setting, NULL, 1, &password);
|
||||
if (0 != ret) {
|
||||
plog_info(plugin, "setting no password");
|
||||
plog_notice(plugin, "setting no password");
|
||||
}
|
||||
|
||||
ret = parse_ssl_params(plugin, setting, &ssl, &ca, &cert, &key, &keypass);
|
||||
@@ -287,55 +316,63 @@ int mqtt_config_parse(neu_plugin_t *plugin, const char *setting,
|
||||
goto error;
|
||||
}
|
||||
|
||||
config->client_id = client_id.v.val_str;
|
||||
config->qos = qos.v.val_int;
|
||||
config->format = format.v.val_int;
|
||||
config->cache = offline_cache.v.val_bool;
|
||||
config->cache_mem_size = cache_mem_size.v.val_int * MB;
|
||||
config->cache_disk_size = cache_disk_size.v.val_int * MB;
|
||||
config->host = host.v.val_str;
|
||||
config->port = port.v.val_int;
|
||||
config->username = username.v.val_str;
|
||||
config->password = password.v.val_str;
|
||||
config->ca = ca.v.val_str;
|
||||
config->cert = cert.v.val_str;
|
||||
config->key = key.v.val_str;
|
||||
config->keypass = keypass.v.val_str;
|
||||
config->client_id = client_id.v.val_str;
|
||||
config->qos = qos.v.val_int;
|
||||
config->format = format.v.val_int;
|
||||
config->write_req_topic = write_req_topic.v.val_str;
|
||||
config->write_resp_topic = write_resp_topic.v.val_str;
|
||||
config->cache = offline_cache.v.val_bool;
|
||||
config->cache_mem_size = cache_mem_size.v.val_int * MB;
|
||||
config->cache_disk_size = cache_disk_size.v.val_int * MB;
|
||||
config->host = host.v.val_str;
|
||||
config->port = port.v.val_int;
|
||||
config->username = username.v.val_str;
|
||||
config->password = password.v.val_str;
|
||||
config->ca = ca.v.val_str;
|
||||
config->cert = cert.v.val_str;
|
||||
config->key = key.v.val_str;
|
||||
config->keypass = keypass.v.val_str;
|
||||
|
||||
plog_info(plugin, "config client-id : %s", config->client_id);
|
||||
plog_info(plugin, "config qos : %d", config->qos);
|
||||
plog_info(plugin, "config format : %s",
|
||||
mqtt_upload_format_str(config->format));
|
||||
plog_info(plugin, "config cache : %zu", config->cache);
|
||||
plog_info(plugin, "config cache-mem-size : %zu", config->cache_mem_size);
|
||||
plog_info(plugin, "config cache-disk-size: %zu", config->cache_disk_size);
|
||||
plog_info(plugin, "config host : %s", config->host);
|
||||
plog_info(plugin, "config port : %" PRIu16, config->port);
|
||||
plog_notice(plugin, "config client-id : %s", config->client_id);
|
||||
plog_notice(plugin, "config qos : %d", config->qos);
|
||||
plog_notice(plugin, "config format : %s",
|
||||
mqtt_upload_format_str(config->format));
|
||||
plog_notice(plugin, "config write-req-topic : %s", config->write_req_topic);
|
||||
plog_notice(plugin, "config write-resp-topic: %s",
|
||||
config->write_resp_topic);
|
||||
plog_notice(plugin, "config cache : %zu", config->cache);
|
||||
plog_notice(plugin, "config cache-mem-size : %zu", config->cache_mem_size);
|
||||
plog_notice(plugin, "config cache-disk-size : %zu",
|
||||
config->cache_disk_size);
|
||||
plog_notice(plugin, "config host : %s", config->host);
|
||||
plog_notice(plugin, "config port : %" PRIu16, config->port);
|
||||
|
||||
if (config->username) {
|
||||
plog_info(plugin, "config username : %s", config->username);
|
||||
plog_notice(plugin, "config username : %s", config->username);
|
||||
}
|
||||
if (config->password) {
|
||||
plog_info(plugin, "config password : %s",
|
||||
0 == strlen(config->password) ? "" : placeholder);
|
||||
plog_notice(plugin, "config password : %s",
|
||||
0 == strlen(config->password) ? "" : placeholder);
|
||||
}
|
||||
if (config->ca) {
|
||||
plog_info(plugin, "config ca : %s", placeholder);
|
||||
plog_notice(plugin, "config ca : %s", placeholder);
|
||||
}
|
||||
if (config->cert) {
|
||||
plog_info(plugin, "config cert : %s", placeholder);
|
||||
plog_notice(plugin, "config cert : %s", placeholder);
|
||||
}
|
||||
if (config->key) {
|
||||
plog_info(plugin, "config key : %s", placeholder);
|
||||
plog_notice(plugin, "config key : %s", placeholder);
|
||||
}
|
||||
if (config->keypass) {
|
||||
plog_info(plugin, "config keypass : %s", placeholder);
|
||||
plog_notice(plugin, "config keypass : %s", placeholder);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free(err_param);
|
||||
free(write_req_topic.v.val_str);
|
||||
free(write_resp_topic.v.val_str);
|
||||
free(host.v.val_str);
|
||||
free(username.v.val_str);
|
||||
free(password.v.val_str);
|
||||
@@ -349,6 +386,8 @@ error:
|
||||
void mqtt_config_fini(mqtt_config_t *config)
|
||||
{
|
||||
free(config->client_id);
|
||||
free(config->write_req_topic);
|
||||
free(config->write_resp_topic);
|
||||
free(config->host);
|
||||
free(config->username);
|
||||
free(config->password);
|
||||
|
||||
+16
-14
@@ -48,20 +48,22 @@ static inline const char *mqtt_upload_format_str(mqtt_upload_format_e f)
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char * client_id; // client id
|
||||
mqtt_upload_format_e format; // upload format
|
||||
neu_mqtt_qos_e qos; // message QoS
|
||||
size_t cache; // cache enable flag
|
||||
size_t cache_mem_size; // cache memory size in bytes
|
||||
size_t cache_disk_size; // cache disk size in bytes
|
||||
char * host; // broker host
|
||||
uint16_t port; // broker port
|
||||
char * username; // user name
|
||||
char * password; // user password
|
||||
char * ca; // CA
|
||||
char * cert; // client cert
|
||||
char * key; // client key
|
||||
char * keypass; // client key password
|
||||
char * client_id; // client id
|
||||
neu_mqtt_qos_e qos; // message QoS
|
||||
mqtt_upload_format_e format; // upload format
|
||||
char * write_req_topic; // write request topic
|
||||
char * write_resp_topic; // write response topic
|
||||
size_t cache; // cache enable flag
|
||||
size_t cache_mem_size; // cache memory size in bytes
|
||||
size_t cache_disk_size; // cache disk size in bytes
|
||||
char * host; // broker host
|
||||
uint16_t port; // broker port
|
||||
char * username; // user name
|
||||
char * password; // user password
|
||||
char * ca; // CA
|
||||
char * cert; // client cert
|
||||
char * key; // client key
|
||||
char * keypass; // client key password
|
||||
} mqtt_config_t;
|
||||
|
||||
int mqtt_config_parse(neu_plugin_t *plugin, const char *setting,
|
||||
|
||||
@@ -194,8 +194,8 @@ static char *generate_write_resp_json(neu_plugin_t * plugin,
|
||||
static inline int send_read_req(neu_plugin_t *plugin, neu_json_mqtt_t *mqtt,
|
||||
neu_json_read_req_t *req)
|
||||
{
|
||||
plog_info(plugin, "read uuid:%s, group:%s, node:%s", mqtt->uuid, req->group,
|
||||
req->node);
|
||||
plog_notice(plugin, "read uuid:%s, group:%s, node:%s", mqtt->uuid,
|
||||
req->group, req->node);
|
||||
|
||||
neu_reqresp_head_t header = { 0 };
|
||||
header.ctx = mqtt;
|
||||
@@ -214,8 +214,8 @@ static inline int send_read_req(neu_plugin_t *plugin, neu_json_mqtt_t *mqtt,
|
||||
static int send_write_req(neu_plugin_t *plugin, neu_json_mqtt_t *mqtt,
|
||||
neu_json_write_req_t *req)
|
||||
{
|
||||
plog_info(plugin, "write uuid:%s, group:%s, node:%s", mqtt->uuid,
|
||||
req->group, req->node);
|
||||
plog_notice(plugin, "write uuid:%s, group:%s, node:%s", mqtt->uuid,
|
||||
req->group, req->node);
|
||||
|
||||
neu_reqresp_head_t header = { 0 };
|
||||
neu_req_write_tag_t cmd = { 0 };
|
||||
@@ -373,7 +373,7 @@ int handle_write_response(neu_plugin_t *plugin, neu_json_mqtt_t *mqtt_json,
|
||||
goto end;
|
||||
}
|
||||
|
||||
char * topic = plugin->write_resp_topic;
|
||||
char * topic = plugin->config.write_resp_topic;
|
||||
neu_mqtt_qos_e qos = plugin->config.qos;
|
||||
rv = publish(plugin, qos, topic, json_str, strlen(json_str));
|
||||
json_str = NULL;
|
||||
@@ -538,8 +538,8 @@ int handle_subscribe_group(neu_plugin_t *plugin, neu_req_subscribe_t *sub_info)
|
||||
goto end;
|
||||
}
|
||||
|
||||
plog_info(plugin, "route driver:%s group:%s to topic:%s", sub_info->driver,
|
||||
sub_info->group, topic.v.val_str);
|
||||
plog_notice(plugin, "route driver:%s group:%s to topic:%s",
|
||||
sub_info->driver, sub_info->group, topic.v.val_str);
|
||||
|
||||
end:
|
||||
free(sub_info->params);
|
||||
@@ -550,7 +550,7 @@ int handle_unsubscribe_group(neu_plugin_t * plugin,
|
||||
neu_req_unsubscribe_t *unsub_info)
|
||||
{
|
||||
route_tbl_del(&plugin->route_tbl, unsub_info->driver, unsub_info->group);
|
||||
plog_info(plugin, "del route driver:%s group:%s", unsub_info->driver,
|
||||
unsub_info->group);
|
||||
plog_notice(plugin, "del route driver:%s group:%s", unsub_info->driver,
|
||||
unsub_info->group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+87
-92
@@ -18,6 +18,7 @@
|
||||
**/
|
||||
|
||||
#include "utils/asprintf.h"
|
||||
#include "utils/time.h"
|
||||
|
||||
#include "mqtt_config.h"
|
||||
#include "mqtt_handle.h"
|
||||
@@ -29,15 +30,15 @@ static void connect_cb(void *data)
|
||||
{
|
||||
neu_plugin_t *plugin = data;
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_CONNECTED;
|
||||
plog_info(plugin, "plugin `%s` connected", neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "plugin `%s` connected", neu_plugin_module.module_name);
|
||||
}
|
||||
|
||||
static void disconnect_cb(void *data)
|
||||
{
|
||||
neu_plugin_t *plugin = data;
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
|
||||
plog_info(plugin, "plugin `%s` disconnected",
|
||||
neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "plugin `%s` disconnected",
|
||||
neu_plugin_module.module_name);
|
||||
}
|
||||
|
||||
static neu_plugin_t *mqtt_plugin_open(void)
|
||||
@@ -50,7 +51,7 @@ static neu_plugin_t *mqtt_plugin_open(void)
|
||||
static int mqtt_plugin_close(neu_plugin_t *plugin)
|
||||
{
|
||||
const char *name = neu_plugin_module.module_name;
|
||||
plog_info(plugin, "success to free plugin:%s", name);
|
||||
plog_notice(plugin, "success to free plugin:%s", name);
|
||||
|
||||
free(plugin);
|
||||
return NEU_ERR_SUCCESS;
|
||||
@@ -58,8 +59,8 @@ static int mqtt_plugin_close(neu_plugin_t *plugin)
|
||||
|
||||
static int mqtt_plugin_init(neu_plugin_t *plugin)
|
||||
{
|
||||
plog_info(plugin, "initialize plugin `%s` success",
|
||||
neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "initialize plugin `%s` success",
|
||||
neu_plugin_module.module_name);
|
||||
neu_adapter_register_metric_cb_t register_metric =
|
||||
plugin->common.adapter_callbacks->register_metric;
|
||||
register_metric(plugin->common.adapter, NEU_METRIC_CACHED_MSGS_NUM,
|
||||
@@ -81,15 +82,11 @@ static int mqtt_plugin_uninit(neu_plugin_t *plugin)
|
||||
plugin->read_req_topic = NULL;
|
||||
free(plugin->read_resp_topic);
|
||||
plugin->read_resp_topic = NULL;
|
||||
free(plugin->write_req_topic);
|
||||
plugin->write_req_topic = NULL;
|
||||
free(plugin->write_resp_topic);
|
||||
plugin->write_resp_topic = NULL;
|
||||
|
||||
route_tbl_free(plugin->route_tbl);
|
||||
|
||||
plog_info(plugin, "uninitialize plugin `%s` success",
|
||||
neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "uninitialize plugin `%s` success",
|
||||
neu_plugin_module.module_name);
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -159,6 +156,65 @@ static int config_mqtt_client(neu_plugin_t *plugin, neu_mqtt_client_t *client,
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int create_topic(neu_plugin_t *plugin)
|
||||
{
|
||||
if (plugin->read_req_topic) {
|
||||
// topics already created
|
||||
return 0;
|
||||
}
|
||||
|
||||
neu_asprintf(&plugin->read_req_topic, "/neuron/%s/read/req",
|
||||
plugin->common.name);
|
||||
if (NULL == plugin->read_req_topic) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_asprintf(&plugin->read_resp_topic, "/neuron/%s/read/resp",
|
||||
plugin->common.name);
|
||||
if (NULL == plugin->read_resp_topic) {
|
||||
free(plugin->read_req_topic);
|
||||
plugin->read_req_topic = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int subscribe(neu_plugin_t *plugin, const mqtt_config_t *config)
|
||||
{
|
||||
if (0 != create_topic(plugin)) {
|
||||
plog_error(plugin, "create topics fail");
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
if (0 !=
|
||||
neu_mqtt_client_subscribe(plugin->client, config->qos,
|
||||
plugin->read_req_topic, plugin,
|
||||
handle_read_req)) {
|
||||
plog_error(plugin, "subscribe [%s] fail", plugin->read_req_topic);
|
||||
return NEU_ERR_MQTT_SUBSCRIBE_FAILURE;
|
||||
}
|
||||
|
||||
if (0 !=
|
||||
neu_mqtt_client_subscribe(plugin->client, config->qos,
|
||||
config->write_req_topic, plugin,
|
||||
handle_write_req)) {
|
||||
plog_error(plugin, "subscribe [%s] fail",
|
||||
plugin->config.write_req_topic);
|
||||
return NEU_ERR_MQTT_SUBSCRIBE_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unsubscribe(neu_plugin_t *plugin, const mqtt_config_t *config)
|
||||
{
|
||||
neu_mqtt_client_unsubscribe(plugin->client, plugin->read_req_topic);
|
||||
neu_mqtt_client_unsubscribe(plugin->client, config->write_req_topic);
|
||||
neu_msleep(100); // wait for message completion
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mqtt_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
{
|
||||
int rv = 0;
|
||||
@@ -181,7 +237,8 @@ static int mqtt_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
}
|
||||
} else if (neu_mqtt_client_is_open(plugin->client)) {
|
||||
started = true;
|
||||
rv = neu_mqtt_client_close(plugin->client);
|
||||
unsubscribe(plugin, &plugin->config);
|
||||
rv = neu_mqtt_client_close(plugin->client);
|
||||
if (0 != rv) {
|
||||
plog_error(plugin, "neu_mqtt_client_close fail");
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
@@ -195,10 +252,15 @@ static int mqtt_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (started && 0 != neu_mqtt_client_open(plugin->client)) {
|
||||
plog_error(plugin, "neu_mqtt_client_open fail");
|
||||
rv = NEU_ERR_MQTT_CONNECT_FAILURE;
|
||||
goto error;
|
||||
if (started) {
|
||||
if (0 != neu_mqtt_client_open(plugin->client)) {
|
||||
plog_error(plugin, "neu_mqtt_client_open fail");
|
||||
rv = NEU_ERR_MQTT_CONNECT_FAILURE;
|
||||
goto error;
|
||||
}
|
||||
if (0 != (rv = subscribe(plugin, &config))) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin->config.host) {
|
||||
@@ -207,61 +269,15 @@ static int mqtt_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
}
|
||||
memmove(&plugin->config, &config, sizeof(config));
|
||||
|
||||
plog_info(plugin, "config plugin `%s` success", plugin_name);
|
||||
plog_notice(plugin, "config plugin `%s` success", plugin_name);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
plog_info(plugin, "config plugin `%s` fail", plugin_name);
|
||||
plog_error(plugin, "config plugin `%s` fail", plugin_name);
|
||||
mqtt_config_fini(&config);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int create_topic(neu_plugin_t *plugin)
|
||||
{
|
||||
if (plugin->read_req_topic) {
|
||||
// topics already created
|
||||
return 0;
|
||||
}
|
||||
|
||||
neu_asprintf(&plugin->read_req_topic, "/neuron/%s/read/req",
|
||||
plugin->common.name);
|
||||
if (NULL == plugin->read_req_topic) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_asprintf(&plugin->read_resp_topic, "/neuron/%s/read/resp",
|
||||
plugin->common.name);
|
||||
if (NULL == plugin->read_resp_topic) {
|
||||
free(plugin->read_req_topic);
|
||||
plugin->read_req_topic = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_asprintf(&plugin->write_req_topic, "/neuron/%s/write/req",
|
||||
plugin->common.name);
|
||||
if (NULL == plugin->write_req_topic) {
|
||||
free(plugin->read_req_topic);
|
||||
plugin->read_req_topic = NULL;
|
||||
free(plugin->read_resp_topic);
|
||||
plugin->read_resp_topic = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_asprintf(&plugin->write_resp_topic, "/neuron/%s/write/resp",
|
||||
plugin->common.name);
|
||||
if (NULL == plugin->write_resp_topic) {
|
||||
free(plugin->read_req_topic);
|
||||
plugin->read_req_topic = NULL;
|
||||
free(plugin->read_resp_topic);
|
||||
plugin->read_resp_topic = NULL;
|
||||
free(plugin->write_req_topic);
|
||||
plugin->write_req_topic = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mqtt_plugin_start(neu_plugin_t *plugin)
|
||||
{
|
||||
int rv = 0;
|
||||
@@ -279,33 +295,11 @@ static int mqtt_plugin_start(neu_plugin_t *plugin)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (0 != create_topic(plugin)) {
|
||||
plog_error(plugin, "create topics fail");
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (0 !=
|
||||
neu_mqtt_client_subscribe(plugin->client, plugin->config.qos,
|
||||
plugin->read_req_topic, plugin,
|
||||
handle_read_req)) {
|
||||
plog_error(plugin, "subscribe [%s] fail", plugin->read_req_topic);
|
||||
rv = NEU_ERR_MQTT_SUBSCRIBE_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (0 !=
|
||||
neu_mqtt_client_subscribe(plugin->client, plugin->config.qos,
|
||||
plugin->write_req_topic, plugin,
|
||||
handle_write_req)) {
|
||||
plog_error(plugin, "subscribe [%s] fail", plugin->write_req_topic);
|
||||
rv = NEU_ERR_MQTT_SUBSCRIBE_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
rv = subscribe(plugin, &plugin->config);
|
||||
|
||||
end:
|
||||
if (0 == rv) {
|
||||
plog_info(plugin, "start plugin `%s` success", plugin_name);
|
||||
plog_notice(plugin, "start plugin `%s` success", plugin_name);
|
||||
} else {
|
||||
plog_error(plugin, "start plugin `%s` failed, error %d", plugin_name,
|
||||
rv);
|
||||
@@ -317,12 +311,13 @@ end:
|
||||
static int mqtt_plugin_stop(neu_plugin_t *plugin)
|
||||
{
|
||||
if (plugin->client) {
|
||||
unsubscribe(plugin, &plugin->config);
|
||||
neu_mqtt_client_close(plugin->client);
|
||||
plog_info(plugin, "mqtt client closed");
|
||||
plog_notice(plugin, "mqtt client closed");
|
||||
}
|
||||
|
||||
plog_info(plugin, "stop plugin `%s` success",
|
||||
neu_plugin_module.module_name);
|
||||
plog_notice(plugin, "stop plugin `%s` success",
|
||||
neu_plugin_module.module_name);
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,6 @@ struct neu_plugin {
|
||||
int64_t cache_metric_update_ts;
|
||||
char * read_req_topic;
|
||||
char * read_resp_topic;
|
||||
char * write_req_topic;
|
||||
char * write_resp_topic;
|
||||
route_entry_t * route_tbl;
|
||||
};
|
||||
|
||||
|
||||
@@ -63,7 +63,8 @@ void handle_logs_files(nng_aio *aio)
|
||||
rv = system("rm -rf /tmp/neuron_debug.tar.gz");
|
||||
nlog_warn("remove old neuron_debug.tar.gz, rv: %d", rv);
|
||||
/* tar the neuron directory */
|
||||
rv = system("tar -zcvf /tmp/neuron_debug.tar.gz ../neuron");
|
||||
rv = system("tar -zcvf /tmp/neuron_debug.tar.gz "
|
||||
"--exclude='persistence/neuron.lic' ../neuron");
|
||||
if (rv == -1) {
|
||||
nlog_error("failed to create neuron_debug.tar.gz, rv: %d", rv);
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_COMMAND_EXECUTION_FAILED, {
|
||||
|
||||
@@ -54,12 +54,20 @@ void handle_login(nng_aio *aio)
|
||||
aio, neu_json_login_req_t, neu_json_decode_login_req, {
|
||||
neu_json_login_resp_t login_resp = { 0 };
|
||||
neu_user_t * user = neu_load_user(req->name);
|
||||
int pass_len = strlen(req->pass);
|
||||
|
||||
if (NULL == user) {
|
||||
nlog_warn("could not find user `%s`", req->name);
|
||||
nlog_error("could not find user `%s`", req->name);
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_OR_PASSWORD, {
|
||||
neu_http_response(aio, error_code.error, result_error);
|
||||
});
|
||||
} else if (pass_len < NEU_USER_PASSWORD_MIN_LEN ||
|
||||
pass_len > NEU_USER_PASSWORD_MAX_LEN) {
|
||||
nlog_error("user `%s` password too short or too long",
|
||||
req->name);
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_PASSWORD_LEN, {
|
||||
neu_http_response(aio, error_code.error, result_error);
|
||||
});
|
||||
} else if (neu_user_check_password(user, req->pass)) {
|
||||
|
||||
char *token = NULL;
|
||||
@@ -81,7 +89,7 @@ void handle_login(nng_aio *aio)
|
||||
jwt_free_str(token);
|
||||
free(result);
|
||||
} else {
|
||||
nlog_warn("user `%s` password check fail", req->name);
|
||||
nlog_error("user `%s` password check fail", req->name);
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_OR_PASSWORD, {
|
||||
neu_http_response(aio, error_code.error, result_error);
|
||||
});
|
||||
@@ -224,6 +232,14 @@ static struct {
|
||||
.plugin = "Modbus TCP",
|
||||
.schema = "modbus-tcp",
|
||||
},
|
||||
{
|
||||
.plugin = "Modbus TCP community",
|
||||
.schema = "modbus-tcp-community",
|
||||
},
|
||||
{
|
||||
.plugin = "Modbus TCP QH",
|
||||
.schema = "modbus-qh-tcp",
|
||||
},
|
||||
{
|
||||
.plugin = "Monitor",
|
||||
.schema = "monitor",
|
||||
|
||||
@@ -55,7 +55,7 @@ static nng_http_server *server_init()
|
||||
nng_http_server *server;
|
||||
|
||||
snprintf(host_port, sizeof(host_port), "http://0.0.0.0:7000");
|
||||
nlog_info("bind url: %s", host_port);
|
||||
nlog_notice("bind url: %s", host_port);
|
||||
|
||||
int ret = nng_url_parse(&url, host_port);
|
||||
if (ret != 0) {
|
||||
@@ -105,7 +105,7 @@ static neu_plugin_t *dashb_plugin_open(void)
|
||||
goto server_init_fail;
|
||||
}
|
||||
|
||||
nlog_info("Success to create plugin: %s", neu_plugin_module.module_name);
|
||||
nlog_notice("Success to create plugin: %s", neu_plugin_module.module_name);
|
||||
return plugin;
|
||||
|
||||
server_init_fail:
|
||||
@@ -121,13 +121,11 @@ static int dashb_plugin_close(neu_plugin_t *plugin)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
nlog_info("Success to before free plugin: %s",
|
||||
neu_plugin_module.module_name);
|
||||
nng_http_server_stop(plugin->server);
|
||||
nng_http_server_release(plugin->server);
|
||||
|
||||
free(plugin);
|
||||
nlog_info("Success to free plugin: %s", neu_plugin_module.module_name);
|
||||
nlog_notice("Success to free plugin: %s", neu_plugin_module.module_name);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -139,7 +137,7 @@ static int dashb_plugin_init(neu_plugin_t *plugin)
|
||||
|
||||
rv = neu_jwt_init(g_config_dir);
|
||||
|
||||
nlog_info("Initialize plugin: %s", neu_plugin_module.module_name);
|
||||
nlog_notice("Initialize plugin: %s", neu_plugin_module.module_name);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -149,7 +147,7 @@ static int dashb_plugin_uninit(neu_plugin_t *plugin)
|
||||
|
||||
(void) plugin;
|
||||
|
||||
nlog_info("Uninitialize plugin: %s", neu_plugin_module.module_name);
|
||||
nlog_notice("Uninitialize plugin: %s", neu_plugin_module.module_name);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -160,7 +158,7 @@ static int dashb_plugin_config(neu_plugin_t *plugin, const char *configs)
|
||||
(void) plugin;
|
||||
(void) configs;
|
||||
|
||||
nlog_info("config plugin: %s", neu_plugin_module.module_name);
|
||||
nlog_notice("config plugin: %s", neu_plugin_module.module_name);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,6 @@ void handle_write(nng_aio *aio)
|
||||
|
||||
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
|
||||
aio, neu_json_write_req_t, neu_json_decode_write_req, {
|
||||
int ret = 0;
|
||||
neu_reqresp_head_t header = { 0 };
|
||||
neu_req_write_tag_t cmd = { 0 };
|
||||
|
||||
@@ -75,8 +74,13 @@ void handle_write(nng_aio *aio)
|
||||
cmd.value.value.u64 = req->value.val_int;
|
||||
break;
|
||||
case NEU_JSON_STR:
|
||||
cmd.value.type = NEU_TYPE_STRING;
|
||||
strcpy(cmd.value.value.str, req->value.val_str);
|
||||
if (strlen(req->value.val_str) >= NEU_VALUE_SIZE) {
|
||||
cmd.value.type = NEU_TYPE_ERROR;
|
||||
cmd.value.value.i32 = NEU_ERR_STRING_TOO_LONG;
|
||||
} else {
|
||||
cmd.value.type = NEU_TYPE_STRING;
|
||||
strcpy(cmd.value.value.str, req->value.val_str);
|
||||
}
|
||||
break;
|
||||
case NEU_JSON_DOUBLE:
|
||||
cmd.value.type = NEU_TYPE_DOUBLE;
|
||||
@@ -91,11 +95,18 @@ void handle_write(nng_aio *aio)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = neu_plugin_op(plugin, header, &cmd);
|
||||
if (ret != 0) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
|
||||
neu_http_response(aio, NEU_ERR_IS_BUSY, result_error);
|
||||
if (cmd.value.type == NEU_TYPE_ERROR) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_STRING_TOO_LONG, {
|
||||
neu_http_response(aio, NEU_ERR_STRING_TOO_LONG,
|
||||
result_error);
|
||||
});
|
||||
} else {
|
||||
int ret = neu_plugin_op(plugin, header, &cmd);
|
||||
if (ret != 0) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
|
||||
neu_http_response(aio, NEU_ERR_IS_BUSY, result_error);
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -205,11 +205,7 @@ ssize_t modbus_s_tcp_req(uint8_t *req, uint16_t req_len, uint8_t *res,
|
||||
*res_len += sizeof(struct modbus_data);
|
||||
*res_len += len;
|
||||
|
||||
if (len > 0xff) {
|
||||
res_data->n_byte = 0xff;
|
||||
} else {
|
||||
res_data->n_byte = len;
|
||||
}
|
||||
res_data->n_byte = len;
|
||||
res_header->len += sizeof(struct modbus_data) + len;
|
||||
break;
|
||||
case MODBUS_WRITE_S_COIL:
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "neuron.h"
|
||||
#include <neuron.h>
|
||||
|
||||
#include "modbus_s.h"
|
||||
|
||||
@@ -31,7 +31,6 @@ zlog_category_t *neuron = NULL;
|
||||
neu_events_t * events = NULL;
|
||||
neu_event_io_t * tcp_server_event = NULL;
|
||||
neu_conn_t * conn = NULL;
|
||||
int64_t global_timestamp = 0;
|
||||
|
||||
static void start_listen(void *data, int fd);
|
||||
static void stop_listen(void *data, int fd);
|
||||
@@ -223,7 +222,7 @@ static int recv_msg(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
switch (type) {
|
||||
case NEU_EVENT_IO_READ: {
|
||||
ssize_t len = 0;
|
||||
uint8_t res[20000] = { 0 };
|
||||
uint8_t res[60000] = { 0 };
|
||||
int res_len = 0;
|
||||
|
||||
len = neu_conn_tcp_server_recv(conn, fd, buf->buf + buf->len,
|
||||
|
||||
+11
-10
@@ -124,8 +124,8 @@ neu_adapter_t *neu_adapter_create(neu_adapter_info_t *info)
|
||||
|
||||
rv = nng_pair1_open(&adapter->sock);
|
||||
assert(rv == 0);
|
||||
nng_socket_set_int(adapter->sock, NNG_OPT_RECVBUF, 128);
|
||||
nng_socket_set_int(adapter->sock, NNG_OPT_SENDBUF, 128);
|
||||
nng_socket_set_int(adapter->sock, NNG_OPT_RECVBUF, 8192);
|
||||
nng_socket_set_int(adapter->sock, NNG_OPT_SENDBUF, 8192);
|
||||
nng_socket_set_ms(adapter->sock, NNG_OPT_SENDTIMEO, 1000);
|
||||
nng_socket_get_int(adapter->sock, NNG_OPT_RECVFD, &adapter->recv_fd);
|
||||
|
||||
@@ -181,13 +181,13 @@ neu_adapter_t *neu_adapter_create(neu_adapter_info_t *info)
|
||||
timer_level.usr_data = (void *) adapter;
|
||||
adapter->timer_lev = neu_event_add_timer(adapter->events, timer_level);
|
||||
|
||||
nlog_info("Success to create adapter: %s", adapter->name);
|
||||
nlog_notice("Success to create adapter: %s", adapter->name);
|
||||
|
||||
adapter_storage_state(adapter->name, adapter->state);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
void neu_adapter_init(neu_adapter_t *adapter, bool auto_start)
|
||||
void neu_adapter_init(neu_adapter_t *adapter, neu_node_running_state_e state)
|
||||
{
|
||||
neu_reqresp_head_t header = { .type = NEU_REQ_NODE_INIT };
|
||||
neu_req_node_init_t init = { 0 };
|
||||
@@ -197,8 +197,8 @@ void neu_adapter_init(neu_adapter_t *adapter, bool auto_start)
|
||||
strcpy(header.receiver, "manager");
|
||||
|
||||
strcpy(init.node, adapter->name);
|
||||
init.auto_start = auto_start;
|
||||
init_msg = neu_msg_gen(&header, &init);
|
||||
init.state = state;
|
||||
init_msg = neu_msg_gen(&header, &init);
|
||||
|
||||
nng_sendmsg(adapter->sock, init_msg, 0);
|
||||
}
|
||||
@@ -371,8 +371,8 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
|
||||
nng_recvmsg(adapter->sock, &msg, 0);
|
||||
header = (neu_reqresp_head_t *) nng_msg_body(msg);
|
||||
nlog_debug("adapter(%s) recv msg from: %s, type: %s", adapter->name,
|
||||
header->sender, neu_reqresp_type_string(header->type));
|
||||
nlog_info("adapter(%s) recv msg from: %s, type: %s", adapter->name,
|
||||
header->sender, neu_reqresp_type_string(header->type));
|
||||
|
||||
switch (header->type) {
|
||||
case NEU_RESP_GET_DRIVER_GROUP:
|
||||
@@ -755,9 +755,10 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
strcpy(name, adapter->name);
|
||||
strcpy(receiver, header->receiver);
|
||||
if (nng_sendmsg(adapter->sock, uninit_msg, 0) == 0) {
|
||||
nlog_warn("%s send uninit msg to %s", name, receiver);
|
||||
nlog_notice("%s send uninit msg to %s", name, receiver);
|
||||
} else {
|
||||
nng_msg_free(uninit_msg);
|
||||
nlog_error("%s send uninit msg to %s failed", name, receiver);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -822,7 +823,7 @@ int neu_adapter_uninit(neu_adapter_t *adapter)
|
||||
|
||||
neu_event_del_timer(adapter->events, adapter->timer_lev);
|
||||
|
||||
nlog_info("Stop the adapter(%s)", adapter->name);
|
||||
nlog_notice("Stop the adapter(%s)", adapter->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ typedef struct adapter_msg_handler {
|
||||
} adapter_msg_handler_t;
|
||||
|
||||
neu_adapter_t *neu_adapter_create(neu_adapter_info_t *info);
|
||||
void neu_adapter_init(neu_adapter_t *adapter, bool auto_start);
|
||||
void neu_adapter_init(neu_adapter_t *adapter, neu_node_running_state_e state);
|
||||
|
||||
int neu_adapter_start(neu_adapter_t *adapter);
|
||||
int neu_adapter_start_single(neu_adapter_t *adapter);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <nng/nng.h>
|
||||
@@ -37,15 +38,24 @@
|
||||
#include "errcodes.h"
|
||||
#include "tag.h"
|
||||
|
||||
typedef struct to_be_write_tag {
|
||||
neu_datatag_t *tag;
|
||||
neu_value_u value;
|
||||
void * req;
|
||||
} to_be_write_tag_t;
|
||||
|
||||
typedef struct group {
|
||||
char *name;
|
||||
|
||||
int64_t timestamp;
|
||||
neu_group_t *group;
|
||||
UT_array * static_tags;
|
||||
int64_t timestamp;
|
||||
neu_group_t * group;
|
||||
UT_array * static_tags;
|
||||
UT_array * wt_tags;
|
||||
pthread_mutex_t wt_mtx;
|
||||
|
||||
neu_event_timer_t *report;
|
||||
neu_event_timer_t *read;
|
||||
neu_event_timer_t *write;
|
||||
|
||||
neu_plugin_group_t grp;
|
||||
neu_adapter_driver_t *driver;
|
||||
@@ -64,6 +74,7 @@ struct neu_adapter_driver {
|
||||
|
||||
static int report_callback(void *usr_data);
|
||||
static int read_callback(void *usr_data);
|
||||
static int write_callback(void *usr_data);
|
||||
static void read_group(int64_t timestamp, int64_t timeout,
|
||||
neu_driver_cache_t *cache, const char *group,
|
||||
UT_array *tags, neu_resp_tag_value_t *datas);
|
||||
@@ -74,6 +85,7 @@ static void update(neu_adapter_t *adapter, const char *group, const char *tag,
|
||||
neu_dvalue_t value);
|
||||
static void write_response(neu_adapter_t *adapter, void *r, neu_error error);
|
||||
static group_t *find_group(neu_adapter_driver_t *driver, const char *name);
|
||||
static void store_write_tag(group_t *group, to_be_write_tag_t *tag);
|
||||
|
||||
static void write_response(neu_adapter_t *adapter, void *r, neu_error error)
|
||||
{
|
||||
@@ -122,7 +134,7 @@ static void update(neu_adapter_t *adapter, const char *group, const char *tag,
|
||||
&driver->adapter, NEU_METRIC_TAG_READ_ERRORS_TOTAL,
|
||||
NEU_TYPE_ERROR == value.type, NULL);
|
||||
}
|
||||
nlog_debug(
|
||||
nlog_info(
|
||||
"update driver: %s, group: %s, tag: %s, type: %s, timestamp: %" PRId64,
|
||||
driver->adapter.name, group, tag, neu_type_string(value.type),
|
||||
global_timestamp);
|
||||
@@ -175,6 +187,7 @@ int neu_adapter_driver_uninit(neu_adapter_driver_t *driver)
|
||||
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, el->report);
|
||||
neu_event_del_timer(driver->driver_events, el->read);
|
||||
neu_event_del_timer(driver->driver_events, el->write);
|
||||
if (el->grp.group_free != NULL) {
|
||||
el->grp.group_free(&el->grp);
|
||||
}
|
||||
@@ -182,7 +195,13 @@ int neu_adapter_driver_uninit(neu_adapter_driver_t *driver)
|
||||
free(el->name);
|
||||
utarray_free(el->grp.tags);
|
||||
|
||||
utarray_foreach(el->wt_tags, to_be_write_tag_t *, tag)
|
||||
{
|
||||
neu_tag_free(tag->tag);
|
||||
}
|
||||
|
||||
utarray_free(el->static_tags);
|
||||
utarray_free(el->wt_tags);
|
||||
neu_group_destroy(el->group);
|
||||
free(el);
|
||||
}
|
||||
@@ -414,8 +433,12 @@ void neu_adapter_driver_write_tag(neu_adapter_driver_t *driver,
|
||||
driver->adapter.cb_funs.response(&driver->adapter, req, &error);
|
||||
free(req);
|
||||
} else {
|
||||
driver->adapter.module->intf_funs->driver.write_tag(
|
||||
driver->adapter.plugin, (void *) req, tag, cmd->value.value);
|
||||
to_be_write_tag_t wtag = { 0 };
|
||||
wtag.req = (void *) req;
|
||||
wtag.value = cmd->value.value;
|
||||
wtag.tag = neu_tag_dup(tag);
|
||||
|
||||
store_write_tag(g, &wtag);
|
||||
}
|
||||
|
||||
neu_tag_free(tag);
|
||||
@@ -429,6 +452,7 @@ void neu_adapter_driver_write_tag(neu_adapter_driver_t *driver,
|
||||
int neu_adapter_driver_add_group(neu_adapter_driver_t *driver, const char *name,
|
||||
uint32_t interval)
|
||||
{
|
||||
UT_icd icd = { sizeof(to_be_write_tag_t), NULL, NULL, NULL };
|
||||
group_t *find = NULL;
|
||||
int ret = NEU_ERR_GROUP_EXIST;
|
||||
|
||||
@@ -443,6 +467,10 @@ int neu_adapter_driver_add_group(neu_adapter_driver_t *driver, const char *name,
|
||||
.type = NEU_EVENT_TIMER_NOBLOCK,
|
||||
};
|
||||
|
||||
pthread_mutex_init(&find->wt_mtx, NULL);
|
||||
|
||||
utarray_new(find->wt_tags, &icd);
|
||||
|
||||
find->driver = driver;
|
||||
find->name = strdup(name);
|
||||
find->group = neu_group_new(name, interval);
|
||||
@@ -456,6 +484,11 @@ int neu_adapter_driver_add_group(neu_adapter_driver_t *driver, const char *name,
|
||||
param.cb = read_callback;
|
||||
find->read = neu_event_add_timer(driver->driver_events, param);
|
||||
|
||||
param.second = 0;
|
||||
param.millisecond = 100;
|
||||
param.cb = write_callback;
|
||||
find->write = neu_event_add_timer(driver->driver_events, param);
|
||||
|
||||
REGISTER_GROUP_METRIC(&driver->adapter, find->name,
|
||||
NEU_METRIC_GROUP_TAGS_TOTAL,
|
||||
neu_group_tag_size(find->group));
|
||||
@@ -514,6 +547,7 @@ int neu_adapter_driver_del_group(neu_adapter_driver_t *driver, const char *name)
|
||||
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, find->report);
|
||||
neu_event_del_timer(driver->driver_events, find->read);
|
||||
neu_event_del_timer(driver->driver_events, find->write);
|
||||
if (find->grp.group_free != NULL) {
|
||||
find->grp.group_free(&find->grp);
|
||||
}
|
||||
@@ -530,11 +564,18 @@ int neu_adapter_driver_del_group(neu_adapter_driver_t *driver, const char *name)
|
||||
neu_driver_cache_del(driver->cache, name, tag->name);
|
||||
}
|
||||
|
||||
utarray_foreach(find->wt_tags, to_be_write_tag_t *, tag)
|
||||
{
|
||||
neu_tag_free(tag->tag);
|
||||
}
|
||||
|
||||
utarray_free(find->static_tags);
|
||||
utarray_free(find->grp.tags);
|
||||
utarray_free(find->wt_tags);
|
||||
neu_group_destroy(find->group);
|
||||
free(find);
|
||||
|
||||
pthread_mutex_destroy(&find->wt_mtx);
|
||||
neu_adapter_del_group_metrics(&driver->adapter, name);
|
||||
ret = NEU_ERR_SUCCESS;
|
||||
}
|
||||
@@ -881,7 +922,30 @@ static void group_change(void *arg, int64_t timestamp, UT_array *static_tags,
|
||||
|
||||
group->static_tags = static_tags;
|
||||
group->grp = grp;
|
||||
nlog_notice("group: %s changed", group->name);
|
||||
nlog_notice("group: %s changed, timestamp: %" PRIi64, group->name,
|
||||
timestamp);
|
||||
}
|
||||
|
||||
static int write_callback(void *usr_data)
|
||||
{
|
||||
group_t * group = (group_t *) usr_data;
|
||||
neu_node_running_state_e state = group->driver->adapter.state;
|
||||
if (state != NEU_NODE_RUNNING_STATE_RUNNING) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&group->wt_mtx);
|
||||
utarray_foreach(group->wt_tags, to_be_write_tag_t *, wtag)
|
||||
{
|
||||
group->driver->adapter.module->intf_funs->driver.write_tag(
|
||||
group->driver->adapter.plugin, (void *) wtag->req, wtag->tag,
|
||||
wtag->value);
|
||||
neu_tag_free(wtag->tag);
|
||||
}
|
||||
utarray_clear(group->wt_tags);
|
||||
pthread_mutex_unlock(&group->wt_mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_callback(void *usr_data)
|
||||
@@ -927,7 +991,7 @@ static int read_report_group(int64_t timestamp, int64_t timeout,
|
||||
if (neu_tag_attribute_test(tag, NEU_ATTRIBUTE_SUBSCRIBE)) {
|
||||
if (neu_driver_cache_get_changed(cache, group, tag->name, &value) !=
|
||||
0) {
|
||||
nlog_debug("tag: %s not changed", tag->name);
|
||||
nlog_info("tag: %s not changed", tag->name);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
@@ -1003,7 +1067,8 @@ static int read_report_group(int64_t timestamp, int64_t timeout,
|
||||
break;
|
||||
}
|
||||
|
||||
if ((timestamp - value.timestamp) > timeout) {
|
||||
if (!neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC) &&
|
||||
(timestamp - value.timestamp) > timeout) {
|
||||
datas[index].value.type = NEU_TYPE_ERROR;
|
||||
datas[index].value.value.i32 = NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED;
|
||||
} else {
|
||||
@@ -1198,3 +1263,10 @@ static void read_group(int64_t timestamp, int64_t timeout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void store_write_tag(group_t *group, to_be_write_tag_t *tag)
|
||||
{
|
||||
pthread_mutex_lock(&group->wt_mtx);
|
||||
utarray_push_back(group->wt_tags, tag);
|
||||
pthread_mutex_unlock(&group->wt_mtx);
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ int adapter_load_setting(const char *node, char **setting)
|
||||
{
|
||||
int rv = neu_persister_load_node_setting(node, (const char **) setting);
|
||||
if (0 != rv) {
|
||||
nlog_info("load %s setting fail", node);
|
||||
nlog_error("load %s setting fail", node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -286,7 +286,8 @@ static void split_static_array(tag_elem_t *tags, UT_array **static_tags,
|
||||
{
|
||||
if (neu_tag_attribute_test(el->tag, NEU_ATTRIBUTE_STATIC)) {
|
||||
utarray_push_back(*static_tags, el->tag);
|
||||
} else {
|
||||
} else if (neu_tag_attribute_test(el->tag, NEU_ATTRIBUTE_SUBSCRIBE) ||
|
||||
neu_tag_attribute_test(el->tag, NEU_ATTRIBUTE_READ)) {
|
||||
utarray_push_back(*other_tags, el->tag);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -189,7 +189,7 @@ static inline void metrics_unregister_entry(const char *name)
|
||||
HASH_FIND_STR(g_metrics_.registered_metrics, name, e);
|
||||
if (0 == --e->value) {
|
||||
HASH_DEL(g_metrics_.registered_metrics, e);
|
||||
nlog_info("del entry:%s", e->name);
|
||||
nlog_notice("del entry:%s", e->name);
|
||||
neu_metric_entry_free(e);
|
||||
}
|
||||
}
|
||||
|
||||
+99
-47
@@ -33,6 +33,10 @@
|
||||
|
||||
#include "connection/neu_connection.h"
|
||||
|
||||
#ifndef CMSPAR
|
||||
#define CMSPAR 010000000000 /* mark or space (stick) parity */
|
||||
#endif
|
||||
|
||||
struct tcp_client {
|
||||
int fd;
|
||||
struct sockaddr_in client;
|
||||
@@ -43,6 +47,7 @@ struct neu_conn {
|
||||
void * data;
|
||||
bool is_connected;
|
||||
bool stop;
|
||||
bool connection_ok;
|
||||
|
||||
neu_conn_callback connected;
|
||||
neu_conn_callback disconnected;
|
||||
@@ -213,10 +218,10 @@ int neu_conn_tcp_server_accept(neu_conn_t *conn)
|
||||
conn->connected(conn->data, fd);
|
||||
conn->callback_trigger = true;
|
||||
|
||||
zlog_info(conn->param.log, "%s:%d accpet new client: %s:%d, fd: %d",
|
||||
conn->param.params.tcp_server.ip,
|
||||
conn->param.params.tcp_server.port, inet_ntoa(client.sin_addr),
|
||||
ntohs(client.sin_port), fd);
|
||||
zlog_notice(conn->param.log, "%s:%d accpet new client: %s:%d, fd: %d",
|
||||
conn->param.params.tcp_server.ip,
|
||||
conn->param.params.tcp_server.port, inet_ntoa(client.sin_addr),
|
||||
ntohs(client.sin_port), fd);
|
||||
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
|
||||
@@ -233,6 +238,8 @@ int neu_conn_tcp_server_close_client(neu_conn_t *conn, int fd)
|
||||
|
||||
conn->disconnected(conn->data, fd);
|
||||
conn_tcp_server_del_client(conn, fd);
|
||||
conn->offset = 0;
|
||||
memset(conn->buf, 0, conn->buf_size);
|
||||
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
return 0;
|
||||
@@ -334,8 +341,14 @@ ssize_t neu_conn_send(neu_conn_t *conn, uint8_t *buf, ssize_t len)
|
||||
conn->fd, len, ret, strerror(errno), errno);
|
||||
}
|
||||
|
||||
if (ret == -1 && errno != EAGAIN) {
|
||||
conn_disconnect(conn);
|
||||
if (ret == -1) {
|
||||
if (errno != EAGAIN) {
|
||||
conn_disconnect(conn);
|
||||
} else {
|
||||
if (conn->connection_ok == true) {
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0 && conn->callback_trigger == false) {
|
||||
@@ -346,6 +359,7 @@ ssize_t neu_conn_send(neu_conn_t *conn, uint8_t *buf, ssize_t len)
|
||||
|
||||
if (ret > 0) {
|
||||
conn->state.send_bytes += ret;
|
||||
conn->connection_ok = true;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
@@ -391,19 +405,23 @@ ssize_t neu_conn_recv(neu_conn_t *conn, uint8_t *buf, ssize_t len)
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ret <= 0) {
|
||||
zlog_error(conn->param.log,
|
||||
"conn fd: %d, recv buf len %zd, ret: %zd, errno: %s(%d)",
|
||||
conn->fd, len, ret, strerror(errno), errno);
|
||||
}
|
||||
|
||||
if (errno == EPIPE || ret == -1 || ret == 0) {
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
|
||||
if (ret > 0 && conn->callback_trigger == false) {
|
||||
conn->connected(conn->data, conn->fd);
|
||||
conn->callback_trigger = true;
|
||||
if (conn->param.type == NEU_CONN_TTY_CLIENT) {
|
||||
if (ret == -1) {
|
||||
zlog_error(
|
||||
conn->param.log,
|
||||
"tty conn fd: %d, recv buf len %zd, ret: %zd, errno: %s(%d)",
|
||||
conn->fd, len, ret, strerror(errno), errno);
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
} else {
|
||||
if (ret <= 0) {
|
||||
zlog_error(conn->param.log,
|
||||
"conn fd: %d, recv buf len %zd, ret: %zd, errno: %s(%d)",
|
||||
conn->fd, len, ret, strerror(errno), errno);
|
||||
if (ret == 0 || (ret == -1 && errno != EAGAIN)) {
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
@@ -483,6 +501,10 @@ static void conn_init_param(neu_conn_t *conn, neu_conn_param_t *param)
|
||||
} else {
|
||||
conn->block = false;
|
||||
}
|
||||
zlog_notice(conn->param.log, "tcp server %s:%d, timeout: %d, block: %d",
|
||||
conn->param.params.tcp_server.ip,
|
||||
conn->param.params.tcp_server.port,
|
||||
conn->param.params.tcp_server.timeout, conn->block);
|
||||
break;
|
||||
case NEU_CONN_TCP_CLIENT:
|
||||
conn->param.params.tcp_client.ip = strdup(param->params.tcp_client.ip);
|
||||
@@ -490,6 +512,10 @@ static void conn_init_param(neu_conn_t *conn, neu_conn_param_t *param)
|
||||
conn->param.params.tcp_client.timeout =
|
||||
param->params.tcp_client.timeout;
|
||||
conn->block = conn->param.params.tcp_client.timeout > 0;
|
||||
zlog_notice(conn->param.log, "tcp client %s:%d, timeout: %d, block: %d",
|
||||
conn->param.params.tcp_client.ip,
|
||||
conn->param.params.tcp_client.port,
|
||||
conn->param.params.tcp_client.timeout, conn->block);
|
||||
break;
|
||||
case NEU_CONN_UDP:
|
||||
conn->param.params.udp.src_ip = strdup(param->params.udp.src_ip);
|
||||
@@ -498,6 +524,11 @@ static void conn_init_param(neu_conn_t *conn, neu_conn_param_t *param)
|
||||
conn->param.params.udp.dst_port = param->params.udp.dst_port;
|
||||
conn->param.params.udp.timeout = param->params.udp.timeout;
|
||||
conn->block = conn->param.params.udp.timeout > 0;
|
||||
zlog_notice(
|
||||
conn->param.log, "udp %s:%d -> %s:%d, timeout: %d, block: %d",
|
||||
conn->param.params.udp.src_ip, conn->param.params.udp.src_port,
|
||||
conn->param.params.udp.dst_ip, conn->param.params.udp.dst_port,
|
||||
conn->param.params.udp.timeout, conn->block);
|
||||
break;
|
||||
case NEU_CONN_TTY_CLIENT:
|
||||
conn->param.params.tty_client.device =
|
||||
@@ -548,9 +579,9 @@ static void conn_tcp_server_listen(neu_conn_t *conn)
|
||||
conn->tcp_server.is_listen = true;
|
||||
|
||||
conn->param.params.tcp_server.start_listen(conn->data, fd);
|
||||
zlog_info(conn->param.log, "tcp server listen %s:%d success, fd: %d",
|
||||
conn->param.params.tcp_server.ip,
|
||||
conn->param.params.tcp_server.port, fd);
|
||||
zlog_notice(conn->param.log, "tcp server listen %s:%d success, fd: %d",
|
||||
conn->param.params.tcp_server.ip,
|
||||
conn->param.params.tcp_server.port, fd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,9 +589,9 @@ static void conn_tcp_server_stop(neu_conn_t *conn)
|
||||
{
|
||||
if (conn->param.type == NEU_CONN_TCP_SERVER &&
|
||||
conn->tcp_server.is_listen == true) {
|
||||
zlog_info(conn->param.log, "tcp server close %s:%d, fd: %d",
|
||||
conn->param.params.tcp_server.ip,
|
||||
conn->param.params.tcp_server.port, conn->fd);
|
||||
zlog_notice(conn->param.log, "tcp server close %s:%d, fd: %d",
|
||||
conn->param.params.tcp_server.ip,
|
||||
conn->param.params.tcp_server.port, conn->fd);
|
||||
|
||||
conn->param.params.tcp_server.stop_listen(conn->data, conn->fd);
|
||||
|
||||
@@ -620,9 +651,9 @@ static void conn_connect(neu_conn_t *conn)
|
||||
conn->is_connected = false;
|
||||
return;
|
||||
} else {
|
||||
zlog_info(conn->param.log, "connect %s:%d success",
|
||||
conn->param.params.tcp_client.ip,
|
||||
conn->param.params.tcp_client.port);
|
||||
zlog_notice(conn->param.log, "connect %s:%d, block: %d success",
|
||||
conn->param.params.tcp_client.ip,
|
||||
conn->param.params.tcp_client.port, conn->block);
|
||||
conn->is_connected = true;
|
||||
conn->fd = fd;
|
||||
}
|
||||
@@ -675,9 +706,9 @@ static void conn_connect(neu_conn_t *conn)
|
||||
conn->is_connected = false;
|
||||
return;
|
||||
} else {
|
||||
zlog_info(conn->param.log, "connect %s:%d success",
|
||||
conn->param.params.udp.dst_ip,
|
||||
conn->param.params.udp.dst_port);
|
||||
zlog_notice(conn->param.log, "connect %s:%d success",
|
||||
conn->param.params.udp.dst_ip,
|
||||
conn->param.params.udp.dst_port);
|
||||
conn->is_connected = true;
|
||||
conn->fd = fd;
|
||||
}
|
||||
@@ -842,6 +873,15 @@ static void conn_connect(neu_conn_t *conn)
|
||||
|
||||
static void conn_disconnect(neu_conn_t *conn)
|
||||
{
|
||||
conn->is_connected = false;
|
||||
conn->connection_ok = false;
|
||||
if (conn->callback_trigger == true) {
|
||||
conn->disconnected(conn->data, conn->fd);
|
||||
conn->callback_trigger = false;
|
||||
}
|
||||
conn->offset = 0;
|
||||
memset(conn->buf, 0, conn->buf_size);
|
||||
|
||||
switch (conn->param.type) {
|
||||
case NEU_CONN_TCP_SERVER:
|
||||
for (int i = 0; i < conn->param.params.tcp_server.max_link; i++) {
|
||||
@@ -861,14 +901,6 @@ static void conn_disconnect(neu_conn_t *conn)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
conn->is_connected = false;
|
||||
if (conn->callback_trigger == true) {
|
||||
conn->disconnected(conn->data, conn->fd);
|
||||
conn->callback_trigger = false;
|
||||
}
|
||||
conn->offset = 0;
|
||||
memset(conn->buf, 0, conn->buf_size);
|
||||
}
|
||||
|
||||
static void conn_tcp_server_add_client(neu_conn_t *conn, int fd,
|
||||
@@ -936,8 +968,7 @@ int neu_conn_stream_consume(neu_conn_t *conn, void *context,
|
||||
if (used == 0) {
|
||||
break;
|
||||
} else if (used == -1) {
|
||||
memset(conn->buf, 0, conn->buf_size);
|
||||
conn->offset = 0;
|
||||
neu_conn_disconnect(conn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -968,8 +999,7 @@ int neu_conn_stream_tcp_server_consume(neu_conn_t *conn, int fd, void *context,
|
||||
if (used == 0) {
|
||||
break;
|
||||
} else if (used == -1) {
|
||||
memset(conn->buf, 0, conn->buf_size);
|
||||
conn->offset = 0;
|
||||
neu_conn_tcp_server_close_client(conn, fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -997,9 +1027,20 @@ int neu_conn_wait_msg(neu_conn_t *conn, void *context, uint16_t n_byte,
|
||||
neu_protocol_unpack_buf_init(&pbuf, conn->buf, conn->offset);
|
||||
neu_buf_result_t result = fn(context, &pbuf);
|
||||
if (result.need > 0) {
|
||||
assert(result.need <= conn->buf_size - conn->offset);
|
||||
ret = neu_conn_recv(conn, conn->buf + conn->offset, result.need);
|
||||
if (result.need <= conn->buf_size - conn->offset) {
|
||||
ret =
|
||||
neu_conn_recv(conn, conn->buf + conn->offset, result.need);
|
||||
} else {
|
||||
zlog_error(conn->param.log,
|
||||
"no enough recv buf, need: %" PRIu16
|
||||
" , buf size: %" PRIu16 " offset: %" PRIu16,
|
||||
result.need, conn->buf_size, conn->offset);
|
||||
return -1;
|
||||
}
|
||||
} else if (result.need == 0) {
|
||||
return result.used;
|
||||
} else {
|
||||
neu_conn_disconnect(conn);
|
||||
return result.used;
|
||||
}
|
||||
}
|
||||
@@ -1021,9 +1062,20 @@ int neu_conn_tcp_server_wait_msg(neu_conn_t *conn, int fd, void *context,
|
||||
neu_buf_result_t result = fn(context, &pbuf);
|
||||
if (result.need > 0) {
|
||||
assert(result.need <= conn->buf_size - conn->offset);
|
||||
ret = neu_conn_tcp_server_recv(conn, fd, conn->buf + conn->offset,
|
||||
result.need);
|
||||
if (result.need <= conn->buf_size - conn->offset) {
|
||||
ret = neu_conn_tcp_server_recv(
|
||||
conn, fd, conn->buf + conn->offset, result.need);
|
||||
} else {
|
||||
zlog_error(conn->param.log,
|
||||
"no enough recv buf, need: %" PRIu16
|
||||
" , buf size: %" PRIu16 " offset: %" PRIu16,
|
||||
result.need, conn->buf_size, conn->offset);
|
||||
return -1;
|
||||
}
|
||||
} else if (result.need == 0) {
|
||||
return result.used;
|
||||
} else {
|
||||
neu_conn_tcp_server_close_client(conn, fd);
|
||||
return result.used;
|
||||
}
|
||||
}
|
||||
|
||||
+133
-11
@@ -33,6 +33,7 @@
|
||||
#include "connection/mqtt_client.h"
|
||||
#include "event/event.h"
|
||||
#include "utils/asprintf.h"
|
||||
#include "utils/time.h"
|
||||
#include "utils/utextend.h"
|
||||
#include "utils/uthash.h"
|
||||
#include "utils/utlist.h"
|
||||
@@ -68,6 +69,7 @@ typedef struct {
|
||||
typedef enum {
|
||||
TASK_PUB,
|
||||
TASK_SUB,
|
||||
TASK_UNSUB,
|
||||
TASK_RECV,
|
||||
} task_kind_e;
|
||||
|
||||
@@ -133,7 +135,8 @@ static inline void tasks_free(task_t *tasks);
|
||||
static void task_cb(void *arg);
|
||||
static void task_handle_pub(task_t *task, neu_mqtt_client_t *client);
|
||||
static void task_handle_sub(task_t *task, neu_mqtt_client_t *client);
|
||||
static void task_handle_recv(task_t *task, neu_mqtt_client_t *client);
|
||||
static void task_handle_unsub(task_t *task, neu_mqtt_client_t *client);
|
||||
static void task_handle_recv(task_t *task, neu_mqtt_client_t *client);
|
||||
|
||||
static subscription_t * subscription_new(neu_mqtt_client_t *client,
|
||||
neu_mqtt_qos_e qos, const char *topic,
|
||||
@@ -221,6 +224,8 @@ static void task_cb(void *arg)
|
||||
task_handle_pub(task, client);
|
||||
} else if (TASK_SUB == task->kind) {
|
||||
task_handle_sub(task, client);
|
||||
} else if (TASK_UNSUB == task->kind) {
|
||||
task_handle_unsub(task, client);
|
||||
} else if (TASK_RECV == task->kind) {
|
||||
task_handle_recv(task, client);
|
||||
} else {
|
||||
@@ -282,19 +287,54 @@ static void task_handle_sub(task_t *task, neu_mqtt_client_t *client)
|
||||
}
|
||||
|
||||
rc = nng_mqtt_msg_get_suback_return_codes(msg, &n);
|
||||
log(info, "recv SUBACK return_code:%d", *rc);
|
||||
log(debug, "recv SUBACK return_code:%d", *rc);
|
||||
rv = 0x80 == *rc ? -1 : 0;
|
||||
task->sub->ack = true;
|
||||
client->suback_count += 1;
|
||||
|
||||
end:
|
||||
// TODO: handle retry subscribe on failure
|
||||
log(info, "sub [%s, QoS%d], %s", task->sub->topic, task->sub->qos,
|
||||
log(notice, "sub [%s, QoS%d], %s", task->sub->topic, task->sub->qos,
|
||||
(0 == rv) ? "OK" : "FAIL");
|
||||
nng_msg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
static void task_handle_unsub(task_t *task, neu_mqtt_client_t *client)
|
||||
{
|
||||
int rv = 0;
|
||||
nng_msg *msg = NULL;
|
||||
nng_aio *aio = task->aio;
|
||||
|
||||
if (0 != (rv = nng_aio_result(aio))) {
|
||||
log(error, "send UNSUBSCRIBE error: %s", nng_strerror(rv));
|
||||
goto end;
|
||||
}
|
||||
|
||||
msg = nng_aio_get_msg(aio);
|
||||
if (NULL == msg) {
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
nng_mqtt_packet_type pt = nng_mqtt_msg_get_packet_type(msg);
|
||||
if (NNG_MQTT_UNSUBACK != pt) {
|
||||
log(error, "recv packet type:%d, expect UNSUBACK packet", pt);
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
if (task->sub) {
|
||||
log(notice, "unsub [%s, QoS%d], %s", task->sub->topic, task->sub->qos,
|
||||
(0 == rv) ? "OK" : "FAIL");
|
||||
} else {
|
||||
log(notice, "unsub %s", (0 == rv) ? "OK" : "FAIL");
|
||||
}
|
||||
nng_msg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
static void task_handle_recv(task_t *task, neu_mqtt_client_t *client)
|
||||
{
|
||||
(void) client;
|
||||
@@ -391,7 +431,7 @@ static void connect_cb(nng_pipe p, nng_pipe_ev ev, void *arg)
|
||||
neu_mqtt_client_connection_cb_t cb = NULL;
|
||||
void * data = NULL;
|
||||
|
||||
log(info, "mqtt client connected");
|
||||
log(notice, "mqtt client connected");
|
||||
|
||||
nng_mtx_lock(client->mtx);
|
||||
// start receiving
|
||||
@@ -417,7 +457,7 @@ static void disconnect_cb(nng_pipe p, nng_pipe_ev ev, void *arg)
|
||||
neu_mqtt_client_connection_cb_t cb = NULL;
|
||||
void * data = NULL;
|
||||
|
||||
log(info, "mqtt client disconnected");
|
||||
log(notice, "mqtt client disconnected");
|
||||
nng_mtx_lock(client->mtx);
|
||||
client->connected = false;
|
||||
cb = client->disconnect_cb;
|
||||
@@ -471,7 +511,7 @@ static void recv_cb(void *arg)
|
||||
uint8_t qos = nng_mqtt_msg_get_publish_qos(msg);
|
||||
|
||||
(void) payload;
|
||||
log(info, "recv [%.*s, QoS%d] %" PRIu32 " bytes", (unsigned) topic_len,
|
||||
log(debug, "recv [%.*s, QoS%d] %" PRIu32 " bytes", (unsigned) topic_len,
|
||||
topic, (int) qos, payload_len);
|
||||
|
||||
// find matching subscription
|
||||
@@ -525,7 +565,7 @@ static inline task_t *client_alloc_task(neu_mqtt_client_t *client)
|
||||
// the task queue length should be a small number due to reuse
|
||||
// log info every time the task queue length increments by 32
|
||||
if (0 == (client->task_count & (32 - 1))) {
|
||||
log(info, "task queue length: %zu", client->task_count);
|
||||
log(debug, "task queue length: %zu", client->task_count);
|
||||
}
|
||||
|
||||
return task;
|
||||
@@ -535,7 +575,7 @@ static inline void client_free_task(neu_mqtt_client_t *client, task_t *task)
|
||||
{
|
||||
nng_aio_set_msg(task->aio, NULL);
|
||||
|
||||
if (TASK_SUB == task->kind) {
|
||||
if (TASK_SUB == task->kind || TASK_UNSUB == task->kind) {
|
||||
subscription_free(task->sub);
|
||||
} else if (TASK_RECV == task->kind) {
|
||||
subscription_free(task->recv.sub);
|
||||
@@ -569,6 +609,16 @@ static inline void client_add_subscription(neu_mqtt_client_t *client,
|
||||
HASH_ADD_STR(client->subscriptions, topic, sub);
|
||||
}
|
||||
|
||||
static inline void client_del_subscription(neu_mqtt_client_t *client,
|
||||
subscription_t * sub)
|
||||
{
|
||||
HASH_DEL(client->subscriptions, sub);
|
||||
if (sub->ack) {
|
||||
client->suback_count -= 1;
|
||||
}
|
||||
subscription_free(sub);
|
||||
}
|
||||
|
||||
static int client_send_sub_msg(neu_mqtt_client_t *client,
|
||||
subscription_t * subscription)
|
||||
{
|
||||
@@ -606,6 +656,38 @@ static int client_send_sub_msg(neu_mqtt_client_t *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_send_unsub_msg(neu_mqtt_client_t *client,
|
||||
subscription_t * subscription)
|
||||
{
|
||||
int rv = 0;
|
||||
nng_msg *sub_msg = NULL;
|
||||
|
||||
if ((rv = nng_mqtt_msg_alloc(&sub_msg, 0)) != 0) {
|
||||
log(error, "nng_mqtt_msg_alloc fail: %s", nng_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
nng_mqtt_topic mqtt_topic = { .buf = (uint8_t *) subscription->topic,
|
||||
.length = strlen(subscription->topic) };
|
||||
|
||||
nng_mqtt_msg_set_packet_type(sub_msg, NNG_MQTT_UNSUBSCRIBE);
|
||||
nng_mqtt_msg_set_unsubscribe_topics(sub_msg, &mqtt_topic, 1);
|
||||
|
||||
task_t *task = client_alloc_task(client);
|
||||
if (NULL == task) {
|
||||
log(error, "client_alloc_task fail");
|
||||
nng_msg_free(sub_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
task->kind = TASK_UNSUB;
|
||||
task->sub = subscription ? subscription_ref(subscription) : NULL;
|
||||
nng_aio_set_msg(task->aio, sub_msg);
|
||||
nng_send_aio(client->sock, task->aio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void client_start_recv(neu_mqtt_client_t *client)
|
||||
{
|
||||
if (client->recv_aio && !client->receiving) {
|
||||
@@ -935,7 +1017,7 @@ int neu_mqtt_client_set_tls(neu_mqtt_client_t *client, const char *ca,
|
||||
|
||||
if (NULL == ca) {
|
||||
// disable tls
|
||||
log(info, "tls disabled");
|
||||
log(debug, "tls disabled");
|
||||
if (client->tls_cfg) {
|
||||
nng_tls_config_free(client->tls_cfg);
|
||||
client->tls_cfg = NULL;
|
||||
@@ -995,7 +1077,7 @@ int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
|
||||
|
||||
if (0 == mem_size_bytes && 0 == db_size_bytes) {
|
||||
// disable cache
|
||||
log(info, "cache disabled");
|
||||
log(debug, "cache disabled");
|
||||
if (client->sqlite_cfg) {
|
||||
nng_mqtt_free_sqlite_opt(client->sqlite_cfg);
|
||||
client->sqlite_cfg = NULL;
|
||||
@@ -1163,7 +1245,7 @@ int neu_mqtt_client_close(neu_mqtt_client_t *client)
|
||||
// wait for all tasks
|
||||
while (client_task_free_list_len(client) != client->task_count) {
|
||||
nng_mtx_unlock(client->mtx);
|
||||
nng_msleep(100);
|
||||
neu_msleep(100);
|
||||
nng_mtx_lock(client->mtx);
|
||||
}
|
||||
client->open = false;
|
||||
@@ -1261,3 +1343,43 @@ error:
|
||||
subscription_free(subscription);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int neu_mqtt_client_unsubscribe(neu_mqtt_client_t *client, const char *topic)
|
||||
{
|
||||
int rv = 0;
|
||||
subscription_t *subscription = NULL;
|
||||
|
||||
nng_mtx_lock(client->mtx);
|
||||
if (NULL == client->recv_aio) {
|
||||
if ((rv = nng_aio_alloc(&client->recv_aio, recv_cb, client)) != 0) {
|
||||
log(error, "nng_aio_alloc fail: %s", nng_strerror(rv));
|
||||
goto error;
|
||||
}
|
||||
if (client->connected) {
|
||||
// connect_cb already fired, then start receiving
|
||||
client_start_recv(client);
|
||||
}
|
||||
}
|
||||
|
||||
HASH_FIND_STR(client->subscriptions, topic, subscription);
|
||||
|
||||
if (client->connected) {
|
||||
// send a unsubscribe message even subscription is NULL
|
||||
if (client_send_unsub_msg(client, subscription) < 0) {
|
||||
log(error, "client_send_unsub_msg fail");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (subscription) {
|
||||
client_del_subscription(client, subscription);
|
||||
}
|
||||
|
||||
nng_mtx_unlock(client->mtx);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
nng_mtx_unlock(client->mtx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
+19
-9
@@ -97,8 +97,9 @@ neu_manager_t *neu_manager_create()
|
||||
rv = nng_listen(manager->socket, url, NULL, 0);
|
||||
assert(rv == 0);
|
||||
|
||||
nng_socket_set_int(manager->socket, NNG_OPT_RECVBUF, 2048);
|
||||
nng_socket_set_int(manager->socket, NNG_OPT_SENDBUF, 2048);
|
||||
nng_socket_set_int(manager->socket, NNG_OPT_RECVBUF, 8192);
|
||||
nng_socket_set_int(manager->socket, NNG_OPT_SENDBUF, 8292);
|
||||
nng_socket_set_ms(manager->socket, NNG_OPT_SENDTIMEO, 1000);
|
||||
nng_socket_get_int(manager->socket, NNG_OPT_RECVFD, ¶m.fd);
|
||||
manager->loop = neu_event_add_io(manager->events, param);
|
||||
|
||||
@@ -135,6 +136,7 @@ neu_manager_t *neu_manager_create()
|
||||
manager->timer_timestamp =
|
||||
neu_event_add_timer(manager->events, timestamp_timer_param);
|
||||
|
||||
nlog_notice("manager start");
|
||||
return manager;
|
||||
}
|
||||
|
||||
@@ -177,7 +179,7 @@ void neu_manager_destroy(neu_manager_t *manager)
|
||||
neu_event_close(manager->events);
|
||||
|
||||
free(manager);
|
||||
nlog_warn("manager exit");
|
||||
nlog_notice("manager exit");
|
||||
}
|
||||
|
||||
const char *neu_manager_get_url()
|
||||
@@ -228,8 +230,8 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
|
||||
header = (neu_reqresp_head_t *) nng_msg_body(msg);
|
||||
|
||||
nlog_debug("manager recv msg from: %s to %s, type: %s", header->sender,
|
||||
header->receiver, neu_reqresp_type_string(header->type));
|
||||
nlog_info("manager recv msg from: %s to %s, type: %s", header->sender,
|
||||
header->receiver, neu_reqresp_type_string(header->type));
|
||||
switch (header->type) {
|
||||
case NEU_REQRESP_TRANS_DATA: {
|
||||
neu_reqresp_trans_data_t *cmd = (neu_reqresp_trans_data_t *) &header[1];
|
||||
@@ -253,7 +255,7 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
utarray_foreach(pipes, nng_pipe *, pipe)
|
||||
{
|
||||
forward_msg_dup(manager, msg, *pipe);
|
||||
nlog_info("forward license update to pipe: %d", pipe->id);
|
||||
nlog_notice("forward license update to pipe: %d", pipe->id);
|
||||
}
|
||||
utarray_free(pipes);
|
||||
|
||||
@@ -265,10 +267,14 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
|
||||
neu_node_manager_update(manager->node_manager, init->node, pipe);
|
||||
|
||||
if (init->auto_start) {
|
||||
if (init->state == NEU_NODE_RUNNING_STATE_STOPPED ||
|
||||
init->state == NEU_NODE_RUNNING_STATE_RUNNING) {
|
||||
neu_adapter_t *adapter =
|
||||
neu_node_manager_find(manager->node_manager, init->node);
|
||||
neu_adapter_start(adapter);
|
||||
if (init->state == NEU_NODE_RUNNING_STATE_STOPPED) {
|
||||
neu_adapter_stop(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
nlog_notice("bind node %s to pipe(%d)", init->node, pipe.id);
|
||||
@@ -482,6 +488,8 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
forward_msg(manager, msg, cmd->app);
|
||||
manager_storage_subscribe(manager, cmd->app, cmd->driver,
|
||||
cmd->group, cmd->params);
|
||||
} else {
|
||||
free(cmd->params);
|
||||
}
|
||||
|
||||
header->type = NEU_RESP_ERROR;
|
||||
@@ -727,8 +735,9 @@ inline static void forward_msg_dup(neu_manager_t *manager, nng_msg *msg,
|
||||
nng_msg_dup(&out_msg, msg);
|
||||
nng_msg_set_pipe(out_msg, pipe);
|
||||
if (nng_sendmsg(manager->socket, out_msg, 0) == 0) {
|
||||
nlog_debug("forward msg to pipe %d", pipe.id);
|
||||
nlog_info("forward msg to pipe %d", pipe.id);
|
||||
} else {
|
||||
nlog_warn("forward msg to pipe %d fail", pipe.id);
|
||||
nng_msg_free(out_msg);
|
||||
}
|
||||
}
|
||||
@@ -742,8 +751,9 @@ inline static void forward_msg(neu_manager_t *manager, nng_msg *msg,
|
||||
nng_msg_dup(&out_msg, msg);
|
||||
nng_msg_set_pipe(out_msg, pipe);
|
||||
if (nng_sendmsg(manager->socket, out_msg, 0) == 0) {
|
||||
nlog_debug("forward msg to %s", node);
|
||||
nlog_info("forward msg to %s", node);
|
||||
} else {
|
||||
nlog_warn("forward msg to pipe (%s)%d fail", node, pipe.id);
|
||||
nng_msg_free(out_msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ UT_array *neu_manager_get_plugins(neu_manager_t *manager)
|
||||
}
|
||||
|
||||
int neu_manager_add_node(neu_manager_t *manager, const char *node_name,
|
||||
const char *plugin_name, bool start)
|
||||
const char * plugin_name,
|
||||
neu_node_running_state_e state)
|
||||
{
|
||||
neu_adapter_t * adapter = NULL;
|
||||
neu_plugin_instance_t instance = { 0 };
|
||||
@@ -77,7 +78,7 @@ int neu_manager_add_node(neu_manager_t *manager, const char *node_name,
|
||||
|
||||
adapter = neu_adapter_create(&adapter_info);
|
||||
neu_node_manager_add(manager->node_manager, adapter);
|
||||
neu_adapter_init(adapter, start);
|
||||
neu_adapter_init(adapter, state);
|
||||
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
@@ -324,8 +325,10 @@ int neu_manager_send_subscribe(neu_manager_t *manager, const char *app,
|
||||
nng_msg_set_pipe(out_msg, pipe);
|
||||
|
||||
if (nng_sendmsg(manager->socket, out_msg, 0) == 0) {
|
||||
nlog_info("send %s to %s", neu_reqresp_type_string(header.type), app);
|
||||
nlog_notice("send %s to %s", neu_reqresp_type_string(header.type), app);
|
||||
} else {
|
||||
nlog_warn("send %s to %s failed", neu_reqresp_type_string(header.type),
|
||||
app);
|
||||
free(cmd.params);
|
||||
nng_msg_free(out_msg);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,8 @@ int neu_manager_del_plugin(neu_manager_t *manager, const char *plugin);
|
||||
UT_array *neu_manager_get_plugins(neu_manager_t *manager);
|
||||
|
||||
int neu_manager_add_node(neu_manager_t *manager, const char *node_name,
|
||||
const char *plugin_name, bool start);
|
||||
const char * plugin_name,
|
||||
neu_node_running_state_e state);
|
||||
int neu_manager_del_node(neu_manager_t *manager, const char *node_name);
|
||||
UT_array *neu_manager_get_nodes(neu_manager_t *manager, neu_node_type_e type,
|
||||
const char *plugin, const char *node);
|
||||
|
||||
@@ -50,11 +50,6 @@ typedef struct plugin_entity {
|
||||
UT_hash_handle hh;
|
||||
} plugin_entity_t;
|
||||
|
||||
typedef struct {
|
||||
char *name_old;
|
||||
char *name_new;
|
||||
} plugin_name_t;
|
||||
|
||||
struct neu_plugin_manager {
|
||||
plugin_entity_t *plugins;
|
||||
};
|
||||
@@ -239,41 +234,6 @@ int neu_plugin_manager_find(neu_plugin_manager_t *mgr, const char *plugin_name,
|
||||
plugin_entity_t *plugin = NULL;
|
||||
int ret = -1;
|
||||
|
||||
static const plugin_name_t name[] = {
|
||||
{ "mqtt", "MQTT" },
|
||||
{ "ekuiper", "eKuiper" },
|
||||
{ "modbus-tcp", "Modbus TCP community" },
|
||||
{ "a1e", "Mitsubishi 1E" },
|
||||
{ "ads", "Beckhoff ADS" },
|
||||
{ "bacnet", "BACnet/IP" },
|
||||
{ "dlt645", "DLT645-2007" },
|
||||
{ "EtherNet-IP", "EtherNet/IP(CIP)" },
|
||||
{ "fins", "Omron FINS TCP" },
|
||||
{ "focas", "Fanuc Focas Ethernet" },
|
||||
{ "iec104", "IEC60870-5-104" },
|
||||
{ "knx", "KNXnet/IP" },
|
||||
{ "modbus-qh-tcp", "Modbus TCP QH" },
|
||||
{ "modbus-rtu", "Modbus RTU" },
|
||||
{ "modbus-plus-tcp", "Modbus TCP" },
|
||||
{ "nona11", "NON A11" },
|
||||
{ "opcua", "OPC UA" },
|
||||
{ "qna3e", "Mitsubishi 3E" },
|
||||
{ "s7comm", "Siemens S7 ISOTCP" },
|
||||
{ "s7comm_for_300", "Siemens S7 ISOTCP for 300/400" },
|
||||
{ "sparkplugb", "SparkPlugB" },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
int i = 0;
|
||||
while (name[i].name_old != NULL) {
|
||||
if (strcmp(plugin_name, name[i].name_old) == 0) {
|
||||
plugin_name = name[i].name_new;
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
HASH_FIND_STR(mgr->plugins, plugin_name, plugin);
|
||||
if (plugin != NULL) {
|
||||
ret = 0;
|
||||
|
||||
+9
-10
@@ -96,7 +96,7 @@ int manager_load_plugin(neu_manager_t *manager)
|
||||
{
|
||||
rv = neu_manager_add_plugin(manager, *name);
|
||||
const char *ok_or_err = (0 == rv) ? "success" : "fail";
|
||||
nlog_info("load plugin %s, lib:%s", ok_or_err, *name);
|
||||
nlog_notice("load plugin %s, lib:%s", ok_or_err, *name);
|
||||
}
|
||||
|
||||
utarray_foreach(plugin_infos, char **, name) { free(*name); }
|
||||
@@ -118,13 +118,12 @@ int manager_load_node(neu_manager_t *manager)
|
||||
|
||||
utarray_foreach(node_infos, neu_persist_node_info_t *, node_info)
|
||||
{
|
||||
rv = neu_manager_add_node(
|
||||
manager, node_info->name, node_info->plugin_name,
|
||||
node_info->state == NEU_NODE_RUNNING_STATE_RUNNING);
|
||||
rv = neu_manager_add_node(manager, node_info->name,
|
||||
node_info->plugin_name, node_info->state);
|
||||
const char *ok_or_err = (0 == rv) ? "success" : "fail";
|
||||
nlog_info("load adapter %s type:%d, name:%s plugin:%s state:%d",
|
||||
ok_or_err, node_info->type, node_info->name,
|
||||
node_info->plugin_name, node_info->state);
|
||||
nlog_notice("load adapter %s type:%d, name:%s plugin:%s state:%d",
|
||||
ok_or_err, node_info->type, node_info->name,
|
||||
node_info->plugin_name, node_info->state);
|
||||
}
|
||||
|
||||
utarray_free(node_infos);
|
||||
@@ -151,9 +150,9 @@ int manager_load_subscribe(neu_manager_t *manager)
|
||||
info->driver_name, info->group_name,
|
||||
info->params);
|
||||
const char *ok_or_err = (0 == rv) ? "success" : "fail";
|
||||
nlog_info("%s load subscription app:%s driver:%s grp:%s",
|
||||
ok_or_err, node->node, info->driver_name,
|
||||
info->group_name);
|
||||
nlog_notice("%s load subscription app:%s driver:%s grp:%s",
|
||||
ok_or_err, node->node, info->driver_name,
|
||||
info->group_name);
|
||||
if (0 == rv) {
|
||||
neu_manager_send_subscribe(manager, node->node,
|
||||
info->driver_name,
|
||||
|
||||
@@ -129,6 +129,8 @@ int neuron_already_running()
|
||||
|
||||
snprintf(buf, sizeof(buf), "%ld", (long) getpid());
|
||||
size = write(fd, buf, strlen(buf) + 1);
|
||||
nlog_warn("write %s, error %s(%d)", NEURON_DAEMON_LOCK_FNAME,
|
||||
strerror(errno), errno);
|
||||
assert(size != -1);
|
||||
|
||||
return 0;
|
||||
|
||||
+11
-10
@@ -205,19 +205,20 @@ neu_event_timer_t *neu_event_add_timer(neu_events_t * events,
|
||||
|
||||
ret = epoll_ctl(events->epoll_fd, EPOLL_CTL_ADD, timer_fd, &event);
|
||||
|
||||
zlog_info(neuron,
|
||||
"add timer, second: %" PRId64 ", millisecond: %" PRId64
|
||||
", timer: %d in epoll %d, "
|
||||
"ret: %d",
|
||||
timer.second, timer.millisecond, timer_fd, events->epoll_fd, ret);
|
||||
zlog_notice(neuron,
|
||||
"add timer, second: %" PRId64 ", millisecond: %" PRId64
|
||||
", timer: %d in epoll %d, "
|
||||
"ret: %d",
|
||||
timer.second, timer.millisecond, timer_fd, events->epoll_fd,
|
||||
ret);
|
||||
|
||||
return timer_ctx;
|
||||
}
|
||||
|
||||
int neu_event_del_timer(neu_events_t *events, neu_event_timer_t *timer)
|
||||
{
|
||||
zlog_info(neuron, "del timer: %d from epoll: %d", timer->fd,
|
||||
events->epoll_fd);
|
||||
zlog_notice(neuron, "del timer: %d from epoll: %d", timer->fd,
|
||||
events->epoll_fd);
|
||||
|
||||
timer->stop = true;
|
||||
nng_mtx_lock(timer->mtx);
|
||||
@@ -251,8 +252,8 @@ neu_event_io_t *neu_event_add_io(neu_events_t *events, neu_event_io_param_t io)
|
||||
|
||||
ret = epoll_ctl(events->epoll_fd, EPOLL_CTL_ADD, io.fd, &event);
|
||||
|
||||
nlog_info("add io, fd: %d, epoll: %d, ret: %d", io.fd, events->epoll_fd,
|
||||
ret);
|
||||
nlog_notice("add io, fd: %d, epoll: %d, ret: %d", io.fd, events->epoll_fd,
|
||||
ret);
|
||||
|
||||
return io_ctx;
|
||||
}
|
||||
@@ -260,7 +261,7 @@ neu_event_io_t *neu_event_add_io(neu_events_t *events, neu_event_io_param_t io)
|
||||
int neu_event_del_io(neu_events_t *events, neu_event_io_t *io)
|
||||
{
|
||||
struct event_data *data = (struct event_data *) io->event_data;
|
||||
zlog_info(neuron, "del io: %d from epoll: %d", io->fd, events->epoll_fd);
|
||||
zlog_notice(neuron, "del io: %d from epoll: %d", io->fd, events->epoll_fd);
|
||||
|
||||
epoll_ctl(events->epoll_fd, EPOLL_CTL_DEL, io->fd, NULL);
|
||||
switch (data->type) {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ static bool exit_flag = false;
|
||||
static neu_manager_t *g_manager = NULL;
|
||||
zlog_category_t * neuron = NULL;
|
||||
bool disable_jwt = false;
|
||||
int default_log_level = ZLOG_LEVEL_INFO;
|
||||
int default_log_level = ZLOG_LEVEL_NOTICE;
|
||||
|
||||
int64_t global_timestamp = 0;
|
||||
|
||||
|
||||
@@ -199,7 +199,8 @@ int neu_json_tag_check_type(neu_json_tag_t *tag)
|
||||
return NEU_JSON_BOOL == tag->t;
|
||||
case NEU_TYPE_BYTES:
|
||||
case NEU_TYPE_STRING:
|
||||
return NEU_JSON_STR == tag->t;
|
||||
return NEU_JSON_STR == tag->t &&
|
||||
strlen(tag->value.val_str) <= NEU_VALUE_SIZE;
|
||||
}
|
||||
} else {
|
||||
// non-static tag should have no initial value
|
||||
|
||||
+117
-17
@@ -25,6 +25,7 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
@@ -49,9 +50,12 @@
|
||||
|
||||
#define PATH_MAX_SIZE 128
|
||||
|
||||
static const char *plugin_file = "persistence/plugins.json";
|
||||
static const char *db_file = "persistence/sqlite.db";
|
||||
static sqlite3 * global_db = NULL;
|
||||
static const char *plugin_file = "persistence/plugins.json";
|
||||
static const char *db_file = "persistence/sqlite.db";
|
||||
static sqlite3 * global_db = NULL;
|
||||
pthread_rwlock_t global_rwlock = PTHREAD_RWLOCK_INITIALIZER;
|
||||
static int global_node_count = 0;
|
||||
static int global_tag_count = 0;
|
||||
|
||||
static inline bool ends_with(const char *str, const char *suffix)
|
||||
{
|
||||
@@ -383,8 +387,8 @@ static int apply_schema_file(sqlite3 *db, const char *dir, const char *file)
|
||||
|
||||
end:
|
||||
if (0 == rv) {
|
||||
nlog_info("success apply schema `%s`, version=`%s` description=`%s`",
|
||||
path, version, description);
|
||||
nlog_notice("success apply schema `%s`, version=`%s` description=`%s`",
|
||||
path, version, description);
|
||||
} else {
|
||||
nlog_error("fail apply schema `%s`, version=`%s` description=`%s`",
|
||||
path, version, description);
|
||||
@@ -441,7 +445,7 @@ static int apply_schemas(sqlite3 *db, const char *dir)
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
nlog_info("schema head version=%s", version ? version : "none");
|
||||
nlog_notice("schema head version=%s", version ? version : "none");
|
||||
|
||||
if (dirty) {
|
||||
nlog_error("database is dirty, need manual intervention");
|
||||
@@ -474,6 +478,44 @@ static int apply_schemas(sqlite3 *db, const char *dir)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline int node_count_load()
|
||||
{
|
||||
int rv = 0;
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
char * query = "select count(*) from nodes";
|
||||
|
||||
if (SQLITE_OK == sqlite3_prepare_v2(global_db, query, -1, &stmt, NULL) &&
|
||||
SQLITE_ROW == sqlite3_step(stmt)) {
|
||||
pthread_rwlock_wrlock(&global_rwlock);
|
||||
global_node_count = sqlite3_column_int(stmt, 0);
|
||||
pthread_rwlock_unlock(&global_rwlock);
|
||||
} else {
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline int tag_count_load()
|
||||
{
|
||||
int rv = 0;
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
char * query = "select count(*) from tags";
|
||||
|
||||
if (SQLITE_OK == sqlite3_prepare_v2(global_db, query, -1, &stmt, NULL) &&
|
||||
SQLITE_ROW == sqlite3_step(stmt)) {
|
||||
pthread_rwlock_wrlock(&global_rwlock);
|
||||
global_tag_count = sqlite3_column_int(stmt, 0);
|
||||
pthread_rwlock_unlock(&global_rwlock);
|
||||
} else {
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int neu_persister_create(const char *schema_dir)
|
||||
{
|
||||
int rv = sqlite3_open(db_file, &global_db);
|
||||
@@ -506,6 +548,12 @@ int neu_persister_create(const char *schema_dir)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 != node_count_load() || 0 != tag_count_load()) {
|
||||
nlog_fatal("load node/tag count fail");
|
||||
sqlite3_close(global_db);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -514,6 +562,36 @@ sqlite3 *neu_persister_get_db()
|
||||
return global_db;
|
||||
}
|
||||
|
||||
static inline void node_count_add(int n)
|
||||
{
|
||||
pthread_rwlock_wrlock(&global_rwlock);
|
||||
global_node_count += n;
|
||||
pthread_rwlock_unlock(&global_rwlock);
|
||||
}
|
||||
|
||||
int neu_persister_node_count()
|
||||
{
|
||||
pthread_rwlock_rdlock(&global_rwlock);
|
||||
int cnt = global_node_count;
|
||||
pthread_rwlock_unlock(&global_rwlock);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static inline void tag_count_add(int n)
|
||||
{
|
||||
pthread_rwlock_wrlock(&global_rwlock);
|
||||
global_tag_count += n;
|
||||
pthread_rwlock_unlock(&global_rwlock);
|
||||
}
|
||||
|
||||
int neu_persister_tag_count()
|
||||
{
|
||||
pthread_rwlock_rdlock(&global_rwlock);
|
||||
int cnt = global_tag_count;
|
||||
pthread_rwlock_unlock(&global_rwlock);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void neu_persister_destroy()
|
||||
{
|
||||
sqlite3_close(global_db);
|
||||
@@ -521,10 +599,15 @@ void neu_persister_destroy()
|
||||
|
||||
int neu_persister_store_node(neu_persist_node_info_t *info)
|
||||
{
|
||||
return execute_sql(global_db,
|
||||
"INSERT INTO nodes (name, type, state, plugin_name) "
|
||||
"VALUES (%Q, %i, %i, %Q)",
|
||||
info->name, info->type, info->state, info->plugin_name);
|
||||
int rv =
|
||||
execute_sql(global_db,
|
||||
"INSERT INTO nodes (name, type, state, plugin_name) "
|
||||
"VALUES (%Q, %i, %i, %Q)",
|
||||
info->name, info->type, info->state, info->plugin_name);
|
||||
if (0 == rv) {
|
||||
node_count_add(1);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static UT_icd node_info_icd = {
|
||||
@@ -585,8 +668,13 @@ int neu_persister_delete_node(const char *node_name)
|
||||
{
|
||||
// rely on foreign key constraints to remove settings, groups, tags and
|
||||
// subscriptions
|
||||
return execute_sql(global_db, "DELETE FROM nodes WHERE name=%Q;",
|
||||
node_name);
|
||||
int rv =
|
||||
execute_sql(global_db, "DELETE FROM nodes WHERE name=%Q;", node_name);
|
||||
if (0 == rv) {
|
||||
node_count_add(-1);
|
||||
tag_count_load();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
int neu_persister_update_node(const char *node_name, const char *new_name)
|
||||
@@ -716,6 +804,9 @@ int neu_persister_store_tag(const char *driver_name, const char *group_name,
|
||||
tag->attribute, tag->precision, tag->type,
|
||||
tag->decimal, tag->description, val_str);
|
||||
|
||||
if (0 == rv) {
|
||||
tag_count_add(1);
|
||||
}
|
||||
free(val_str);
|
||||
return rv;
|
||||
}
|
||||
@@ -821,11 +912,12 @@ int neu_persister_store_tags(const char *driver_name, const char *group_name,
|
||||
goto error;
|
||||
}
|
||||
|
||||
tag_count_add(n);
|
||||
sqlite3_finalize(stmt);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
nlog_info("rollback transaction");
|
||||
nlog_warn("rollback transaction");
|
||||
sqlite3_exec(global_db, "ROLLBACK", NULL, NULL, NULL);
|
||||
sqlite3_finalize(stmt);
|
||||
free(val_str);
|
||||
@@ -926,10 +1018,14 @@ int neu_persister_update_tag_value(const char * driver_name,
|
||||
int neu_persister_delete_tag(const char *driver_name, const char *group_name,
|
||||
const char *tag_name)
|
||||
{
|
||||
return execute_sql(
|
||||
int rv = execute_sql(
|
||||
global_db,
|
||||
"DELETE FROM tags WHERE driver_name=%Q AND group_name=%Q AND name=%Q",
|
||||
driver_name, group_name, tag_name);
|
||||
if (0 == rv) {
|
||||
tag_count_add(-1);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
int neu_persister_store_subscription(const char *app_name,
|
||||
@@ -1101,9 +1197,13 @@ error:
|
||||
int neu_persister_delete_group(const char *driver_name, const char *group_name)
|
||||
{
|
||||
// rely on foreign key constraints to delete tags and subscriptions
|
||||
return execute_sql(global_db,
|
||||
"DELETE FROM groups WHERE driver_name=%Q AND name=%Q",
|
||||
driver_name, group_name);
|
||||
int rv = execute_sql(global_db,
|
||||
"DELETE FROM groups WHERE driver_name=%Q AND name=%Q",
|
||||
driver_name, group_name);
|
||||
if (0 == rv) {
|
||||
tag_count_load();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
int neu_persister_store_node_setting(const char *node_name, const char *setting)
|
||||
|
||||
@@ -295,6 +295,8 @@ int neu_http_response(nng_aio *aio, neu_err_code_e code, char *content)
|
||||
case NEU_ERR_MQTT_CONNECT_FAILURE:
|
||||
case NEU_ERR_MQTT_SUBSCRIBE_FAILURE:
|
||||
case NEU_ERR_MQTT_PUBLISH_FAILURE:
|
||||
case NEU_ERR_STRING_TOO_LONG:
|
||||
case NEU_ERR_FILE_WRITE_FAILURE:
|
||||
status = NNG_HTTP_STATUS_OK;
|
||||
break;
|
||||
case NEU_ERR_EINTERNAL:
|
||||
|
||||
@@ -47,4 +47,4 @@ gtest_discover_tests(json_test)
|
||||
gtest_discover_tests(http_test)
|
||||
gtest_discover_tests(jwt_test)
|
||||
gtest_discover_tests(base64_test)
|
||||
gtest_discover_tests(tag_sort_test)
|
||||
gtest_discover_tests(tag_sort_test)
|
||||
|
||||
Reference in New Issue
Block a user