Merge pull request #1176 from hxy7yx/main

Open source Modbus TCP/RTU, delete existing Modbus TCP community
This commit is contained in:
fengzeroz
2023-04-11 15:58:20 +08:00
committed by GitHub
27 changed files with 1676 additions and 282 deletions
-1
View File
@@ -12,4 +12,3 @@ PointerAlignment: Right
SpaceAfterCStyleCast: true
AllowShortFunctionsOnASingleLine: Inline
BreakBeforeBinaryOperators: None
+3 -1
View File
@@ -3,7 +3,9 @@
"libplugin-mqtt.so",
"libplugin-ekuiper.so",
"libplugin-monitor.so",
"libplugin-modbus-tcp-comm.so",
"libplugin-modbus-tcp.so",
"libplugin-modbus-rtu.so",
"libplugin-modbus-qh-tcp.so",
"libplugin-file.so"
]
}
+184
View File
@@ -0,0 +1,184 @@
*** 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}
+77 -90
View File
@@ -1,4 +1,7 @@
*** Settings ***
Library Process
Library OperatingSystem
Resource resource/api.resource
Resource resource/common.resource
Resource resource/error.resource
@@ -7,9 +10,13 @@ Suite Setup Modbus Test Setup
Suite Teardown Modbus Test Teardown
*** Variables ***
${modbus_node} modbus_node
${PLUGIN-MODBUS-TCP} Modbus TCP
${MODBUS_TCP_CONFIG_WRONG} {"host": "127.0.0.1", "port": 60502}
${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}
${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}}
@@ -46,135 +53,115 @@ ${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_node} ${MODBUS_TCP_CONFIG}
${modbus_tcp_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_node} ${MODBUS_TCP_CONFIG_WRONG}
${modbus_tcp_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_node}
${hold_uint16} ${modbus_node}
${hold_int32} ${modbus_node}
${hold_uint32} ${modbus_node}
${hold_float} ${modbus_node}
${hold_string} ${modbus_node}
${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}
${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}
${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}
${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_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_bit_1} ${modbus_node}
${input_bit_2} ${modbus_node}
${input_bit_3} ${modbus_node}
${input_bit_4} ${modbus_node}
${input_bit_5} ${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}
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_node} 200 ${NEU_ERR_TAG_TYPE_NOT_SUPPORT}
${input_bit_1_attribute_unmatch} ${modbus_node} 200 ${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT}
${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}
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_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"
${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"
${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
${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
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_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_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_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
${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
Read some tags at time, it will be success.
${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
[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}
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_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_tcp_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_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_tcp_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_node} Compare Tag Value As Int 120
${hold_int16} ${hold_int16_type_update} hold_int16 ${modbus_node} Compare Tag Value As Int 120
${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
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_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
${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}
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_node}
12 ${input_bit_1} input ${modbus_tcp_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_node}
1 ${input_bit_1} input_bit_1 ${modbus_tcp_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_node}
1 ${hold_int16} hold_int16 ${modbus_tcp_node}
*** Keywords ***
Modbus Test Setup
@@ -182,17 +169,17 @@ Modbus Test Setup
Start Neuronx
${res}= Add Node ${modbus_node} ${PLUGIN-MODBUS-TCP}
${res}= Add Node ${modbus_tcp_node} ${PLUGIN-MODBUS-TCP}
Check Response Status ${res} 200
${res}= Node Setting ${modbus_node} ${MODBUS_TCP_CONFIG}
${res}= Node Setting ${modbus_tcp_node} ${MODBUS_TCP_CONFIG}
Check Response Status ${res} 200
${state}= Get Node State ${modbus_node}
${state}= Get Node State ${modbus_tcp_node}
Should Be Equal As Integers ${state}[running] ${NODE_STATE_RUNNING}
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_DISCONNECTED}
# Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_CONNECTED}
Modbus Test Teardown
Del Node ${modbus_node}
Del Node ${modbus_tcp_node}
Stop Neuronx
Terminate All Processes kill=false
+3 -3
View File
@@ -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}
Node Setting ${modbus-tcp-2} {"host": "127.0.0.1", "port": 502, "timeout": 3000}
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 ${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}
Node Setting ${modbus-tcp-2} {"host": "127.0.0.1", "port": 502, "timeout": 3000, "connection_mode": 0, "interval": 20}
Neuron Stop Running ${process}
${process} = Neuron Start Running
+1 -1
View File
@@ -3,7 +3,7 @@ Library REST http://127.0.0.1:7000
Resource common.resource
*** Variables ***
${PLUGIN-MODBUS-TCP} Modbus TCP community
${PLUGIN-MODBUS-TCP} Modbus TCP
${PLUGIN-MQTT} MQTT
${PLUGIN-EKUIPER} eKuiper
+2 -2
View File
@@ -17,7 +17,7 @@ Resource simulator.resource
${test_data_dir} ft/data
${PLUGIN_MODBUS_TCP} Modbus TCP community
${PLUGIN_MODBUS_TCP} Modbus TCP
${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, "timeout": 3000}
${MODBUS_TCP_CONFIG} {"host": "127.0.0.1", "port": 60502, "connection_mode": 0, "timeout": 3000, "interval": 20}
*** Variables ***
${neuron_process}
+5 -9
View File
@@ -70,13 +70,9 @@ Read some ${tags} from ${node}, it will be success.
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
${res}= Add Tags ${node} group ${tags}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Sleep 290ms
${res}= Read Tags ${node} group
@@ -238,7 +234,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.
Read a ${tag} with named ${tag_name} that don't exist in plc form ${node}, it will be failure ${error}.
[Tags] Driver 15
${res}= Add Group ${node} group 100
@@ -252,7 +248,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} ${tag_name} ${NEU_ERR_TAG_NOT_EXIST}
Check Tag Error As Int ${res}[tags] ${tag_name} ${error}
[Teardown] Del Group ${node} group
+28 -8
View File
@@ -3,13 +3,33 @@ 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-community.json DESTINATION ${CMAKE_BINARY_DIR}/plugins/schema/)
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/)
# modbus rtu plugin
set(MODBUS_TCP_PLUGIN plugin-modbus-tcp-comm)
set(MODBUS_TCP_PLUGIN_SOURCES modbus_tcp.c
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
${MODBUS_SRC})
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)
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)
+104
View File
@@ -0,0 +1,104 @@
{
"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
}
]
}
}
}
+305
View File
@@ -0,0 +1,305 @@
{
"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
}
}
}
-67
View File
@@ -1,67 +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": 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
}
}
}
+117
View File
@@ -0,0 +1,117 @@
{
"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
}
}
}
+53
View File
@@ -23,6 +23,25 @@
#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) >=
@@ -149,6 +168,40 @@ 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) {
+9
View File
@@ -92,6 +92,15 @@ 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
+10
View File
@@ -123,6 +123,16 @@ 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) {
+224
View File
@@ -0,0 +1,224 @@
/**
* 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, &param);
} else {
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
plugin->conn =
neu_conn_new(&param, (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);
}
+108 -29
View File
@@ -16,14 +16,16 @@
* 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 {
char * group;
UT_array * tags;
char * group;
modbus_read_cmd_sort_t *cmd_sort;
};
@@ -46,22 +48,76 @@ 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);
return neu_conn_send(plugin->conn, 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;
}
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;
neu_conn_state_t state = { 0 };
int64_t rtt = NEU_METRIC_LAST_RTT_MS_MAX;
struct modbus_group_data *gd = NULL;
int64_t rtt = NEU_METRIC_LAST_RTT_MS_MAX;
if (group->user_data == NULL) {
gd = calloc(1, sizeof(struct modbus_group_data));
@@ -81,32 +137,39 @@ 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++) {
uint16_t response_size = 0;
int64_t start = neu_time_ms();
plugin->cmd_idx = i;
uint16_t response_size = 0;
uint64_t read_tms = neu_time_ms();
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) {
process_protocol_buf(plugin, response_size);
int64_t end = neu_time_ms();
if (end - start < rtt) {
rtt = end - start;
}
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);
}
}
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,
@@ -114,12 +177,11 @@ 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)
uint8_t *bytes, int error)
{
neu_plugin_t * plugin = (neu_plugin_t *) ctx;
struct modbus_group_data *gd =
@@ -127,11 +189,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 (bytes == NULL) {
if (error != NEU_ERR_SUCCESS) {
neu_dvalue_t dvalue = { 0 };
dvalue.type = NEU_TYPE_ERROR;
dvalue.value.i32 = NEU_ERR_PLUGIN_DISCONNECTED;
dvalue.value.i32 = error;
plugin->common.adapter_callbacks->driver.update(
plugin->common.adapter, gd->group, NULL, dvalue);
return 0;
@@ -182,6 +244,11 @@ 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:
@@ -196,7 +263,6 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
case MODBUS_AREA_INPUT:
break;
}
break;
}
case NEU_TYPE_STRING: {
@@ -218,7 +284,6 @@ 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:
@@ -242,18 +307,23 @@ 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;
@@ -318,12 +388,21 @@ static int process_protocol_buf(neu_plugin_t *plugin, uint16_t response_size)
neu_protocol_unpack_buf_t pbuf = { 0 };
ssize_t ret = 0;
ret = neu_conn_recv(plugin->conn, recv_buf, response_size);
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);
}
if (ret > 0) {
if (ret == response_size) {
if (response_size < 512) {
plog_recv_protocol(plugin, recv_buf, ret);
}
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);
+11 -1
View File
@@ -33,18 +33,28 @@ 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);
uint8_t *bytes, int error);
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);
+276
View File
@@ -0,0 +1,276 @@
/**
* 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, &param);
} else {
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
plugin->conn =
neu_conn_new(&param, (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);
}
+83 -20
View File
@@ -20,6 +20,7 @@
#include <neuron.h>
#include "modbus_req.h"
#include "modbus_stack.h"
struct modbus_stack {
@@ -28,10 +29,16 @@ struct modbus_stack {
modbus_stack_value value_fn;
modbus_stack_write_resp write_resp;
uint16_t seq;
modbus_protocol_e protocol;
uint16_t read_seq;
uint16_t write_seq;
uint8_t *buf;
uint16_t buf_size;
};
modbus_stack_t *modbus_stack_create(void *ctx, modbus_stack_send send_fn,
modbus_stack_t *modbus_stack_create(void *ctx, modbus_protocol_e protocol,
modbus_stack_send send_fn,
modbus_stack_value value_fn,
modbus_stack_write_resp write_resp)
{
@@ -41,12 +48,17 @@ modbus_stack_t *modbus_stack_create(void *ctx, modbus_stack_send send_fn,
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);
}
@@ -56,9 +68,14 @@ int modbus_stack_recv(modbus_stack_t *stack, neu_protocol_unpack_buf_t *buf)
struct modbus_code code = { 0 };
int ret = 0;
ret = modbus_header_unwrap(buf, &header);
if (ret <= 0) {
return ret;
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_code_unwrap(buf, &code);
@@ -78,8 +95,19 @@ int modbus_stack_recv(modbus_stack_t *stack, neu_protocol_unpack_buf_t *buf)
return ret;
}
bytes = neu_protocol_unpack_buf(buf, data.n_byte);
stack->value_fn(stack->ctx, code.slave_id, data.n_byte, bytes);
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);
}
break;
}
@@ -95,6 +123,14 @@ 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);
}
@@ -108,6 +144,9 @@ 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) {
@@ -132,14 +171,23 @@ int modbus_stack_read(modbus_stack_t *stack, uint8_t slave_id,
*response_size += sizeof(struct modbus_code);
*response_size += sizeof(struct modbus_data);
modbus_header_wrap(&pbuf, stack->seq++);
*response_size += sizeof(struct modbus_header);
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;
}
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);
stack->value_fn(stack->ctx, 0, 0, NULL, NEU_ERR_PLUGIN_DISCONNECTED);
}
return ret;
}
@@ -148,11 +196,14 @@ 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)
{
uint8_t * buf = calloc(256, 1);
neu_protocol_pack_buf_t pbuf = { 0 };
int ret = 0;
static __thread neu_protocol_pack_buf_t pbuf = { 0 };
neu_protocol_pack_buf_init(&pbuf, buf, 256);
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);
}
switch (area) {
case MODBUS_AREA_COIL:
@@ -169,22 +220,34 @@ 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:
assert(false);
stack->write_resp(stack->ctx, req, NEU_ERR_PLUGIN_TAG_NOT_ALLOW_WRITE);
break;
}
*response_size += sizeof(struct modbus_code);
*response_size += sizeof(struct modbus_address);
modbus_header_wrap(&pbuf, stack->seq++);
*response_size += sizeof(struct modbus_header);
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;
}
ret = stack->send_fn(stack->ctx, neu_protocol_pack_buf_used_size(&pbuf),
neu_protocol_pack_buf_get(&pbuf));
int 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;
}
+15 -8
View File
@@ -29,22 +29,29 @@ 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);
uint8_t *bytes, int error);
typedef int (*modbus_stack_write_resp)(void *ctx, void *req, int error);
modbus_stack_t *modbus_stack_create(void *ctx, modbus_stack_send send_fn,
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_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,
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,
int modbus_stack_read(modbus_stack_t *stack, 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);
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);
#endif
+49 -30
View File
@@ -18,19 +18,22 @@
**/
#include <stdlib.h>
#include "neuron.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_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);
@@ -56,18 +59,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-community",
.module_name = "Modbus TCP community",
.schema = "modbus-tcp",
.module_name = "Modbus TCP",
.module_descr =
"The modbus-tcp community plugin is used for devices connected using "
"the modbus protocol tcp mode.",
.module_descr_zh =
"modbus-tcp community 插件用于连接使用 modbus tcp 协议的设备",
"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 "
"插件的加强版,用户可选择作为客户端连接,还是服务端连接",
.intf_funs = &plugin_intf_funs,
.kind = NEU_PLUGIN_KIND_SYSTEM,
.type = NEU_NA_TYPE_DRIVER,
.single = false,
.display = true,
.single = false,
};
static neu_plugin_t *driver_open(void)
@@ -88,9 +91,11 @@ static int driver_close(neu_plugin_t *plugin)
static int driver_init(neu_plugin_t *plugin)
{
plugin->events = neu_event_new();
plugin->stack = modbus_stack_create((void *) plugin, modbus_send_msg,
modbus_value_handle, modbus_write_resp);
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;
}
@@ -131,32 +136,46 @@ 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_conn_param_t param = { 0 };
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 };
ret =
neu_parse_param((char *) config, &err_param, 3, &port, &host, &timeout);
ret = neu_parse_param((char *) config, &err_param, 5, &port, &host, &mode,
&timeout, &interval);
if (ret != 0) {
plog_warn(plugin, "config: %s, decode error: %s", (char *) config,
err_param);
plog_warn(plugin, "config: %s, decode error: %s", config, err_param);
free(err_param);
free(host.v.val_str);
return -1;
}
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;
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;
}
plog_info(plugin, "config: host: %s, port: %" PRId64 ", timeout: %" PRId64,
host.v.val_str, port.v.val_int, 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);
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
if (plugin->conn != NULL) {
plugin->conn = neu_conn_reconfig(plugin->conn, &param);
} else {
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
plugin->conn =
neu_conn_new(&param, (void *) plugin, modbus_conn_connected,
modbus_conn_disconnected);
-8
View File
@@ -224,14 +224,6 @@ 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",
+5 -1
View File
@@ -205,7 +205,11 @@ 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;
res_data->n_byte = len;
if (len > 0xff) {
res_data->n_byte = 0xff;
} else {
res_data->n_byte = len;
}
res_header->len += sizeof(struct modbus_data) + len;
break;
case MODBUS_WRITE_S_COIL:
+3 -2
View File
@@ -23,7 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <neuron.h>
#include "neuron.h"
#include "modbus_s.h"
@@ -31,6 +31,7 @@ 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);
@@ -222,7 +223,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[60000] = { 0 };
uint8_t res[20000] = { 0 };
int res_len = 0;
len = neu_conn_tcp_server_recv(conn, fd, buf->buf + buf->len,
+1 -1
View File
@@ -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)