mirror of
https://github.com/emqx/neuron.git
synced 2026-10-29 23:19:18 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c789ffc8ad | ||
|
|
f93bf7183b | ||
|
|
12eb0e6c74 | ||
|
|
e7b62d9218 | ||
|
|
a2a608a720 | ||
|
|
0583a45d1d | ||
|
|
d4a749c3e9 | ||
|
|
a86064cf8a | ||
|
|
471f8e439e | ||
|
|
6ab74604d4 | ||
|
|
dd1faf19c7 | ||
|
|
84c117cafb | ||
|
|
9e091c3fc9 | ||
|
|
c03d85d31d | ||
|
|
5f1a702bdb | ||
|
|
382c17c78a | ||
|
|
34247aa1f1 | ||
|
|
4cf7357a22 | ||
|
|
29ae8339e9 | ||
|
|
146bb62e81 | ||
|
|
d65773eb90 | ||
|
|
9301489e3e | ||
|
|
d68668619a | ||
|
|
fa3c6a1eb8 | ||
|
|
f707797208 | ||
|
|
4146bd1510 | ||
|
|
7c52356d30 | ||
|
|
e3654f4303 | ||
|
|
9c81e79992 | ||
|
|
39a1d924e7 | ||
|
|
4b237a67d0 | ||
|
|
2eb00f54fc | ||
|
|
a24f2a8a76 | ||
|
|
384eab840a | ||
|
|
5003991ad4 | ||
|
|
dad58af7e6 | ||
|
|
cd8727b81e | ||
|
|
a5b2a345c6 | ||
|
|
46e64f7845 | ||
|
|
c62ab89ff2 | ||
|
|
55171e1eb0 | ||
|
|
d586487077 | ||
|
|
fa8dcb3f98 | ||
|
|
a115fbd303 | ||
|
|
94f164e08c | ||
|
|
d2d1d3cd91 | ||
|
|
e88894e34d | ||
|
|
10a4521a99 | ||
|
|
ef06dec1a5 | ||
|
|
45994cc23f | ||
|
|
f360d34688 | ||
|
|
cae5c3f9c6 | ||
|
|
68775233d3 | ||
|
|
2d4ef2e81a | ||
|
|
b1fc78632d | ||
|
|
e52a3d8dd9 | ||
|
|
82e216c161 | ||
|
|
2cb2d81254 | ||
|
|
203acf54c8 | ||
|
|
413cb7600f | ||
|
|
8d57bbb252 | ||
|
|
3cecf258a3 | ||
|
|
eb5de62e46 | ||
|
|
0fde678e1e | ||
|
|
2b33aa933a | ||
|
|
9d1c68a420 | ||
|
|
5ee5b71dab | ||
|
|
3de06119d0 | ||
|
|
7e4119de21 | ||
|
|
40df46a0fc | ||
|
|
eedf2a9819 | ||
|
|
4472c2aeb1 | ||
|
|
872ac53c3f | ||
|
|
a5fea3f2bb | ||
|
|
1e0ed4be64 | ||
|
|
0080cde80b | ||
|
|
5cf6d23d43 | ||
|
|
caecaf67a6 | ||
|
|
8efdc08a32 | ||
|
|
6d95a37651 | ||
|
|
5a0a6206cf | ||
|
|
4035de49ca | ||
|
|
e379386249 | ||
|
|
c003332911 | ||
|
|
4c38f80618 | ||
|
|
2d0e36d596 | ||
|
|
b9945c458e | ||
|
|
614b949354 | ||
|
|
134dffee48 | ||
|
|
820265dfc3 | ||
|
|
3fcbe3f7b7 | ||
|
|
ee6e962aa6 | ||
|
|
a7bf4a85e5 | ||
|
|
10df7590ca | ||
|
|
c31db4b5db |
@@ -8,9 +8,9 @@ on:
|
||||
- published
|
||||
|
||||
env:
|
||||
VERSION: 2.4.0
|
||||
UI_VERSION: 2.4.0
|
||||
BRANCH: main
|
||||
VERSION: 2.5.3
|
||||
UI_VERSION: 2.5.3
|
||||
BRANCH: v2.5
|
||||
|
||||
jobs:
|
||||
cross-build:
|
||||
|
||||
+6
-1
@@ -89,6 +89,12 @@ set(NEURON_BASE_SOURCES
|
||||
src/utils/async_queue.c
|
||||
src/utils/mem_cache.c
|
||||
${PERSIST_SOURCES})
|
||||
|
||||
if (SMART_LINK)
|
||||
message(STATUS "using smart link")
|
||||
add_definitions(-DNEU_SMART_LINK)
|
||||
set(NEURON_BASE_SOURCES ${NEURON_BASE_SOURCES} src/connection/smart_link.c)
|
||||
endif()
|
||||
|
||||
add_library(neuron-base SHARED)
|
||||
target_sources(neuron-base PRIVATE ${NEURON_BASE_SOURCES} ${NEURON_SRC_PARSE})
|
||||
@@ -156,7 +162,6 @@ add_subdirectory(plugins/modbus)
|
||||
add_subdirectory(plugins/mqtt)
|
||||
add_subdirectory(plugins/ekuiper)
|
||||
add_subdirectory(plugins/monitor)
|
||||
add_subdirectory(plugins/file)
|
||||
|
||||
add_subdirectory(simulator)
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
"libplugin-ekuiper.so",
|
||||
"libplugin-monitor.so",
|
||||
"libplugin-modbus-tcp.so",
|
||||
"libplugin-modbus-rtu.so",
|
||||
"libplugin-modbus-qh-tcp.so",
|
||||
"libplugin-file.so"
|
||||
"libplugin-modbus-rtu.so"
|
||||
]
|
||||
}
|
||||
@@ -59,6 +59,19 @@ Get APP node, it should be success.
|
||||
Check Response Status ${res} 200
|
||||
Node Should Exist ${res}[nodes] mqtt-node
|
||||
|
||||
Update node name to empty string, it should fail.
|
||||
${res} = Update Node modbus-node ${EMPTY}
|
||||
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_NODE_NAME_EMPTY}
|
||||
|
||||
Update node name to excessive long string, it should fail.
|
||||
${name} = Evaluate 'a'*200
|
||||
${res} = Update Node modbus-node ${name}
|
||||
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_NODE_NAME_TOO_LONG}
|
||||
|
||||
Update driver node name, it should fail if the node does not exist
|
||||
${res} = Update Node modbus-node-nonexistent mqtt-node
|
||||
|
||||
|
||||
@@ -6,10 +6,15 @@ Suite Setup Start Neuronx
|
||||
Suite Teardown Stop Neuronx
|
||||
|
||||
*** Test Cases ***
|
||||
login with invalid username and password, it should return failure
|
||||
login with invalid username, it should return failure
|
||||
POST /api/v2/login {"name":"admin1", "pass": "0000"}
|
||||
Integer response status 401
|
||||
Integer $.error ${NEU_ERR_INVALID_USER_OR_PASSWORD}
|
||||
Integer $.error ${NEU_ERR_INVALID_USER}
|
||||
|
||||
login with invalid password, it should return failure
|
||||
POST /api/v2/login {"name":"admin", "pass": "2333"}
|
||||
Integer response status 401
|
||||
Integer $.error ${NEU_ERR_INVALID_PASSWORD}
|
||||
|
||||
login with username and password, it should return success
|
||||
POST /api/v2/login {"name":"admin", "pass": "0000"}
|
||||
|
||||
@@ -16,6 +16,10 @@ ${NEU_ERR_FILE_NOT_EXIST} 1011
|
||||
${NEU_ERR_INVALID_PASSWORD_LEN} 1012
|
||||
${NEU_ERR_DUPLICATE_PASSWORD} 1013
|
||||
${NEU_ERR_COMMAND_EXECUTION_FAILED} 1014
|
||||
${NEU_ERR_IP_ADDRESS_INVALID} 1015
|
||||
${NEU_ERR_IP_ADDRESS_IN_USE} 1016
|
||||
${NEU_ERR_INVALID_USER} 1017
|
||||
${NEU_ERR_INVALID_PASSWORD} 1018
|
||||
|
||||
${NEU_ERR_NODE_EXIST} 2002
|
||||
${NEU_ERR_NODE_NOT_EXIST} 2003
|
||||
@@ -27,7 +31,10 @@ ${NEU_ERR_NODE_NOT_RUNNING} 2008
|
||||
${NEU_ERR_NODE_IS_STOPED} 2009
|
||||
${NEU_ERR_NODE_NAME_TOO_LONG} 2010
|
||||
${NEU_ERR_NODE_NOT_ALLOW_DELETE} 2011
|
||||
${NEU_ERR_NODE_NOT_ALLOW_SUBSCRIBE} 2012
|
||||
${NEU_ERR_NODE_NOT_ALLOW_UPDATE} 2013
|
||||
${NEU_ERR_NODE_NOT_ALLOW_MAP} 2014
|
||||
${NEU_ERR_NODE_NAME_EMPTY} 2015
|
||||
|
||||
${NEU_ERR_GROUP_ALREADY_SUBSCRIBED} 2101
|
||||
${NEU_ERR_GROUP_NOT_SUBSCRIBE} 2102
|
||||
|
||||
@@ -44,6 +44,14 @@ Create a template with too long name, it should fail.
|
||||
[Teardown] Del Template ${g_long_str}
|
||||
|
||||
|
||||
Create a template with too long plugin name, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_long_str} ${g_groups}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_PLUGIN_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Create a template having no group, it should success.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_empty}
|
||||
Check Response Status ${res} 200
|
||||
@@ -126,12 +134,26 @@ Create a template with singleton plugin, it should fail.
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Create a template with north plugin, it should fail.
|
||||
${res} = Add Template ${g_template} MQTT ${g_empty}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_PLUGIN_NOT_SUPPORT_TEMPLATE}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Get nonexistent template, it should fail.
|
||||
${res} = Get Template ${g_template}
|
||||
Check Response Status ${res} 404
|
||||
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NOT_FOUND}
|
||||
|
||||
|
||||
Get a template using too long name query parameter, it should fail.
|
||||
${res} = Get Template ${g_long_str}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_PARAM_IS_WRONG}
|
||||
|
||||
|
||||
Get an existent template having no groups, it should success.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_empty}
|
||||
Check Response Status ${res} 200
|
||||
@@ -186,6 +208,12 @@ Delete a nonexistent template, it should fail.
|
||||
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NOT_FOUND}
|
||||
|
||||
|
||||
Delete a template using too long name query parameter, it should fail.
|
||||
${res} = Del Template ${g_long_str}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_PARAM_IS_WRONG}
|
||||
|
||||
|
||||
Delete an existent template, it should success.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_empty}
|
||||
Check Response Status ${res} 200
|
||||
@@ -311,6 +339,18 @@ Add group with invalid interval to existing template, it should fail.
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Add group using too long template name in request, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_empty}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Add Template Group ${g_long_str} ${g_group1}[name] ${2000}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Add group with too long name to existing template, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_empty}
|
||||
Check Response Status ${res} 200
|
||||
@@ -346,6 +386,18 @@ Get groups from nonexistent template, it should fail.
|
||||
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NOT_FOUND}
|
||||
|
||||
|
||||
Get groups using too long name query parameter, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Get Template Groups ${g_long_str}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_PARAM_IS_WRONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Get groups when there are no groups, it should return empty result.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_empty}
|
||||
Check Response Status ${res} 200
|
||||
@@ -379,6 +431,30 @@ Update group interval when template does not exist, it should fail.
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Update group using too long template name in request, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Put Template Group ${g_long_str} ${g_group1}[name] ${2000}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Update group using too long group name in request, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Put Template Group ${g_template} ${g_long_str} ${2000}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_GROUP_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Update group interval when group does not exist, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_empty}
|
||||
Check Response Status ${res} 200
|
||||
@@ -438,6 +514,30 @@ Delete nonexistent group from existent template, it should fail.
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Delete group using too long template name in request, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Del Template Group ${g_long_str} ${g_group1}[name]
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Delete group using too long group name in request, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Del Template Group ${g_template} ${g_long_str}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_GROUP_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Delete group from existent template, it should success.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
@@ -526,6 +626,26 @@ Add tag with conflicting name to existing template group, it should fail.
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Add tag using too long template name in request, it should fail.
|
||||
Add Template And One Group ${g_template} ${g_plugin} ${g_group1}[name] ${g_group1}[interval]
|
||||
|
||||
${res} = Add Template Tags ${g_long_str} ${g_group1}[name] ${g_tag1}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Add tag using too long group name in request, it should fail.
|
||||
Add Template And One Group ${g_template} ${g_plugin} ${g_group1}[name] ${g_group1}[interval]
|
||||
|
||||
${res} = Add Template Tags ${g_template} ${g_long_str} ${g_tag1}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_GROUP_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Add tag with too long name to existing template group, it should fail.
|
||||
Add Template And One Group ${g_template} ${g_plugin} ${g_group1}[name] ${g_group1}[interval]
|
||||
|
||||
@@ -601,6 +721,30 @@ Get tags from nonexistent template group, it should fail.
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Get tags using too long template name query parameter, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Get Template Tags ${g_long_str} ${g_group1}[name]
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_PARAM_IS_WRONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Get tags using too long group name query parameter, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Get Template Tags ${g_template} ${g_long_str}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_PARAM_IS_WRONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Get tags when there are none from existent template group, it should return empty result.
|
||||
Add Template And One Group ${g_template} ${g_plugin} ${g_group1}[name] ${g_group1}[interval]
|
||||
|
||||
@@ -623,6 +767,18 @@ Get tags from existent template group, it should return the tags.
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Get tags using too long tag name query parameter, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Grep Template Tags ${g_template} ${g_group1}[name] ${g_long_str}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_PARAM_IS_WRONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Get tags by name pattern when there is no match, it should return empty result.
|
||||
Add Template And One Group ${g_template} ${g_plugin} ${g_group1}[name] ${g_group1}[interval]
|
||||
|
||||
@@ -688,6 +844,30 @@ Update tag when template tag does not exist, it should fail.
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Update tag using too long template name in request, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Put Template Tags ${g_long_str} ${g_group1}[name] ${g_tag1}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Update tag using too long group name in request, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Put Template Tags ${g_template} ${g_long_str} ${g_tag1}
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_GROUP_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Update tag name to invalid value, it should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
@@ -786,6 +966,42 @@ Delete tag when template tag does not exist, it trivially success.
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Delete tag using too long template name in request, it should should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Del Template Tags ${g_long_str} ${g_group1}[name] ${g_tag1}[name]
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Delete tag using too long group name in request, it should should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Del Template Tags ${g_template} ${g_long_str} ${g_tag1}[name]
|
||||
Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_GROUP_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Delete tag using too long tag name in request, it should should fail.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
Check Error Code ${res} ${NEU_ERR_SUCCESS}
|
||||
|
||||
${res} = Del Template Tags ${g_template} ${g_group1}[name] ${g_tag1}[name] ${g_long_str}
|
||||
#Check Response Status ${res} 400
|
||||
Check Error Code ${res} ${NEU_ERR_TAG_NAME_TOO_LONG}
|
||||
|
||||
[Teardown] Del Template ${g_template}
|
||||
|
||||
|
||||
Delete one tag, it should keep other tags untouched.
|
||||
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
|
||||
Check Response Status ${res} 200
|
||||
|
||||
@@ -257,8 +257,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 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
|
||||
* 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
|
||||
@@ -17,21 +17,9 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
#ifndef _NEU_M_PLUGIN_file_REQ_H_
|
||||
#define _NEU_M_PLUGIN_file_REQ_H_
|
||||
#ifndef NEURON_CONNECTION_SMART_LINK_H
|
||||
#define NEURON_CONNECTION_SMART_LINK_H
|
||||
|
||||
#include <neuron.h>
|
||||
|
||||
struct neu_plugin {
|
||||
neu_plugin_common_t common;
|
||||
|
||||
neu_events_t *events;
|
||||
|
||||
int file_length;
|
||||
};
|
||||
|
||||
int file_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group);
|
||||
int file_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value);
|
||||
int neu_conn_smart_link_auto_set(const char *dev_path);
|
||||
|
||||
#endif
|
||||
@@ -45,6 +45,10 @@ typedef enum {
|
||||
NEU_ERR_INVALID_PASSWORD_LEN = 1012,
|
||||
NEU_ERR_DUPLICATE_PASSWORD = 1013,
|
||||
NEU_ERR_COMMAND_EXECUTION_FAILED = 1014,
|
||||
NEU_ERR_IP_ADDRESS_INVALID = 1015,
|
||||
NEU_ERR_IP_ADDRESS_IN_USE = 1016,
|
||||
NEU_ERR_INVALID_USER = 1017,
|
||||
NEU_ERR_INVALID_PASSWORD = 1018,
|
||||
|
||||
NEU_ERR_NODE_EXIST = 2002,
|
||||
NEU_ERR_NODE_NOT_EXIST = 2003,
|
||||
@@ -59,6 +63,7 @@ typedef enum {
|
||||
NEU_ERR_NODE_NOT_ALLOW_SUBSCRIBE = 2012,
|
||||
NEU_ERR_NODE_NOT_ALLOW_UPDATE = 2013,
|
||||
NEU_ERR_NODE_NOT_ALLOW_MAP = 2014,
|
||||
NEU_ERR_NODE_NAME_EMPTY = 2015,
|
||||
|
||||
NEU_ERR_GROUP_ALREADY_SUBSCRIBED = 2101,
|
||||
NEU_ERR_GROUP_NOT_SUBSCRIBE = 2102,
|
||||
|
||||
@@ -100,6 +100,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.
|
||||
|
||||
@@ -95,7 +95,7 @@ inline static const char *neu_type_string(neu_type_e type)
|
||||
return "";
|
||||
}
|
||||
|
||||
#define NEU_VALUE_SIZE 512
|
||||
#define NEU_VALUE_SIZE 128
|
||||
typedef union {
|
||||
bool boolean;
|
||||
int8_t i8;
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* 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 default data-stream-processing node setting when
|
||||
-- the data-stream-processing node exists and is at init state.
|
||||
-- The init state implies the user has not provide any setting yet.
|
||||
INSERT INTO
|
||||
settings (node_name, setting)
|
||||
SELECT
|
||||
name,
|
||||
'{"params":{"host":"0.0.0.0","port":7081}}'
|
||||
FROM
|
||||
nodes
|
||||
WHERE
|
||||
name = 'data-stream-processing'
|
||||
and state = 1;
|
||||
|
||||
-- Update default data-stream-processing node to running state when
|
||||
-- the data-stream-processing node exists and is at init state.
|
||||
UPDATE
|
||||
nodes
|
||||
SET
|
||||
state = 3
|
||||
where
|
||||
name = 'data-stream-processing'
|
||||
and state = 1;
|
||||
|
||||
COMMIT;
|
||||
@@ -28,7 +28,7 @@ FROM nodes
|
||||
WHERE
|
||||
settings.node_name = nodes.name
|
||||
AND JSON_EXTRACT(json(setting), '$.params.transport_mode') IS NULL
|
||||
AND (nodes.plugin_name='modbus-qh-tcp' OR nodes.plugin_name='modbus-plus-tcp' OR nodes.plugin_name='modbus-rtu' OR nodes.plugin_name='modbus-tcp' OR nodes.plugin_name='Modbus TCP' OR nodes.plugin_name='Modbus RTU' OR nodes.plugin_name='Modbus TCP QH');
|
||||
AND (nodes.plugin_name='modbus-qh-tcp' OR nodes.plugin_name='modbus-plus-tcp' OR nodes.plugin_name='modbus-tcp' OR nodes.plugin_name='Modbus TCP' OR nodes.plugin_name='Modbus TCP QH');
|
||||
|
||||
UPDATE settings
|
||||
SET setting = JSON_SET(json(setting), '$.params.connection_mode', 0)
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
* 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;
|
||||
|
||||
-- default data-stream-processing node for neuronex
|
||||
INSERT
|
||||
OR REPLACE INTO nodes (name, type, state, plugin_name)
|
||||
VALUES
|
||||
('data-stream-processing', 2, 1, 'eKuiper');
|
||||
UPDATE nodes
|
||||
SET plugin_name = 'Mitsubishi FX'
|
||||
WHERE plugin_name = 'Mitsabishi FX';
|
||||
|
||||
COMMIT;
|
||||
COMMIT;
|
||||
@@ -17,6 +17,10 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "errcodes.h"
|
||||
#include "neuron.h"
|
||||
#include "utils/asprintf.h"
|
||||
@@ -99,6 +103,7 @@ static int ekuiper_plugin_uninit(neu_plugin_t *plugin)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
nng_close(plugin->sock);
|
||||
nng_aio_free(plugin->recv_aio);
|
||||
nng_mtx_free(plugin->mtx);
|
||||
free(plugin->host);
|
||||
@@ -127,7 +132,14 @@ static int ekuiper_plugin_start(neu_plugin_t *plugin)
|
||||
if ((rv = nng_listen(plugin->sock, url, NULL, 0)) != 0) {
|
||||
plog_error(plugin, "nng_listen: %s", nng_strerror(rv));
|
||||
nng_close(plugin->sock);
|
||||
return NEU_ERR_EINTERNAL;
|
||||
if (NNG_EADDRINVAL == rv) {
|
||||
rv = NEU_ERR_IP_ADDRESS_INVALID;
|
||||
} else if (NNG_EADDRINUSE == rv) {
|
||||
rv = NEU_ERR_IP_ADDRESS_IN_USE;
|
||||
} else {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nng_recv_aio(plugin->sock, plugin->recv_aio);
|
||||
@@ -163,6 +175,12 @@ static int parse_config(neu_plugin_t *plugin, const char *setting,
|
||||
goto error;
|
||||
}
|
||||
|
||||
struct in_addr addr;
|
||||
if (0 == inet_aton(host.v.val_str, &addr)) {
|
||||
plog_error(plugin, "inet_aton fail: %s", host.v.val_str);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// port, required
|
||||
if (0 == port.v.val_int || port.v.val_int > 65535) {
|
||||
plog_error(plugin, "setting invalid port: %" PRIi64, port.v.val_int);
|
||||
@@ -182,6 +200,41 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int check_url_listenable(neu_plugin_t *plugin, const char *url,
|
||||
const char *host, uint16_t port)
|
||||
{
|
||||
if (NULL != plugin->host && // already configured and
|
||||
port == plugin->port && // port is the same, then if
|
||||
(0 == strcmp(plugin->host, host) // 1. host is the same
|
||||
|| 0 == strcmp("0.0.0.0", host) // 2. to bind to any address
|
||||
|| 0 == strcmp("0.0.0.0", plugin->host) // 3. bound to any address
|
||||
)) {
|
||||
// early return, no need check url is listenable
|
||||
return 0;
|
||||
}
|
||||
|
||||
nng_socket sock = NNG_SOCKET_INITIALIZER;
|
||||
int rv = nng_pair0_open(&sock);
|
||||
if (0 != rv) {
|
||||
plog_error(plugin, "nng_pair0_open: %s", nng_strerror(rv));
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
if (0 != (rv = nng_listen(sock, url, NULL, 0))) {
|
||||
plog_error(plugin, "nng_listen: %s", nng_strerror(rv));
|
||||
if (NNG_EADDRINVAL == rv) {
|
||||
rv = NEU_ERR_IP_ADDRESS_INVALID;
|
||||
} else if (NNG_EADDRINUSE == rv) {
|
||||
rv = NEU_ERR_IP_ADDRESS_IN_USE;
|
||||
} else {
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
nng_close(sock);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ekuiper_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
{
|
||||
int rv = 0;
|
||||
@@ -201,6 +254,10 @@ static int ekuiper_plugin_config(neu_plugin_t *plugin, const char *setting)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (0 != (rv = check_url_listenable(plugin, url, host, port))) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
plog_notice(plugin, "config success");
|
||||
|
||||
free(plugin->host);
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/plugins")
|
||||
|
||||
set(CMAKE_BUILD_RPATH ./)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/plugins/file/file.json DESTINATION ${CMAKE_BINARY_DIR}/plugins/schema/)
|
||||
|
||||
set(PLUGIN_NAME plugin-file)
|
||||
set(PLUGIN_SOURCES file_plugin.c file_req.c)
|
||||
add_library(${PLUGIN_NAME} SHARED)
|
||||
target_include_directories(${PLUGIN_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include/neuron)
|
||||
target_sources(${PLUGIN_NAME} PRIVATE ${PLUGIN_SOURCES})
|
||||
target_link_libraries(${PLUGIN_NAME} neuron-base)
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"tag_regex": [
|
||||
{
|
||||
"type": 13,
|
||||
"regex": ""
|
||||
}
|
||||
],
|
||||
"group_interval": 1000,
|
||||
"file_length": {
|
||||
"name": "File Max Length",
|
||||
"name_zh": "文件最大长度",
|
||||
"description": "",
|
||||
"description_zh": "",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 512,
|
||||
"valid": {
|
||||
"min": 1,
|
||||
"max": 512
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,173 +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 "file_req.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_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group);
|
||||
static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag);
|
||||
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 = "file",
|
||||
.module_name = "File",
|
||||
.module_descr = "The plugin is used to read and write files.",
|
||||
.module_descr_zh = "该插件用于读写文件。",
|
||||
.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)
|
||||
{
|
||||
plog_notice(plugin, "close and free `%s` plugin success",
|
||||
plugin->common.name);
|
||||
|
||||
free(plugin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_init(neu_plugin_t *plugin)
|
||||
{
|
||||
plugin->events = neu_event_new();
|
||||
|
||||
plog_notice(plugin, "initialize `%s` plugin success", plugin->common.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_uninit(neu_plugin_t *plugin)
|
||||
{
|
||||
neu_event_close(plugin->events);
|
||||
|
||||
plog_notice(plugin, "uninitialize `%s` plugin success",
|
||||
plugin->common.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_start(neu_plugin_t *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)
|
||||
{
|
||||
plugin->common.link_state = NEU_NODE_LINK_STATE_DISCONNECTED;
|
||||
|
||||
plog_notice(plugin, "stop `%s` plugin success", plugin->common.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
{
|
||||
char * err_param = NULL;
|
||||
neu_json_elem_t file_length = { .name = "file_length", .t = NEU_JSON_INT };
|
||||
|
||||
int ret = neu_parse_param((char *) config, &err_param, 1, &file_length);
|
||||
if (ret != 0) {
|
||||
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->common.link_state = NEU_NODE_LINK_STATE_CONNECTED;
|
||||
|
||||
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)
|
||||
{
|
||||
plog_notice(plugin, "validate tag success, name:%s, address:%s, type:%d ",
|
||||
tag->name, tag->address, tag->type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
|
||||
{
|
||||
return file_group_timer(plugin, group);
|
||||
}
|
||||
|
||||
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value)
|
||||
{
|
||||
int ret = file_write(plugin, req, tag, value);
|
||||
|
||||
plog_notice(plugin,
|
||||
"write response, ret: %d, tag_name: %s, type: %d, address: %s",
|
||||
ret, tag->name, tag->type, tag->address);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,165 +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 <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "file_req.h"
|
||||
|
||||
struct file_group_data {
|
||||
UT_array *tags;
|
||||
char * group;
|
||||
};
|
||||
|
||||
static void plugin_group_free(neu_plugin_group_t *pgp);
|
||||
|
||||
int file_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
|
||||
{
|
||||
neu_adapter_update_metric_cb_t update_metric =
|
||||
plugin->common.adapter_callbacks->update_metric;
|
||||
int64_t rtt = NEU_METRIC_LAST_RTT_MS_MAX;
|
||||
|
||||
struct file_group_data *gd = NULL;
|
||||
int length = plugin->file_length;
|
||||
|
||||
if (group->user_data == NULL) {
|
||||
gd = calloc(1, sizeof(struct file_group_data));
|
||||
group->user_data = gd;
|
||||
group->group_free = plugin_group_free;
|
||||
utarray_new(gd->tags, &ut_ptr_icd);
|
||||
|
||||
gd->group = strdup(group->group_name);
|
||||
}
|
||||
|
||||
utarray_foreach(group->tags, neu_datatag_t *, tag)
|
||||
{
|
||||
FILE * f = NULL;
|
||||
struct stat st = { 0 };
|
||||
char * buf = calloc(1, length);
|
||||
neu_dvalue_t dvalue = { 0 };
|
||||
|
||||
if (stat(tag->address, &st) != 0) {
|
||||
dvalue.type = NEU_TYPE_ERROR;
|
||||
dvalue.value.i32 = NEU_ERR_FILE_NOT_EXIST;
|
||||
goto dvalue_result;
|
||||
}
|
||||
|
||||
if ((f = fopen(tag->address, "rb+")) == NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
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_STRING_TOO_LONG;
|
||||
|
||||
fclose(f);
|
||||
goto dvalue_result;
|
||||
}
|
||||
|
||||
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_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));
|
||||
rtt = 1;
|
||||
fclose(f);
|
||||
|
||||
dvalue_result:
|
||||
plugin->common.adapter_callbacks->driver.update(
|
||||
plugin->common.adapter, group->group_name, tag->name, dvalue);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
update_metric(plugin->common.adapter, NEU_METRIC_LAST_RTT_MS, rtt, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void plugin_group_free(neu_plugin_group_t *pgp)
|
||||
{
|
||||
struct file_group_data *gd = (struct file_group_data *) pgp->user_data;
|
||||
|
||||
utarray_foreach(gd->tags, neu_datatag_t **, tag) { free(*tag); }
|
||||
|
||||
utarray_free(gd->tags);
|
||||
free(gd->group);
|
||||
|
||||
free(gd);
|
||||
}
|
||||
|
||||
int file_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value)
|
||||
{
|
||||
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;
|
||||
|
||||
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:
|
||||
plugin->common.adapter_callbacks->driver.write_response(
|
||||
plugin->common.adapter, req, ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -5,7 +5,6 @@ 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/)
|
||||
# modbus rtu plugin
|
||||
set(MODBUS_RTU_PLUGIN plugin-modbus-rtu)
|
||||
set(MODBUS_RTU_PLUGIN_SOURCES modbus_rtu.c
|
||||
@@ -24,12 +23,3 @@ target_include_directories(${MODBUS_TCP_PLUS_PLUGIN} PRIVATE ${CMAKE_SOURCE_DIR}
|
||||
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)
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,31 +327,6 @@
|
||||
"value": 1
|
||||
}
|
||||
},
|
||||
"transport_mode": {
|
||||
"name": "Transport Mode",
|
||||
"name_zh": "传输模式",
|
||||
"description": "TCP transfer or UDP transfer",
|
||||
"description_zh": "TCP 传输或 UDP 传输",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "TCP",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "UDP",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"condition": {
|
||||
"field": "link",
|
||||
"value": 1
|
||||
}
|
||||
},
|
||||
"connection_mode": {
|
||||
"name": "Connection Mode",
|
||||
"name_zh": "连接模式",
|
||||
@@ -375,10 +350,6 @@
|
||||
"condition": {
|
||||
"field": "link",
|
||||
"value": 1
|
||||
},
|
||||
"condition": {
|
||||
"field": "transport_mode",
|
||||
"value": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-8
@@ -40,14 +40,23 @@ typedef enum modbus_action {
|
||||
} modbus_action_e;
|
||||
|
||||
typedef enum modbus_function {
|
||||
MODBUS_READ_COIL = 0x1,
|
||||
MODBUS_READ_INPUT = 0x02,
|
||||
MODBUS_READ_HOLD_REG = 0x03,
|
||||
MODBUS_READ_INPUT_REG = 0x04,
|
||||
MODBUS_WRITE_S_COIL = 0x05,
|
||||
MODBUS_WRITE_S_HOLD_REG = 0x06,
|
||||
MODBUS_WRITE_M_HOLD_REG = 0x10,
|
||||
MODBUS_WRITE_M_COIL = 0x0F
|
||||
MODBUS_READ_COIL = 0x1,
|
||||
MODBUS_READ_INPUT = 0x02,
|
||||
MODBUS_READ_HOLD_REG = 0x03,
|
||||
MODBUS_READ_INPUT_REG = 0x04,
|
||||
MODBUS_WRITE_S_COIL = 0x05,
|
||||
MODBUS_WRITE_S_HOLD_REG = 0x06,
|
||||
MODBUS_WRITE_M_HOLD_REG = 0x10,
|
||||
MODBUS_WRITE_M_COIL = 0x0F,
|
||||
MODBUS_READ_COIL_ERR = 0x81,
|
||||
MODBUS_READ_INPUT_ERR = 0x82,
|
||||
MODBUS_READ_HOLD_REG_ERR = 0x83,
|
||||
MODBUS_READ_INPUT_REG_ERR = 0x84,
|
||||
MODBUS_WRITE_S_COIL_ERR = 0x85,
|
||||
MODBUS_WRITE_S_HOLD_REG_ERR = 0x86,
|
||||
MODBUS_WRITE_M_HOLD_REG_ERR = 0x90,
|
||||
MODBUS_WRITE_M_COIL_ERR = 0x8F,
|
||||
MODBUS_DEVICE_ERR = -2
|
||||
} modbus_function_e;
|
||||
|
||||
typedef enum modbus_area {
|
||||
|
||||
@@ -1,245 +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_tag_validator(const neu_datatag_t *tag);
|
||||
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,
|
||||
.driver.tag_validator = driver_tag_validator,
|
||||
.driver.write_tags = NULL,
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (plugin->stack) {
|
||||
modbus_stack_destroy(plugin->stack);
|
||||
}
|
||||
|
||||
neu_event_close(plugin->events);
|
||||
|
||||
plog_notice(plugin, "%s uninit success", plugin->common.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_error(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_notice(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_tag_validator(const neu_datatag_t *tag)
|
||||
{
|
||||
modbus_point_t point = { 0 };
|
||||
return modbus_tag_to_point(tag, &point);
|
||||
}
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
+223
-33
@@ -30,7 +30,8 @@ struct modbus_group_data {
|
||||
};
|
||||
|
||||
static void plugin_group_free(neu_plugin_group_t *pgp);
|
||||
static int process_protocol_buf(neu_plugin_t *plugin, uint16_t response_size);
|
||||
static int process_protocol_buf(neu_plugin_t *plugin, uint8_t slave_id,
|
||||
uint16_t response_size);
|
||||
|
||||
void modbus_conn_connected(void *data, int fd)
|
||||
{
|
||||
@@ -162,29 +163,137 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
|
||||
plugin->cmd_idx = i;
|
||||
uint16_t response_size = 0;
|
||||
uint64_t read_tms = neu_time_ms();
|
||||
|
||||
int ret = modbus_stack_read(
|
||||
int ret_buf = 0;
|
||||
int ret_r = 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) {
|
||||
if (ret_r > 0) {
|
||||
ret_buf = process_protocol_buf(
|
||||
plugin, gd->cmd_sort->cmd[i].slave_id, response_size);
|
||||
if (ret_buf > 0) {
|
||||
rtt = neu_time_ms() - read_tms;
|
||||
} else if (ret_buf == 0) {
|
||||
for (uint16_t j = 0; j < plugin->max_retries; j++) {
|
||||
ret_r = modbus_stack_read_retry(plugin, gd, i, j,
|
||||
&response_size);
|
||||
if (ret_r > 0) {
|
||||
ret_buf = process_protocol_buf(
|
||||
plugin, gd->cmd_sort->cmd[i].slave_id,
|
||||
response_size);
|
||||
if (ret_buf > 0) {
|
||||
rtt = neu_time_ms() - read_tms;
|
||||
break;
|
||||
} else if (ret_buf < 0) {
|
||||
if (ret_buf == -1) {
|
||||
modbus_value_handle(
|
||||
plugin, gd->cmd_sort->cmd[i].slave_id, 0,
|
||||
NULL,
|
||||
NEU_ERR_PLUGIN_PROTOCOL_DECODE_FAILURE);
|
||||
plog_error(
|
||||
plugin,
|
||||
"modbus message error, skip, %hhu!%hu",
|
||||
gd->cmd_sort->cmd[i].slave_id,
|
||||
gd->cmd_sort->cmd[i].start_address);
|
||||
} else if (ret_buf == -2) {
|
||||
modbus_value_handle(
|
||||
plugin, gd->cmd_sort->cmd[i].slave_id, 0,
|
||||
NULL, NEU_ERR_PLUGIN_READ_FAILURE);
|
||||
plog_error(
|
||||
plugin,
|
||||
"modbus device response error, skip, "
|
||||
"%hhu!%hu",
|
||||
gd->cmd_sort->cmd[i].slave_id,
|
||||
gd->cmd_sort->cmd[i].start_address);
|
||||
}
|
||||
rtt = neu_time_ms() - read_tms;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
modbus_value_handle(plugin,
|
||||
gd->cmd_sort->cmd[i].slave_id, 0,
|
||||
NULL, NEU_ERR_PLUGIN_DISCONNECTED);
|
||||
rtt = NEU_METRIC_LAST_RTT_MS_MAX;
|
||||
neu_conn_disconnect(plugin->conn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret_r > 0 && ret_buf == 0) {
|
||||
modbus_value_handle(plugin, gd->cmd_sort->cmd[i].slave_id,
|
||||
0, NULL,
|
||||
NEU_ERR_PLUGIN_DEVICE_NOT_RESPONSE);
|
||||
plog_warn(plugin,
|
||||
"no modbus response received, skip, %hhu!%hu",
|
||||
gd->cmd_sort->cmd[i].slave_id,
|
||||
gd->cmd_sort->cmd[i].start_address);
|
||||
}
|
||||
} else if (ret_buf < 0) {
|
||||
if (ret_buf == -1) {
|
||||
modbus_value_handle(plugin, gd->cmd_sort->cmd[i].slave_id,
|
||||
0, NULL,
|
||||
NEU_ERR_PLUGIN_PROTOCOL_DECODE_FAILURE);
|
||||
plog_error(plugin, "modbus message error, skip, %hhu!%hu",
|
||||
gd->cmd_sort->cmd[i].slave_id,
|
||||
gd->cmd_sort->cmd[i].start_address);
|
||||
} else if (ret_buf == -2) {
|
||||
modbus_value_handle(plugin, gd->cmd_sort->cmd[i].slave_id,
|
||||
0, NULL, NEU_ERR_PLUGIN_READ_FAILURE);
|
||||
plog_error(plugin,
|
||||
"modbus device response error, skip, %hhu!%hu",
|
||||
gd->cmd_sort->cmd[i].slave_id,
|
||||
gd->cmd_sort->cmd[i].start_address);
|
||||
}
|
||||
rtt = neu_time_ms() - read_tms;
|
||||
}
|
||||
} else {
|
||||
for (uint16_t j = 0; j < plugin->max_retries; j++) {
|
||||
ret = modbus_stack_read_retry(plugin, gd, i, j, &response_size);
|
||||
if (ret > 0) {
|
||||
ret = process_protocol_buf(plugin, response_size);
|
||||
rtt = neu_time_ms() - read_tms;
|
||||
break;
|
||||
ret_r =
|
||||
modbus_stack_read_retry(plugin, gd, i, j, &response_size);
|
||||
if (ret_r > 0) {
|
||||
ret_buf = process_protocol_buf(
|
||||
plugin, gd->cmd_sort->cmd[i].slave_id, response_size);
|
||||
if (ret_buf > 0) {
|
||||
rtt = neu_time_ms() - read_tms;
|
||||
break;
|
||||
} else if (ret_buf < 0) {
|
||||
if (ret_buf == -1) {
|
||||
modbus_value_handle(
|
||||
plugin, gd->cmd_sort->cmd[i].slave_id, 0, NULL,
|
||||
NEU_ERR_PLUGIN_PROTOCOL_DECODE_FAILURE);
|
||||
plog_error(plugin,
|
||||
"modbus message error, skip, %hhu!%hu",
|
||||
gd->cmd_sort->cmd[i].slave_id,
|
||||
gd->cmd_sort->cmd[i].start_address);
|
||||
} else if (ret_buf == -2) {
|
||||
modbus_value_handle(
|
||||
plugin, gd->cmd_sort->cmd[i].slave_id, 0, NULL,
|
||||
NEU_ERR_PLUGIN_READ_FAILURE);
|
||||
plog_error(plugin,
|
||||
"modbus device response error, skip, "
|
||||
"%hhu!%hu",
|
||||
gd->cmd_sort->cmd[i].slave_id,
|
||||
gd->cmd_sort->cmd[i].start_address);
|
||||
}
|
||||
rtt = neu_time_ms() - read_tms;
|
||||
break;
|
||||
} else if (ret_buf == 0) {
|
||||
modbus_value_handle(
|
||||
plugin, gd->cmd_sort->cmd[i].slave_id, 0, NULL,
|
||||
NEU_ERR_PLUGIN_DEVICE_NOT_RESPONSE);
|
||||
plog_warn(plugin,
|
||||
"no modbus response received, skip, %hhu!%hu",
|
||||
gd->cmd_sort->cmd[i].slave_id,
|
||||
gd->cmd_sort->cmd[i].start_address);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret <= 0) {
|
||||
if (ret_r <= 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;
|
||||
neu_conn_disconnect(plugin->conn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (plugin->interval > 0) {
|
||||
@@ -216,7 +325,7 @@ 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 (error == NEU_ERR_PLUGIN_DISCONNECTED) {
|
||||
neu_dvalue_t dvalue = { 0 };
|
||||
|
||||
dvalue.type = NEU_TYPE_ERROR;
|
||||
@@ -224,6 +333,17 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
plugin->common.adapter_callbacks->driver.update(
|
||||
plugin->common.adapter, gd->group, NULL, dvalue);
|
||||
return 0;
|
||||
} else if (error != NEU_ERR_SUCCESS) {
|
||||
utarray_foreach(gd->cmd_sort->cmd[plugin->cmd_idx].tags,
|
||||
modbus_point_t **, p_tag)
|
||||
{
|
||||
neu_dvalue_t dvalue = { 0 };
|
||||
dvalue.type = NEU_TYPE_ERROR;
|
||||
dvalue.value.i32 = error;
|
||||
plugin->common.adapter_callbacks->driver.update(
|
||||
plugin->common.adapter, gd->group, (*p_tag)->name, dvalue);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
utarray_foreach(gd->cmd_sort->cmd[plugin->cmd_idx].tags, modbus_point_t **,
|
||||
@@ -380,7 +500,7 @@ int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
point.start_address, point.n_register, value.bytes,
|
||||
n_byte, &response_size);
|
||||
if (ret > 0) {
|
||||
process_protocol_buf(plugin, response_size);
|
||||
process_protocol_buf(plugin, point.slave_id, response_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -409,29 +529,99 @@ static void plugin_group_free(neu_plugin_group_t *pgp)
|
||||
free(gd);
|
||||
}
|
||||
|
||||
static int process_protocol_buf(neu_plugin_t *plugin, uint16_t response_size)
|
||||
static int process_protocol_buf(neu_plugin_t *plugin, uint8_t slave_id,
|
||||
uint16_t response_size)
|
||||
{
|
||||
uint8_t * recv_buf = calloc(response_size, 1);
|
||||
neu_protocol_unpack_buf_t pbuf = { 0 };
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (plugin->is_server && plugin->protocol == MODBUS_PROTOCOL_TCP) {
|
||||
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 == response_size) {
|
||||
if (response_size < 512) {
|
||||
plog_recv_protocol(plugin, recv_buf, ret);
|
||||
if (plugin->protocol == MODBUS_PROTOCOL_TCP) {
|
||||
if (plugin->is_server) {
|
||||
ret = neu_conn_tcp_server_recv(plugin->conn, plugin->client_fd,
|
||||
recv_buf,
|
||||
sizeof(struct modbus_header));
|
||||
} else {
|
||||
ret = neu_conn_recv(plugin->conn, recv_buf,
|
||||
sizeof(struct modbus_header));
|
||||
}
|
||||
neu_protocol_unpack_buf_init(&pbuf, recv_buf, ret);
|
||||
ret = modbus_stack_recv(plugin->stack, &pbuf);
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (ret == 0 || ret == -1) {
|
||||
free(recv_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret == sizeof(struct modbus_header)) {
|
||||
struct modbus_header *header = (struct modbus_header *) recv_buf;
|
||||
int ret1 = 0;
|
||||
|
||||
if (htons(header->len) >
|
||||
response_size - sizeof(struct modbus_header)) {
|
||||
free(recv_buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
plog_recv_protocol(plugin, recv_buf, ret);
|
||||
if (plugin->is_server) {
|
||||
ret1 = neu_conn_tcp_server_recv(
|
||||
plugin->conn, plugin->client_fd,
|
||||
recv_buf + sizeof(struct modbus_header),
|
||||
htons(header->len));
|
||||
} else {
|
||||
ret1 = neu_conn_recv(plugin->conn,
|
||||
recv_buf + sizeof(struct modbus_header),
|
||||
htons(header->len));
|
||||
}
|
||||
if (ret1 != htons(header->len)) {
|
||||
free(recv_buf);
|
||||
return -1;
|
||||
}
|
||||
ret += ret1;
|
||||
} else {
|
||||
free(recv_buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
if (ret < 512) {
|
||||
plog_recv_protocol(plugin, recv_buf, ret);
|
||||
}
|
||||
neu_protocol_unpack_buf_init(&pbuf, recv_buf, ret);
|
||||
int ret_s = modbus_stack_recv(plugin->stack, slave_id, &pbuf);
|
||||
if (ret_s == MODBUS_DEVICE_ERR) {
|
||||
ret = ret_s;
|
||||
} else {
|
||||
if (ret != response_size) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = ret_s;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (plugin->protocol == MODBUS_PROTOCOL_RTU) {
|
||||
ret = neu_conn_recv(plugin->conn, recv_buf, response_size);
|
||||
|
||||
if (ret == 0 || ret == -1) {
|
||||
free(recv_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
if (response_size < 512) {
|
||||
plog_recv_protocol(plugin, recv_buf, ret);
|
||||
}
|
||||
neu_protocol_unpack_buf_init(&pbuf, recv_buf, ret);
|
||||
int ret_s = modbus_stack_recv(plugin->stack, 0, &pbuf);
|
||||
if (ret_s == MODBUS_DEVICE_ERR) {
|
||||
ret = ret_s;
|
||||
} else {
|
||||
if (ret != response_size) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = ret_s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(recv_buf);
|
||||
return ret;
|
||||
}
|
||||
+25
-35
@@ -66,11 +66,11 @@ const neu_plugin_module_t neu_plugin_module = {
|
||||
.module_name = "Modbus RTU",
|
||||
.module_descr =
|
||||
"This plugin is used to connect devices using modbus rtu protocol. "
|
||||
"Support serial,TCP and UDP communication methods. Selecting "
|
||||
"Support serial and TCP communication methods. Selecting "
|
||||
"client/server is also supported.",
|
||||
.module_descr_zh =
|
||||
"该插件用于连接使用 modbus rtu 协议的设备。支持串口, TCP 和 UDP "
|
||||
"三种通信方式。也支持选择客户端/服务端。",
|
||||
"该插件用于连接使用 modbus rtu 协议的设备。支持串口, TCP "
|
||||
"两种通信方式。也支持选择客户端/服务端。",
|
||||
.intf_funs = &plugin_intf_funs,
|
||||
.kind = NEU_PLUGIN_KIND_SYSTEM,
|
||||
.type = NEU_NA_TYPE_DRIVER,
|
||||
@@ -148,10 +148,9 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
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 tmode = { .name = "transport_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 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 };
|
||||
@@ -184,8 +183,8 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
ret = neu_parse_param((char *) config, &err_param, 5, &device, &stop,
|
||||
&parity, &baud, &data);
|
||||
} else {
|
||||
ret = neu_parse_param((char *) config, &err_param, 4, &mode, &host,
|
||||
&port, &tmode);
|
||||
ret = neu_parse_param((char *) config, &err_param, 3, &mode, &host,
|
||||
&port);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
@@ -223,33 +222,24 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
device.v.val_str, baud.v.val_int, data.v.val_int,
|
||||
parity.v.val_int, stop.v.val_int);
|
||||
} else {
|
||||
if (tmode.v.val_int == 1) {
|
||||
param.type = NEU_CONN_UDP;
|
||||
param.params.udp.timeout = 3000;
|
||||
param.params.udp.src_ip = "0.0.0.0";
|
||||
param.params.udp.src_port = 0;
|
||||
param.params.udp.dst_ip = host.v.val_str;
|
||||
param.params.udp.dst_port = port.v.val_int;
|
||||
plugin->is_server = false;
|
||||
} 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;
|
||||
}
|
||||
if (mode.v.val_int == 0) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (mode.v.val_int == 0) {
|
||||
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_notice(plugin,
|
||||
"config: host: %s, port: %" PRId64 ", mode: %" PRId64 "",
|
||||
host.v.val_str, port.v.val_int, mode.v.val_int);
|
||||
|
||||
@@ -62,7 +62,8 @@ void modbus_stack_destroy(modbus_stack_t *stack)
|
||||
free(stack);
|
||||
}
|
||||
|
||||
int modbus_stack_recv(modbus_stack_t *stack, neu_protocol_unpack_buf_t *buf)
|
||||
int modbus_stack_recv(modbus_stack_t *stack, uint8_t slave_id,
|
||||
neu_protocol_unpack_buf_t *buf)
|
||||
{
|
||||
struct modbus_header header = { 0 };
|
||||
struct modbus_code code = { 0 };
|
||||
@@ -74,13 +75,19 @@ int modbus_stack_recv(modbus_stack_t *stack, neu_protocol_unpack_buf_t *buf)
|
||||
plog_warn((neu_plugin_t *) stack->ctx, "try modbus rtu driver");
|
||||
}
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ret = modbus_code_unwrap(buf, &code);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_TCP) {
|
||||
if (code.slave_id != slave_id) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (code.function) {
|
||||
@@ -92,7 +99,7 @@ int modbus_stack_recv(modbus_stack_t *stack, neu_protocol_unpack_buf_t *buf)
|
||||
uint8_t * bytes = NULL;
|
||||
ret = modbus_data_unwrap(buf, &data);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_TCP && data.n_byte == 0xff) {
|
||||
@@ -116,18 +123,38 @@ int modbus_stack_recv(modbus_stack_t *stack, neu_protocol_unpack_buf_t *buf)
|
||||
case MODBUS_WRITE_M_COIL: {
|
||||
struct modbus_address address = { 0 };
|
||||
ret = modbus_address_unwrap(buf, &address);
|
||||
if (ret <= 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MODBUS_READ_COIL_ERR:
|
||||
return MODBUS_DEVICE_ERR;
|
||||
case MODBUS_READ_INPUT_ERR:
|
||||
return MODBUS_DEVICE_ERR;
|
||||
case MODBUS_READ_HOLD_REG_ERR:
|
||||
return MODBUS_DEVICE_ERR;
|
||||
case MODBUS_READ_INPUT_REG_ERR:
|
||||
return MODBUS_DEVICE_ERR;
|
||||
case MODBUS_WRITE_S_COIL_ERR:
|
||||
return MODBUS_DEVICE_ERR;
|
||||
case MODBUS_WRITE_S_HOLD_REG_ERR:
|
||||
return MODBUS_DEVICE_ERR;
|
||||
case MODBUS_WRITE_M_HOLD_REG_ERR:
|
||||
return MODBUS_DEVICE_ERR;
|
||||
case MODBUS_WRITE_M_COIL_ERR:
|
||||
return MODBUS_DEVICE_ERR;
|
||||
case MODBUS_WRITE_S_HOLD_REG:
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_RTU) {
|
||||
struct modbus_crc crc = { 0 };
|
||||
ret = modbus_crc_unwrap(buf, &crc);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,10 +165,11 @@ 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)
|
||||
{
|
||||
static __thread uint8_t buf[16] = { 0 };
|
||||
static __thread neu_protocol_pack_buf_t pbuf = { 0 };
|
||||
int ret = 0;
|
||||
modbus_action_e m_action = MODBUS_ACTION_DEFAULT;
|
||||
static __thread uint8_t buf[16] = { 0 };
|
||||
static __thread neu_protocol_pack_buf_t pbuf = { 0 };
|
||||
int ret = 0;
|
||||
*response_size = 0;
|
||||
modbus_action_e m_action = MODBUS_ACTION_DEFAULT;
|
||||
|
||||
neu_protocol_pack_buf_init(&pbuf, buf, sizeof(buf));
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ modbus_stack_t *modbus_stack_create(void *ctx, modbus_protocol_e protocol,
|
||||
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_recv(modbus_stack_t *stack, uint8_t slave_id,
|
||||
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,
|
||||
|
||||
@@ -62,26 +62,47 @@ void handle_add_adapter(nng_aio *aio)
|
||||
})
|
||||
}
|
||||
|
||||
void handle_update_adapter(nng_aio *aio)
|
||||
static inline int send_node_update_req(nng_aio * aio,
|
||||
neu_json_update_node_req_t *req)
|
||||
{
|
||||
neu_plugin_t *plugin = neu_rest_get_plugin();
|
||||
|
||||
int len = strlen(req->name);
|
||||
if (NEU_NODE_NAME_LEN <= len) {
|
||||
return NEU_ERR_NODE_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
len = strlen(req->new_name);
|
||||
if (NEU_NODE_NAME_LEN <= len) {
|
||||
return NEU_ERR_NODE_NAME_TOO_LONG;
|
||||
} else if (0 == len) {
|
||||
return NEU_ERR_NODE_NAME_EMPTY;
|
||||
}
|
||||
|
||||
neu_req_update_node_t cmd = { 0 };
|
||||
strcpy(cmd.node, req->name);
|
||||
strcpy(cmd.new_name, req->new_name);
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.ctx = aio,
|
||||
.type = NEU_REQ_UPDATE_NODE,
|
||||
};
|
||||
|
||||
if (0 != neu_plugin_op(plugin, header, &cmd)) {
|
||||
return NEU_ERR_IS_BUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void handle_update_adapter(nng_aio *aio)
|
||||
{
|
||||
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
|
||||
aio, neu_json_update_node_req_t, neu_json_decode_update_node_req, {
|
||||
int ret = 0;
|
||||
neu_reqresp_head_t header = { 0 };
|
||||
neu_req_update_node_t cmd = { 0 };
|
||||
|
||||
header.ctx = aio;
|
||||
header.type = NEU_REQ_UPDATE_NODE;
|
||||
strcpy(cmd.node, req->name);
|
||||
strcpy(cmd.new_name, req->new_name);
|
||||
|
||||
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);
|
||||
});
|
||||
int ret = send_node_update_req(aio, req);
|
||||
if (0 != ret) {
|
||||
NEU_JSON_RESPONSE_ERROR(
|
||||
ret, { neu_http_response(aio, ret, result_error); });
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -152,12 +152,6 @@ static struct neu_http_handler rest_handlers[] = {
|
||||
.url = "/",
|
||||
.value.path = "/web",
|
||||
},
|
||||
{
|
||||
.method = NEU_HTTP_METHOD_UNDEFINE,
|
||||
.type = NEU_HTTP_HANDLER_PROXY,
|
||||
.url = "/api/v2/ekuiper",
|
||||
.value.dst_url = "http://127.0.0.1:9081",
|
||||
},
|
||||
{
|
||||
.method = NEU_HTTP_METHOD_POST,
|
||||
.type = NEU_HTTP_HANDLER_FUNCTION,
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -58,7 +58,7 @@ void handle_login(nng_aio *aio)
|
||||
|
||||
if (NULL == user) {
|
||||
nlog_error("could not find user `%s`", req->name);
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_OR_PASSWORD, {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER, {
|
||||
neu_http_response(aio, error_code.error, result_error);
|
||||
});
|
||||
} else if (pass_len < NEU_USER_PASSWORD_MIN_LEN ||
|
||||
@@ -90,7 +90,7 @@ void handle_login(nng_aio *aio)
|
||||
free(result);
|
||||
} else {
|
||||
nlog_error("user `%s` password check fail", req->name);
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_USER_OR_PASSWORD, {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_PASSWORD, {
|
||||
neu_http_response(aio, error_code.error, result_error);
|
||||
});
|
||||
}
|
||||
@@ -114,10 +114,10 @@ void handle_password(nng_aio *aio)
|
||||
rv = NEU_ERR_INVALID_PASSWORD_LEN;
|
||||
} else if (NULL == (user = neu_load_user(req->name))) {
|
||||
nlog_error("could not find user `%s`", req->name);
|
||||
rv = NEU_ERR_INVALID_USER_OR_PASSWORD;
|
||||
rv = NEU_ERR_INVALID_USER;
|
||||
} else if (!neu_user_check_password(user, req->old_pass)) {
|
||||
nlog_error("user `%s` password check fail", req->name);
|
||||
rv = NEU_ERR_INVALID_USER_OR_PASSWORD;
|
||||
rv = NEU_ERR_INVALID_PASSWORD;
|
||||
} else if (0 !=
|
||||
(rv = neu_user_update_password(user, req->new_pass))) {
|
||||
nlog_error("user `%s` update password fail", req->name);
|
||||
|
||||
@@ -170,15 +170,22 @@ void handle_del_template(nng_aio *aio)
|
||||
|
||||
NEU_VALIDATE_JWT(aio);
|
||||
|
||||
neu_req_del_template_t cmd = { 0 };
|
||||
|
||||
int ret = neu_http_get_param_str(aio, "name", cmd.name, sizeof(cmd.name));
|
||||
// optional parameter
|
||||
if (-2 != ret && (ret <= 0 || sizeof(cmd.name) <= (size_t) ret)) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_PARAM_IS_WRONG, {
|
||||
neu_http_response(aio, NEU_ERR_PARAM_IS_WRONG, result_error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.ctx = aio,
|
||||
.type = NEU_REQ_DEL_TEMPLATE,
|
||||
};
|
||||
|
||||
neu_req_del_template_t cmd = { 0 };
|
||||
|
||||
neu_http_get_param_str(aio, "name", cmd.name, sizeof(cmd.name));
|
||||
|
||||
if (0 != neu_plugin_op(plugin, header, &cmd)) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
|
||||
neu_http_response(aio, NEU_ERR_IS_BUSY, result_error);
|
||||
@@ -197,10 +204,19 @@ void handle_get_template(nng_aio *aio)
|
||||
};
|
||||
neu_req_get_template_t cmd = { 0 };
|
||||
|
||||
if (neu_http_get_param_str(aio, "name", cmd.name, sizeof(cmd.name)) <= 0) {
|
||||
int ret = neu_http_get_param_str(aio, "name", cmd.name, sizeof(cmd.name));
|
||||
if (0 < ret && (size_t) ret < sizeof(cmd.name)) {
|
||||
// valid name parameter provided
|
||||
header.type = NEU_REQ_GET_TEMPLATE;
|
||||
} else if (-2 == ret) {
|
||||
// no name parameter
|
||||
header.type = NEU_REQ_GET_TEMPLATES;
|
||||
} else {
|
||||
header.type = NEU_REQ_GET_TEMPLATE;
|
||||
// invalid name parameter
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_PARAM_IS_WRONG, {
|
||||
neu_http_response(aio, NEU_ERR_PARAM_IS_WRONG, result_error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 != neu_plugin_op(plugin, header, &cmd)) {
|
||||
@@ -327,16 +343,24 @@ send_template_mod_group_req(nng_aio *aio, neu_reqresp_type_e type,
|
||||
{
|
||||
neu_plugin_t *plugin = neu_rest_get_plugin();
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.ctx = aio,
|
||||
.type = type,
|
||||
};
|
||||
if (strlen(req->tmpl) >= NEU_TEMPLATE_NAME_LEN) {
|
||||
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
|
||||
} else if (strlen(req->group) >= NEU_GROUP_NAME_LEN) {
|
||||
return NEU_ERR_GROUP_NAME_TOO_LONG;
|
||||
} else if (req->interval < NEU_GROUP_INTERVAL_LIMIT) {
|
||||
return NEU_ERR_GROUP_PARAMETER_INVALID;
|
||||
}
|
||||
|
||||
neu_req_add_template_group_t cmd = { 0 };
|
||||
strcpy(cmd.tmpl, req->tmpl);
|
||||
strcpy(cmd.group, req->group);
|
||||
cmd.interval = req->interval;
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.ctx = aio,
|
||||
.type = type,
|
||||
};
|
||||
|
||||
if (0 != neu_plugin_op(plugin, header, &cmd)) {
|
||||
return NEU_ERR_IS_BUSY;
|
||||
}
|
||||
@@ -350,22 +374,10 @@ static inline void process_mod_template_group(nng_aio * aio,
|
||||
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
|
||||
aio, neu_json_template_mod_group_req_t,
|
||||
neu_json_decode_template_mod_group_req, {
|
||||
if (strlen(req->group) >= NEU_GROUP_NAME_LEN) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_GROUP_NAME_TOO_LONG, {
|
||||
neu_http_response(aio, NEU_ERR_GROUP_NAME_TOO_LONG,
|
||||
result_error);
|
||||
});
|
||||
} else if (req->interval < NEU_GROUP_INTERVAL_LIMIT) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_GROUP_PARAMETER_INVALID, {
|
||||
neu_http_response(aio, NEU_ERR_GROUP_PARAMETER_INVALID,
|
||||
result_error);
|
||||
});
|
||||
} else {
|
||||
int ret = send_template_mod_group_req(aio, type, req);
|
||||
if (ret != 0) {
|
||||
NEU_JSON_RESPONSE_ERROR(
|
||||
ret, { neu_http_response(aio, ret, result_error); });
|
||||
}
|
||||
int ret = send_template_mod_group_req(aio, type, req);
|
||||
if (ret != 0) {
|
||||
NEU_JSON_RESPONSE_ERROR(
|
||||
ret, { neu_http_response(aio, ret, result_error); });
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -380,23 +392,43 @@ void handle_update_template_group(nng_aio *aio)
|
||||
process_mod_template_group(aio, NEU_REQ_UPDATE_TEMPLATE_GROUP);
|
||||
}
|
||||
|
||||
void handle_del_template_group(nng_aio *aio)
|
||||
static inline int
|
||||
send_template_del_group_req(nng_aio * aio,
|
||||
neu_json_template_del_group_req_t *req)
|
||||
{
|
||||
neu_plugin_t *plugin = neu_rest_get_plugin();
|
||||
|
||||
if (strlen(req->tmpl) >= NEU_TEMPLATE_NAME_LEN) {
|
||||
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
if (strlen(req->group) >= NEU_GROUP_NAME_LEN) {
|
||||
return NEU_ERR_GROUP_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
neu_req_add_template_tag_t cmd = { 0 };
|
||||
strcpy(cmd.tmpl, req->tmpl);
|
||||
strcpy(cmd.group, req->group);
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.ctx = aio,
|
||||
.type = NEU_REQ_DEL_TEMPLATE_GROUP,
|
||||
};
|
||||
|
||||
if (0 != neu_plugin_op(plugin, header, &cmd)) {
|
||||
return NEU_ERR_IS_BUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void handle_del_template_group(nng_aio *aio)
|
||||
{
|
||||
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
|
||||
aio, neu_json_template_del_group_req_t,
|
||||
neu_json_decode_template_del_group_req, {
|
||||
neu_reqresp_head_t header = { 0 };
|
||||
header.ctx = aio;
|
||||
header.type = NEU_REQ_DEL_TEMPLATE_GROUP;
|
||||
|
||||
neu_req_add_template_group_t cmd = { 0 };
|
||||
strcpy(cmd.tmpl, req->tmpl);
|
||||
strcpy(cmd.group, req->group);
|
||||
|
||||
if (0 != neu_plugin_op(plugin, header, &cmd)) {
|
||||
int ret = NEU_ERR_IS_BUSY;
|
||||
int ret = send_template_del_group_req(aio, req);
|
||||
if (0 != ret) {
|
||||
NEU_JSON_RESPONSE_ERROR(
|
||||
ret, { neu_http_response(aio, ret, result_error); });
|
||||
}
|
||||
@@ -406,15 +438,16 @@ void handle_del_template_group(nng_aio *aio)
|
||||
static int send_template_mod_tags_req(nng_aio *aio, neu_reqresp_type_e type,
|
||||
neu_json_template_mod_tags_req_t *req)
|
||||
{
|
||||
int ret = 0;
|
||||
neu_plugin_t *plugin = neu_rest_get_plugin();
|
||||
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
if (strlen(req->tmpl) >= NEU_TEMPLATE_NAME_LEN) {
|
||||
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.ctx = aio,
|
||||
.type = type,
|
||||
};
|
||||
if (strlen(req->group) >= NEU_GROUP_NAME_LEN) {
|
||||
return NEU_ERR_GROUP_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
neu_req_add_template_tag_t cmd = { 0 };
|
||||
strcpy(cmd.tmpl, req->tmpl);
|
||||
@@ -425,7 +458,7 @@ static int send_template_mod_tags_req(nng_aio *aio, neu_reqresp_type_e type,
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < req->n_tag; i++) {
|
||||
for (int i = 0; i < req->n_tag; i++) {
|
||||
cmd.n_tag += 1;
|
||||
if (0 != (ret = set_tag_by_json(&cmd.tags[i], &req->tags[i]))) {
|
||||
neu_req_add_template_tag_fini(&cmd);
|
||||
@@ -433,6 +466,11 @@ static int send_template_mod_tags_req(nng_aio *aio, neu_reqresp_type_e type,
|
||||
}
|
||||
}
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.ctx = aio,
|
||||
.type = type,
|
||||
};
|
||||
|
||||
if (0 != neu_plugin_op(plugin, header, &cmd)) {
|
||||
neu_req_add_template_tag_fini(&cmd);
|
||||
return NEU_ERR_IS_BUSY;
|
||||
@@ -447,26 +485,38 @@ static int send_template_del_tags_req(nng_aio * aio,
|
||||
int ret = 0;
|
||||
neu_plugin_t *plugin = neu_rest_get_plugin();
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.ctx = aio,
|
||||
.type = NEU_REQ_DEL_TEMPLATE_TAG,
|
||||
};
|
||||
if (strlen(req->tmpl) >= NEU_TEMPLATE_NAME_LEN) {
|
||||
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
if (strlen(req->group) >= NEU_GROUP_NAME_LEN) {
|
||||
return NEU_ERR_GROUP_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
neu_req_del_template_tag_t cmd = { 0 };
|
||||
strcpy(cmd.tmpl, req->tmpl);
|
||||
strcpy(cmd.group, req->group);
|
||||
|
||||
cmd.n_tag = req->n_tags;
|
||||
cmd.tags = calloc(req->n_tags, sizeof(char *));
|
||||
cmd.tags = calloc(req->n_tags, sizeof(char *));
|
||||
if (NULL == cmd.tags) {
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < req->n_tags; i++) {
|
||||
if (strlen(req->tags[i]) >= NEU_TAG_NAME_LEN) {
|
||||
neu_req_del_template_tag_fini(&cmd);
|
||||
return NEU_ERR_TAG_NAME_TOO_LONG;
|
||||
}
|
||||
cmd.tags[i] = req->tags[i];
|
||||
req->tags[i] = NULL; // ownership moved
|
||||
cmd.n_tag += 1;
|
||||
}
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.ctx = aio,
|
||||
.type = NEU_REQ_DEL_TEMPLATE_TAG,
|
||||
};
|
||||
|
||||
if (ret != neu_plugin_op(plugin, header, &cmd)) {
|
||||
neu_req_del_template_tag_fini(&cmd);
|
||||
ret = NEU_ERR_IS_BUSY;
|
||||
@@ -530,44 +580,74 @@ void handle_get_template_tags(nng_aio *aio)
|
||||
|
||||
neu_req_get_template_tag_t cmd = { 0 };
|
||||
|
||||
if (neu_http_get_param_str(aio, "template", cmd.tmpl, sizeof(cmd.tmpl)) <=
|
||||
0 ||
|
||||
neu_http_get_param_str(aio, "group", cmd.group, sizeof(cmd.group)) <=
|
||||
0) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_PARAM_IS_WRONG, {
|
||||
neu_http_response(aio, NEU_ERR_PARAM_IS_WRONG, result_error);
|
||||
})
|
||||
return;
|
||||
ret = neu_http_get_param_str(aio, "template", cmd.tmpl, sizeof(cmd.tmpl));
|
||||
// required parameter
|
||||
if (ret <= 0 || sizeof(cmd.tmpl) <= (size_t) ret) {
|
||||
ret = NEU_ERR_PARAM_IS_WRONG;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// optional
|
||||
neu_http_get_param_str(aio, "name", cmd.name, sizeof(cmd.name));
|
||||
ret = neu_http_get_param_str(aio, "group", cmd.group, sizeof(cmd.group));
|
||||
// required parameter
|
||||
if (ret <= 0 || sizeof(cmd.tmpl) <= (size_t) ret) {
|
||||
ret = NEU_ERR_PARAM_IS_WRONG;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = neu_http_get_param_str(aio, "name", cmd.name, sizeof(cmd.name));
|
||||
// optional parameter
|
||||
if (-2 != ret && (ret <= 0 || sizeof(cmd.name) <= (size_t) ret)) {
|
||||
ret = NEU_ERR_PARAM_IS_WRONG;
|
||||
goto end;
|
||||
}
|
||||
|
||||
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 (0 != ret) {
|
||||
ret = NEU_ERR_IS_BUSY;
|
||||
}
|
||||
|
||||
end:
|
||||
if (0 != ret) {
|
||||
NEU_JSON_RESPONSE_ERROR(ret,
|
||||
{ neu_http_response(aio, ret, result_error); });
|
||||
}
|
||||
}
|
||||
|
||||
static inline int send_template_inst_req(nng_aio * aio,
|
||||
neu_json_template_inst_req_t *req)
|
||||
{
|
||||
neu_plugin_t *plugin = neu_rest_get_plugin();
|
||||
|
||||
if (strlen(req->name) >= NEU_TEMPLATE_NAME_LEN) {
|
||||
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
if (strlen(req->node) >= NEU_NODE_NAME_LEN) {
|
||||
return NEU_ERR_PLUGIN_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
neu_req_inst_template_t cmd = { 0 };
|
||||
strncpy(cmd.tmpl, req->name, sizeof(cmd.tmpl));
|
||||
strncpy(cmd.node, req->node, sizeof(cmd.node));
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.ctx = aio,
|
||||
.type = NEU_REQ_INST_TEMPLATE,
|
||||
};
|
||||
|
||||
if (0 != neu_plugin_op(plugin, header, &cmd)) {
|
||||
return NEU_ERR_IS_BUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void handle_instantiate_template(nng_aio *aio)
|
||||
{
|
||||
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
|
||||
aio, neu_json_template_inst_req_t, neu_json_decode_template_inst_req, {
|
||||
neu_plugin_t *plugin = neu_rest_get_plugin();
|
||||
|
||||
neu_reqresp_head_t header = { 0 };
|
||||
header.ctx = aio;
|
||||
header.type = NEU_REQ_INST_TEMPLATE;
|
||||
|
||||
neu_req_inst_template_t cmd = { 0 };
|
||||
strncpy(cmd.tmpl, req->name, sizeof(cmd.tmpl));
|
||||
strncpy(cmd.node, req->node, sizeof(cmd.node));
|
||||
|
||||
int ret = neu_plugin_op(plugin, header, &cmd);
|
||||
int ret = send_template_inst_req(aio, req);
|
||||
if (0 != ret) {
|
||||
ret = NEU_ERR_IS_BUSY;
|
||||
NEU_JSON_RESPONSE_ERROR(
|
||||
ret, { neu_http_response(aio, ret, result_error); });
|
||||
}
|
||||
@@ -587,7 +667,8 @@ void handle_get_template_group(nng_aio *aio)
|
||||
|
||||
neu_req_get_template_group_t cmd = { 0 };
|
||||
int ret = neu_http_get_param_str(aio, "name", cmd.tmpl, sizeof(cmd.tmpl));
|
||||
if (ret <= 0 || (size_t) ret >= sizeof(cmd.tmpl)) {
|
||||
// required parameter
|
||||
if (ret <= 0 || sizeof(cmd.tmpl) <= (size_t) ret) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_PARAM_IS_WRONG, {
|
||||
neu_http_response(aio, NEU_ERR_PARAM_IS_WRONG, result_error);
|
||||
});
|
||||
|
||||
+20
-3
@@ -244,7 +244,7 @@ int neu_adapter_rename(neu_adapter_t *adapter, const char *new_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 };
|
||||
@@ -254,8 +254,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);
|
||||
}
|
||||
@@ -321,6 +321,22 @@ static int adapter_update_metric(neu_adapter_t *adapter,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adapter_reset_metrics(neu_adapter_t *adapter)
|
||||
{
|
||||
neu_metric_entry_t *entry = NULL;
|
||||
if (NULL == adapter->metrics) {
|
||||
return;
|
||||
}
|
||||
|
||||
HASH_LOOP(hh, adapter->metrics->entries, entry) { entry->value = 0; }
|
||||
|
||||
neu_group_metrics_t *g = NULL;
|
||||
HASH_LOOP(hh, adapter->metrics->group_metrics, g)
|
||||
{
|
||||
HASH_LOOP(hh, g->entries, entry) { entry->value = 0; }
|
||||
}
|
||||
}
|
||||
|
||||
static int adapter_command(neu_adapter_t *adapter, neu_reqresp_head_t header,
|
||||
void *data)
|
||||
{
|
||||
@@ -1056,6 +1072,7 @@ int neu_adapter_stop(neu_adapter_t *adapter)
|
||||
if (error == NEU_ERR_SUCCESS) {
|
||||
adapter->state = NEU_NODE_RUNNING_STATE_STOPPED;
|
||||
adapter_storage_state(adapter->name, adapter->state);
|
||||
adapter_reset_metrics(adapter);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
||||
@@ -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_rename(neu_adapter_t *adapter, const char *new_name);
|
||||
|
||||
|
||||
@@ -123,9 +123,10 @@ void neu_driver_cache_add(neu_driver_cache_t *cache, const char *group,
|
||||
nng_mtx_unlock(cache->mtx);
|
||||
}
|
||||
|
||||
void neu_driver_cache_update(neu_driver_cache_t *cache, const char *group,
|
||||
const char *tag, int64_t timestamp,
|
||||
neu_dvalue_t value)
|
||||
void neu_driver_cache_update_change(neu_driver_cache_t *cache,
|
||||
const char *group, const char *tag,
|
||||
int64_t timestamp, neu_dvalue_t value,
|
||||
bool change)
|
||||
{
|
||||
struct elem *elem = NULL;
|
||||
tkey_t key = to_key(group, tag);
|
||||
@@ -185,6 +186,9 @@ void neu_driver_cache_update(neu_driver_cache_t *cache, const char *group,
|
||||
}
|
||||
}
|
||||
|
||||
if (change) {
|
||||
elem->changed = true;
|
||||
}
|
||||
elem->value.type = value.type;
|
||||
elem->value.value = value.value;
|
||||
}
|
||||
@@ -192,6 +196,13 @@ void neu_driver_cache_update(neu_driver_cache_t *cache, const char *group,
|
||||
nng_mtx_unlock(cache->mtx);
|
||||
}
|
||||
|
||||
void neu_driver_cache_update(neu_driver_cache_t *cache, const char *group,
|
||||
const char *tag, int64_t timestamp,
|
||||
neu_dvalue_t value)
|
||||
{
|
||||
neu_driver_cache_update_change(cache, group, tag, timestamp, value, false);
|
||||
}
|
||||
|
||||
int neu_driver_cache_get(neu_driver_cache_t *cache, const char *group,
|
||||
const char *tag, neu_driver_cache_value_t *value)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,10 @@ void neu_driver_cache_add(neu_driver_cache_t *cache, const char *group,
|
||||
void neu_driver_cache_update(neu_driver_cache_t *cache, const char *group,
|
||||
const char *tag, int64_t timestamp,
|
||||
neu_dvalue_t value);
|
||||
void neu_driver_cache_update_change(neu_driver_cache_t *cache,
|
||||
const char *group, const char *tag,
|
||||
int64_t timestamp, neu_dvalue_t value,
|
||||
bool change);
|
||||
|
||||
void neu_driver_cache_del(neu_driver_cache_t *cache, const char *group,
|
||||
const char *tag);
|
||||
|
||||
+94
-11
@@ -57,6 +57,7 @@ typedef struct group {
|
||||
|
||||
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;
|
||||
@@ -75,6 +76,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);
|
||||
@@ -101,10 +103,55 @@ static void write_response(neu_adapter_t *adapter, void *r, neu_error error)
|
||||
static void update_im(neu_adapter_t *adapter, const char *group,
|
||||
const char *tag, neu_dvalue_t value)
|
||||
{
|
||||
(void) adapter;
|
||||
(void) group;
|
||||
(void) tag;
|
||||
(void) value;
|
||||
neu_adapter_driver_t *driver = (neu_adapter_driver_t *) adapter;
|
||||
neu_reqresp_head_t header = { 0 };
|
||||
|
||||
if (tag == NULL || value.type == NEU_TYPE_ERROR) {
|
||||
nlog_warn("update_im tag is null or value is error %d",
|
||||
value.value.i32);
|
||||
return;
|
||||
}
|
||||
|
||||
UT_array *tags = neu_adapter_driver_get_ptag(driver, group, tag);
|
||||
neu_driver_cache_update_change(driver->cache, group, tag, global_timestamp,
|
||||
value, true);
|
||||
driver->adapter.cb_funs.update_metric(&driver->adapter,
|
||||
NEU_METRIC_TAG_READS_TOTAL, 1, NULL);
|
||||
neu_datatag_t *first = utarray_front(tags);
|
||||
|
||||
if (first == NULL ||
|
||||
!neu_tag_attribute_test(first, NEU_ATTRIBUTE_SUBSCRIBE)) {
|
||||
utarray_free(tags);
|
||||
nlog_info("update immediately, driver: %s, "
|
||||
"group: %s, tag: %s, type: %s, "
|
||||
"timestamp: %" PRId64,
|
||||
driver->adapter.name, group, tag, neu_type_string(value.type),
|
||||
global_timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
nlog_info("update and report immediately, driver: %s, "
|
||||
"group: %s, tag: %s, type: %s, "
|
||||
"timestamp: %" PRId64,
|
||||
driver->adapter.name, group, tag, neu_type_string(value.type),
|
||||
global_timestamp);
|
||||
|
||||
header.type = NEU_REQRESP_TRANS_DATA;
|
||||
neu_reqresp_trans_data_t *data = calloc(
|
||||
1, sizeof(neu_reqresp_trans_data_t) + sizeof(neu_resp_tag_value_t));
|
||||
|
||||
strcpy(data->driver, driver->adapter.name);
|
||||
strcpy(data->group, group);
|
||||
|
||||
data->n_tag = read_report_group(global_timestamp, 0, driver->cache, group,
|
||||
tags, (neu_resp_tag_value_t *) &data[1]);
|
||||
|
||||
if (data->n_tag > 0) {
|
||||
driver->adapter.cb_funs.response(&driver->adapter, &header, data);
|
||||
}
|
||||
|
||||
utarray_free(tags);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void update(neu_adapter_t *adapter, const char *group, const char *tag,
|
||||
@@ -197,6 +244,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);
|
||||
}
|
||||
@@ -405,7 +453,7 @@ static void cal_decimal(neu_type_e tag_type, neu_type_e value_type,
|
||||
case NEU_TYPE_WORD:
|
||||
case NEU_TYPE_LWORD:
|
||||
case NEU_TYPE_DWORD:
|
||||
if (value_type == NEU_TYPE_INT64 || NEU_TYPE_LWORD) {
|
||||
if (value_type == NEU_TYPE_INT64 || value_type == NEU_TYPE_LWORD) {
|
||||
value->u64 = value->u64 / decimal;
|
||||
} else if (value_type == NEU_TYPE_DOUBLE) {
|
||||
value->u64 = (uint64_t) round(value->d64 / decimal);
|
||||
@@ -485,10 +533,9 @@ void neu_adapter_driver_write_tags(neu_adapter_driver_t *driver,
|
||||
|
||||
tv.value = cmd->tags[i].value.value;
|
||||
utarray_push_back(tags, &tv);
|
||||
} else {
|
||||
if (tag != NULL) {
|
||||
neu_tag_free(tag);
|
||||
}
|
||||
}
|
||||
if (tag != NULL) {
|
||||
neu_tag_free(tag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,6 +672,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));
|
||||
@@ -683,6 +735,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);
|
||||
}
|
||||
@@ -964,6 +1017,25 @@ UT_array *neu_adapter_driver_get_read_tag(neu_adapter_driver_t *driver,
|
||||
return tags;
|
||||
}
|
||||
|
||||
UT_array *neu_adapter_driver_get_ptag(neu_adapter_driver_t *driver,
|
||||
const char *group, const char *tag)
|
||||
{
|
||||
group_t * find = NULL;
|
||||
UT_array *tags = NULL;
|
||||
|
||||
HASH_FIND_STR(driver->groups, group, find);
|
||||
if (find != NULL) {
|
||||
neu_datatag_t *t = neu_group_find_tag(find->group, tag);
|
||||
if (t != NULL) {
|
||||
utarray_new(tags, neu_tag_get_icd());
|
||||
utarray_push_back(tags, t);
|
||||
neu_tag_free(t);
|
||||
}
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
static int report_callback(void *usr_data)
|
||||
{
|
||||
group_t * group = (group_t *) usr_data;
|
||||
@@ -1069,7 +1141,7 @@ static void group_change(void *arg, int64_t timestamp, UT_array *static_tags,
|
||||
timestamp);
|
||||
}
|
||||
|
||||
static int read_callback(void *usr_data)
|
||||
static int write_callback(void *usr_data)
|
||||
{
|
||||
group_t * group = (group_t *) usr_data;
|
||||
neu_node_running_state_e state = group->driver->adapter.state;
|
||||
@@ -1098,6 +1170,17 @@ static int read_callback(void *usr_data)
|
||||
utarray_clear(group->wt_tags);
|
||||
pthread_mutex_unlock(&group->wt_mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_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;
|
||||
}
|
||||
|
||||
if (neu_group_is_change(group->group, group->timestamp)) {
|
||||
neu_group_change_test(group->group, group->timestamp, (void *) group,
|
||||
group_change);
|
||||
@@ -1210,7 +1293,7 @@ static int read_report_group(int64_t timestamp, int64_t timeout,
|
||||
}
|
||||
|
||||
if (!neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC) &&
|
||||
(timestamp - value.timestamp) > timeout) {
|
||||
(timestamp - value.timestamp) > timeout && timeout > 0) {
|
||||
datas[index].value.type = NEU_TYPE_ERROR;
|
||||
datas[index].value.value.i32 = NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED;
|
||||
} else {
|
||||
|
||||
@@ -51,19 +51,21 @@ int neu_adapter_driver_group_exist(neu_adapter_driver_t *driver,
|
||||
const char * name);
|
||||
UT_array *neu_adapter_driver_get_group(neu_adapter_driver_t *driver);
|
||||
|
||||
int neu_adapter_driver_add_tag(neu_adapter_driver_t *driver, const char *group,
|
||||
neu_datatag_t *tag);
|
||||
int neu_adapter_driver_del_tag(neu_adapter_driver_t *driver, const char *group,
|
||||
const char *tag);
|
||||
int neu_adapter_driver_update_tag(neu_adapter_driver_t *driver,
|
||||
const char *group, neu_datatag_t *tag);
|
||||
int neu_adapter_driver_get_tag(neu_adapter_driver_t *driver, const char *group,
|
||||
UT_array **tags);
|
||||
int neu_adapter_driver_query_tag(neu_adapter_driver_t *driver,
|
||||
const char *group, const char *name,
|
||||
UT_array **tags);
|
||||
void neu_adapter_driver_get_value_tag(neu_adapter_driver_t *driver,
|
||||
const char *group, UT_array **tags);
|
||||
int neu_adapter_driver_add_tag(neu_adapter_driver_t *driver, const char *group,
|
||||
neu_datatag_t *tag);
|
||||
int neu_adapter_driver_del_tag(neu_adapter_driver_t *driver, const char *group,
|
||||
const char *tag);
|
||||
int neu_adapter_driver_update_tag(neu_adapter_driver_t *driver,
|
||||
const char *group, neu_datatag_t *tag);
|
||||
int neu_adapter_driver_get_tag(neu_adapter_driver_t *driver, const char *group,
|
||||
UT_array **tags);
|
||||
UT_array *neu_adapter_driver_get_ptag(neu_adapter_driver_t *driver,
|
||||
const char *group, const char *tag);
|
||||
int neu_adapter_driver_query_tag(neu_adapter_driver_t *driver,
|
||||
const char *group, const char *name,
|
||||
UT_array **tags);
|
||||
void neu_adapter_driver_get_value_tag(neu_adapter_driver_t *driver,
|
||||
const char *group, UT_array **tags);
|
||||
UT_array *neu_adapter_driver_get_read_tag(neu_adapter_driver_t *driver,
|
||||
const char * group);
|
||||
#endif
|
||||
|
||||
@@ -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_error("load %s setting fail", node);
|
||||
nlog_warn("load %s setting fail", node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
+8
-3
@@ -60,8 +60,9 @@ const char *usage_text =
|
||||
"OPTIONS:\n"
|
||||
" -d, --daemon run as daemon process\n"
|
||||
" -h, --help show this help message\n"
|
||||
" --stop stop running neuron\n"
|
||||
" --log log to the stdout\n"
|
||||
" --log_level <LEVEL> default log level(DEBUG,INFO)\n"
|
||||
" --log_level <LEVEL> default log level(DEBUG,NOTICE)\n"
|
||||
" --reset-password reset dashboard to use default password\n"
|
||||
" --restart <POLICY> restart policy to apply when neuron daemon terminates,\n"
|
||||
" - never, never restart (default)\n"
|
||||
@@ -151,6 +152,7 @@ void neu_cli_args_init(neu_cli_args_t *args, int argc, char *argv[])
|
||||
{ "disable_auth", no_argument, NULL, 'a' },
|
||||
{ "config_dir", required_argument, NULL, 'c' },
|
||||
{ "plugin_dir", required_argument, NULL, 'p' },
|
||||
{ "stop", no_argument, NULL, 's' },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
@@ -200,6 +202,9 @@ void neu_cli_args_init(neu_cli_args_t *args, int argc, char *argv[])
|
||||
case 'p':
|
||||
plugin_dir = strdup(optarg);
|
||||
break;
|
||||
case 's':
|
||||
args->stop = true;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
@@ -254,8 +259,8 @@ void neu_cli_args_init(neu_cli_args_t *args, int argc, char *argv[])
|
||||
if (strcmp(log_level, "DEBUG") == 0) {
|
||||
default_log_level = ZLOG_LEVEL_DEBUG;
|
||||
}
|
||||
if (strcmp(log_level, "INFO") == 0) {
|
||||
default_log_level = ZLOG_LEVEL_INFO;
|
||||
if (strcmp(log_level, "NOTICE") == 0) {
|
||||
default_log_level = ZLOG_LEVEL_NOTICE;
|
||||
}
|
||||
free(log_level);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ typedef struct {
|
||||
char * log_init_file;
|
||||
char * config_dir;
|
||||
char * plugin_dir;
|
||||
bool stop;
|
||||
} neu_cli_args_t;
|
||||
|
||||
/** Parse command line arguments.
|
||||
|
||||
+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);
|
||||
}
|
||||
}
|
||||
|
||||
+38
-11
@@ -47,6 +47,7 @@ struct neu_conn {
|
||||
void * data;
|
||||
bool is_connected;
|
||||
bool stop;
|
||||
bool connection_ok;
|
||||
|
||||
neu_conn_callback connected;
|
||||
neu_conn_callback disconnected;
|
||||
@@ -341,8 +342,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) {
|
||||
@@ -353,6 +360,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);
|
||||
@@ -399,14 +407,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), type:%d",
|
||||
conn->fd, len, ret, strerror(errno), errno, conn->param.type);
|
||||
if (errno == EPIPE || (ret == 0 && errno != 0)) {
|
||||
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);
|
||||
@@ -507,7 +524,7 @@ ssize_t neu_conn_udp_recvfrom(neu_conn_t *conn, uint8_t *buf, ssize_t len,
|
||||
zlog_error(conn->param.log,
|
||||
"conn udp fd: %d, recv buf len %zd, ret: %zd, errno: %s(%d)",
|
||||
conn->fd, len, ret, strerror(errno), errno);
|
||||
if (errno == EPIPE || (ret == 0 && errno != 0)) {
|
||||
if (ret == 0 || (ret == -1 && errno != EAGAIN)) {
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
}
|
||||
@@ -838,8 +855,17 @@ static void conn_connect(neu_conn_t *conn)
|
||||
}
|
||||
case NEU_CONN_TTY_CLIENT: {
|
||||
struct termios tty_opt = { 0 };
|
||||
|
||||
#ifdef NEU_SMART_LINK
|
||||
#include "connection/neu_smart_link.h"
|
||||
ret =
|
||||
neu_conn_smart_link_auto_set(conn->param.params.tty_client.device);
|
||||
zlog_notice(conn->param.log, "smart link ret: %d", ret);
|
||||
if (ret > 0) {
|
||||
fd = ret;
|
||||
}
|
||||
#else
|
||||
fd = open(conn->param.params.tty_client.device, O_RDWR | O_NOCTTY, 0);
|
||||
#endif
|
||||
if (fd <= 0) {
|
||||
zlog_error(conn->param.log, "open %s error: %s(%d)",
|
||||
conn->param.params.tty_client.device, strerror(errno),
|
||||
@@ -995,7 +1021,8 @@ static void conn_connect(neu_conn_t *conn)
|
||||
|
||||
static void conn_disconnect(neu_conn_t *conn)
|
||||
{
|
||||
conn->is_connected = false;
|
||||
conn->is_connected = false;
|
||||
conn->connection_ok = false;
|
||||
if (conn->callback_trigger == true) {
|
||||
conn->disconnected(conn->data, conn->fd);
|
||||
conn->callback_trigger = false;
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/serial.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
#include "json/json.h"
|
||||
|
||||
#include "connection/neu_smart_link.h"
|
||||
|
||||
#define DEVICE_CONF_PATH "/etc/config/device.conf"
|
||||
#define SERIAL_CONF_PATH "/etc/config/serial.conf"
|
||||
#define SMART_LINK_PATH "/dev/smartlink"
|
||||
|
||||
#define TYPE 'S'
|
||||
#define UART_RS232 _IOWR(TYPE, 1, int)
|
||||
#define UART_RS485 _IOWR(TYPE, 0, int)
|
||||
|
||||
enum SERIAL_MODE { SM_RS232, SM_RS422, SM_RS485 };
|
||||
|
||||
static int get_port(const char *path);
|
||||
static int get_port_property(int port, int *mode, int *baudrate);
|
||||
static int read_file(const char *path, char **buf);
|
||||
static int set_serial_mode(const char *dev_path, int baudrate, int mode);
|
||||
|
||||
int neu_conn_smart_link_auto_set(const char *dev_path)
|
||||
{
|
||||
int mode = 0;
|
||||
int baudrate = 0;
|
||||
int port = get_port(dev_path);
|
||||
if (port <= 0) {
|
||||
return -1;
|
||||
}
|
||||
printf("get port %d\n", port);
|
||||
|
||||
int ret = get_port_property(port, &mode, &baudrate);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("get port property %d %d\n", mode, baudrate);
|
||||
|
||||
ret = set_serial_mode(dev_path, baudrate, mode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_file(const char *path, char **buf)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
|
||||
fp = fopen(path, "r");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int size = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
*buf = calloc(1, size + 1);
|
||||
if (*buf == NULL) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = fread(*buf, 1, size, fp);
|
||||
if (ret != size) {
|
||||
fclose(fp);
|
||||
free(*buf);
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_port(const char *dev_path)
|
||||
{
|
||||
json_t * root = NULL;
|
||||
json_error_t error;
|
||||
char * buf = NULL;
|
||||
int ret = read_file(DEVICE_CONF_PATH, &buf);
|
||||
if (ret <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
root = json_loads(buf, JSON_DECODE_ANY, &error);
|
||||
if (root == NULL) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_json_elem_t e_tty = {
|
||||
.name = "tty_name",
|
||||
.t = NEU_JSON_OBJECT,
|
||||
};
|
||||
|
||||
ret = neu_json_decode_value(root, &e_tty);
|
||||
if (ret != 0 || json_is_array((json_t *) e_tty.v.val_object) == false) {
|
||||
free(buf);
|
||||
json_decref(root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
json_t *e_dev = NULL;
|
||||
json_array_foreach(e_tty.v.val_object, index, e_dev)
|
||||
{
|
||||
neu_json_elem_t e_dd = {
|
||||
.name = "device",
|
||||
.t = NEU_JSON_STR,
|
||||
};
|
||||
|
||||
ret = neu_json_decode_value(e_dev, &e_dd);
|
||||
if (ret != 0) {
|
||||
free(buf);
|
||||
json_decref(root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(e_dd.v.val_str, dev_path) == 0) {
|
||||
neu_json_elem_t e_port = {
|
||||
.name = "port",
|
||||
.t = NEU_JSON_INT,
|
||||
};
|
||||
|
||||
ret = neu_json_decode_value(e_dev, &e_port);
|
||||
if (ret != 0) {
|
||||
free(buf);
|
||||
json_decref(root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
json_decref(root);
|
||||
free(e_dd.v.val_str);
|
||||
return e_port.v.val_int;
|
||||
}
|
||||
free(e_dd.v.val_str);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
json_decref(root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int get_port_property(int port, int *mode, int *baudrate)
|
||||
{
|
||||
json_t * root = NULL;
|
||||
json_error_t error;
|
||||
char * buf = NULL;
|
||||
int ret = read_file(SERIAL_CONF_PATH, &buf);
|
||||
if (ret <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
root = json_loads(buf, JSON_DECODE_ANY, &error);
|
||||
if (root == NULL) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
json_t *e_port = json_array_get(root, port - 1);
|
||||
if (e_port == NULL) {
|
||||
json_decref(root);
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_json_elem_t elems[] = {
|
||||
{
|
||||
.name = "mode",
|
||||
.t = NEU_JSON_INT,
|
||||
},
|
||||
{
|
||||
.name = "baudrate",
|
||||
.t = NEU_JSON_INT,
|
||||
},
|
||||
};
|
||||
|
||||
ret = neu_json_decode_by_json(e_port, NEU_JSON_ELEM_SIZE(elems), elems);
|
||||
if (ret != 0) {
|
||||
free(buf);
|
||||
json_decref(root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*mode = elems[0].v.val_int;
|
||||
*baudrate = elems[1].v.val_int;
|
||||
|
||||
json_decref(root);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_serial_mode(const char *dev_path, int baudrate, int mode)
|
||||
{
|
||||
static pthread_mutex_t mode_switch_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_lock(&mode_switch_mtx);
|
||||
|
||||
int serial_fd, switch_fd;
|
||||
int tty_num, para;
|
||||
int ret = -1;
|
||||
|
||||
struct serial_rs485 conf;
|
||||
conf.flags &= !SER_RS485_ENABLED;
|
||||
|
||||
switch (baudrate) {
|
||||
case 38400:
|
||||
conf.delay_rts_after_send = 1;
|
||||
break;
|
||||
case 57600:
|
||||
conf.delay_rts_after_send = 4;
|
||||
break;
|
||||
case 115200:
|
||||
conf.delay_rts_after_send = 6;
|
||||
break;
|
||||
default:
|
||||
conf.delay_rts_after_send = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((serial_fd = open(dev_path, O_RDWR | O_NOCTTY)) < 0) {
|
||||
fprintf(stderr, "open %s failed, fd: %d, strerr: %s\n", dev_path,
|
||||
serial_fd, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mode != SM_RS232) {
|
||||
if (ioctl(serial_fd, TIOCMGET, ¶) != 0) {
|
||||
fprintf(stderr, "ioctl failed, strerr: %s\n", strerror(errno));
|
||||
goto out2;
|
||||
}
|
||||
if (mode == SM_RS422) {
|
||||
para |= TIOCM_DTR;
|
||||
conf.flags |= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
|
||||
} else if (mode == SM_RS485) {
|
||||
para &= ~TIOCM_DTR;
|
||||
conf.flags |= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
|
||||
}
|
||||
if (ioctl(serial_fd, TIOCMSET, ¶) != 0) {
|
||||
fprintf(stderr, "ioctl failed, strerr: %s\n", strerror(errno));
|
||||
goto out2;
|
||||
}
|
||||
}
|
||||
ioctl(serial_fd, TIOCSRS485, &conf);
|
||||
|
||||
if ((switch_fd = open(SMART_LINK_PATH, O_RDWR)) < 0) {
|
||||
fprintf(stderr, "open %s failed, ret: %d, strerr: %s\n",
|
||||
SMART_LINK_PATH, switch_fd, strerror(errno));
|
||||
goto out2;
|
||||
}
|
||||
|
||||
sscanf(dev_path, "%*[a-zA-Z/]%d", &tty_num);
|
||||
printf("tty_num: %d\n", tty_num);
|
||||
if (mode == SM_RS232) {
|
||||
ret = ioctl(switch_fd, UART_RS232, tty_num);
|
||||
} else {
|
||||
ret = ioctl(switch_fd, UART_RS485, tty_num);
|
||||
}
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ioctl failed, ret: %d, strerr: %s\n", ret,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
close(switch_fd);
|
||||
ret = serial_fd;
|
||||
pthread_mutex_unlock(&mode_switch_mtx);
|
||||
return ret;
|
||||
out2:
|
||||
close(serial_fd);
|
||||
serial_fd = -1;
|
||||
out:
|
||||
pthread_mutex_unlock(&mode_switch_mtx);
|
||||
return ret;
|
||||
}
|
||||
+5
-1
@@ -274,10 +274,14 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
break;
|
||||
}
|
||||
|
||||
if (init->auto_start) {
|
||||
if (init->state == NEU_NODE_RUNNING_STATE_RUNNING ||
|
||||
init->state == NEU_NODE_RUNNING_STATE_STOPPED) {
|
||||
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);
|
||||
|
||||
@@ -45,7 +45,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 };
|
||||
@@ -79,7 +80,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;
|
||||
}
|
||||
@@ -167,6 +168,11 @@ int neu_manager_add_template(neu_manager_t *manager, const char *name,
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
if (NEU_NA_TYPE_DRIVER != plug_inst->module->type) {
|
||||
free_plugin_instance(plug_inst);
|
||||
return NEU_ERR_PLUGIN_NOT_SUPPORT_TEMPLATE;
|
||||
}
|
||||
|
||||
neu_template_t *tmpl = neu_template_new(name, plugin);
|
||||
if (NULL == tmpl) {
|
||||
free_plugin_instance(plug_inst);
|
||||
@@ -521,7 +527,7 @@ int neu_manager_instantiate_template(neu_manager_t * manager,
|
||||
neu_adapter_driver_t *driver = (neu_adapter_driver_t *) adapter;
|
||||
|
||||
if (adapter->module->type != NEU_NA_TYPE_DRIVER) {
|
||||
ret = NEU_ERR_GROUP_NOT_ALLOW;
|
||||
ret = NEU_ERR_PLUGIN_NOT_SUPPORT_TEMPLATE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
@@ -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, int type,
|
||||
const char *plugin, const char *node);
|
||||
|
||||
+2
-3
@@ -362,9 +362,8 @@ 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_notice("load adapter %s type:%d, name:%s plugin:%s state:%d",
|
||||
ok_or_err, node_info->type, node_info->name,
|
||||
|
||||
@@ -135,3 +135,38 @@ int neuron_already_running()
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int neuron_stop()
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
FILE *fp = fopen(NEURON_DAEMON_LOCK_FNAME, "r");
|
||||
if (NULL == fp) {
|
||||
nlog_error("cannot open %s reason: %s\n", NEURON_DAEMON_LOCK_FNAME,
|
||||
strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
|
||||
long pid = -1;
|
||||
if (1 != fscanf(fp, "%ld", &pid)) {
|
||||
nlog_error("cannot scan pid from: %s\n", NEURON_DAEMON_LOCK_FNAME);
|
||||
goto end;
|
||||
}
|
||||
|
||||
pid_t gid = getpgid((pid_t) pid);
|
||||
if (-1 == gid) {
|
||||
nlog_error("cannot get gpid reason: %s\n", strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (0 == kill((pid_t)(-gid), SIGINT)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
nlog_error("cannot kill gpid:%ld reason: %s\n", (long) gid,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
end:
|
||||
fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
@@ -34,6 +34,8 @@ void daemonize();
|
||||
*/
|
||||
int neuron_already_running();
|
||||
|
||||
int neuron_stop();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+16
-2
@@ -110,9 +110,23 @@ int main(int argc, char *argv[])
|
||||
zlog_level_switch(neuron, default_log_level);
|
||||
|
||||
if (neuron_already_running()) {
|
||||
nlog_fatal("neuron process already running, exit.");
|
||||
rv = -1;
|
||||
if (args.stop) {
|
||||
rv = neuron_stop();
|
||||
nlog_notice("neuron stop ret=%d", rv);
|
||||
if (rv == 0) {
|
||||
printf("neuron stop successfully.\n");
|
||||
}
|
||||
} else {
|
||||
nlog_fatal("neuron process already running, exit.");
|
||||
rv = -1;
|
||||
}
|
||||
goto main_end;
|
||||
} else {
|
||||
if (args.stop) {
|
||||
rv = 0;
|
||||
printf("neuron no running.\n");
|
||||
goto main_end;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < args.restart; ++i) {
|
||||
|
||||
+122
-13
@@ -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)
|
||||
{
|
||||
@@ -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,24 @@ 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 = 0;
|
||||
if (strcmp(info->plugin_name, "Monitor") == 0) {
|
||||
rv = execute_sql(
|
||||
global_db,
|
||||
"INSERT OR IGNORE INTO nodes (name, type, state, plugin_name) "
|
||||
"VALUES (%Q, %i, %i, %Q)",
|
||||
info->name, info->type, info->state, info->plugin_name);
|
||||
} else {
|
||||
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 +677,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 +813,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;
|
||||
}
|
||||
@@ -831,6 +931,7 @@ int neu_persister_store_tags(const char *driver_name, const char *group_name,
|
||||
goto error;
|
||||
}
|
||||
|
||||
tag_count_add(n);
|
||||
sqlite3_finalize(stmt);
|
||||
return 0;
|
||||
|
||||
@@ -944,10 +1045,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,
|
||||
@@ -1128,9 +1233,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)
|
||||
|
||||
+7
-1
@@ -77,7 +77,7 @@ ssize_t neu_url_decode(const char *s, size_t len, char *buf, size_t size)
|
||||
}
|
||||
buf[j++] = c;
|
||||
}
|
||||
buf[(j < size) ? j : --j] = '\0';
|
||||
buf[(j < size) ? j : j - 1] = '\0';
|
||||
return j;
|
||||
}
|
||||
|
||||
@@ -317,10 +317,14 @@ int neu_http_response(nng_aio *aio, neu_err_code_e code, char *content)
|
||||
case NEU_ERR_NEED_TOKEN:
|
||||
case NEU_ERR_DECODE_TOKEN:
|
||||
case NEU_ERR_INVALID_USER_OR_PASSWORD:
|
||||
case NEU_ERR_INVALID_USER:
|
||||
case NEU_ERR_INVALID_PASSWORD:
|
||||
status = NNG_HTTP_STATUS_UNAUTHORIZED;
|
||||
break;
|
||||
case NEU_ERR_BODY_IS_WRONG:
|
||||
case NEU_ERR_PARAM_IS_WRONG:
|
||||
case NEU_ERR_IP_ADDRESS_INVALID:
|
||||
case NEU_ERR_IP_ADDRESS_IN_USE:
|
||||
case NEU_ERR_NODE_SETTING_INVALID:
|
||||
case NEU_ERR_NODE_NOT_ALLOW_UPDATE:
|
||||
case NEU_ERR_NODE_NOT_ALLOW_SUBSCRIBE:
|
||||
@@ -332,10 +336,12 @@ int neu_http_response(nng_aio *aio, neu_err_code_e code, char *content)
|
||||
case NEU_ERR_LIBRARY_FAILED_TO_OPEN:
|
||||
case NEU_ERR_LIBRARY_MODULE_INVALID:
|
||||
case NEU_ERR_NODE_NAME_TOO_LONG:
|
||||
case NEU_ERR_NODE_NAME_EMPTY:
|
||||
case NEU_ERR_GROUP_NAME_TOO_LONG:
|
||||
case NEU_ERR_INVALID_PASSWORD_LEN:
|
||||
case NEU_ERR_DUPLICATE_PASSWORD:
|
||||
case NEU_ERR_TEMPLATE_NAME_TOO_LONG:
|
||||
case NEU_ERR_PLUGIN_NAME_TOO_LONG:
|
||||
case NEU_ERR_PLUGIN_NOT_SUPPORT_TEMPLATE:
|
||||
status = NNG_HTTP_STATUS_BAD_REQUEST;
|
||||
break;
|
||||
|
||||
@@ -42,9 +42,17 @@ target_include_directories(tag_sort_test PRIVATE
|
||||
target_link_libraries(tag_sort_test neuron-base gtest_main gtest)
|
||||
#target_link_directories(modbus_point_test PRIVATE /usr/local/lib)
|
||||
|
||||
add_executable(modbus_test modbus_test.cc
|
||||
${CMAKE_SOURCE_DIR}/plugins/modbus/modbus.c
|
||||
${CMAKE_SOURCE_DIR}/plugins/modbus/modbus_point.c)
|
||||
target_include_directories(modbus_test PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/plugins/modbus)
|
||||
target_link_libraries(modbus_test neuron-base gtest_main gtest pthread zlog)
|
||||
|
||||
include(GoogleTest)
|
||||
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)
|
||||
gtest_discover_tests(modbus_test)
|
||||
@@ -113,6 +113,11 @@ TEST(HTTPTest, http_get_param_str)
|
||||
EXPECT_EQ(ret, 3);
|
||||
EXPECT_EQ(0, strcmp("组", buf));
|
||||
|
||||
nng_http_req_set_uri(req, "/?group=%E7%BB%84");
|
||||
ret = neu_http_get_param_str(aio, "group", buf, 3);
|
||||
EXPECT_EQ(ret, 3);
|
||||
EXPECT_EQ(0, strncmp("组", buf, 2));
|
||||
|
||||
nng_aio_free(aio);
|
||||
nng_http_req_free(req);
|
||||
nng_url_free(url);
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
#include <cstdint>
|
||||
#include <gtest/gtest.h>
|
||||
#include <neuron.h>
|
||||
extern "C" {
|
||||
#include "modbus.h"
|
||||
#include "modbus_point.h"
|
||||
}
|
||||
|
||||
zlog_category_t *neuron = NULL;
|
||||
int64_t global_timestamp = 0;
|
||||
|
||||
TEST(test_modbus_header_wrap, should_return_right_header_value)
|
||||
{
|
||||
uint8_t buf[16] = { 0 };
|
||||
neu_protocol_pack_buf_t pbuf = { 0 };
|
||||
uint16_t seq = 0x0004;
|
||||
|
||||
neu_protocol_pack_buf_init(&pbuf, buf, sizeof(buf));
|
||||
|
||||
modbus_header_wrap(&pbuf, seq);
|
||||
|
||||
struct modbus_header *header =
|
||||
(struct modbus_header *) neu_protocol_unpack_buf(
|
||||
&pbuf, sizeof(struct modbus_header));
|
||||
|
||||
EXPECT_EQ(0x0004, ntohs(header->seq));
|
||||
EXPECT_EQ(0x0, header->protocol);
|
||||
EXPECT_EQ(0x0, ntohs(header->len));
|
||||
}
|
||||
|
||||
TEST(test_modbus_header_unwrap, should_return_right_header_value)
|
||||
{
|
||||
uint8_t buf[16] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 };
|
||||
neu_protocol_unpack_buf_t pbuf = { 0 };
|
||||
struct modbus_header header = { 0 };
|
||||
|
||||
neu_protocol_unpack_buf_init(&pbuf, buf, sizeof(buf));
|
||||
|
||||
modbus_header_unwrap(&pbuf, &header);
|
||||
|
||||
EXPECT_EQ(0x1, header.seq);
|
||||
EXPECT_EQ(0x0, header.protocol);
|
||||
EXPECT_EQ(0x0, header.len);
|
||||
}
|
||||
|
||||
TEST(test_modbus_code_wrap, should_return_right_code_value)
|
||||
{
|
||||
uint8_t buf[16] = { 0 };
|
||||
neu_protocol_pack_buf_t pbuf = { 0 };
|
||||
uint8_t slave_id = 1;
|
||||
uint8_t function = MODBUS_READ_HOLD_REG;
|
||||
neu_protocol_pack_buf_init(&pbuf, buf, sizeof(buf));
|
||||
|
||||
modbus_code_wrap(&pbuf, slave_id, function);
|
||||
|
||||
struct modbus_code *code = (struct modbus_code *) neu_protocol_unpack_buf(
|
||||
&pbuf, sizeof(struct modbus_code));
|
||||
|
||||
EXPECT_EQ(0x1, code->slave_id);
|
||||
EXPECT_EQ(0x3, code->function);
|
||||
}
|
||||
|
||||
TEST(test_modbus_code_unwrap, should_return_right_code_value)
|
||||
{
|
||||
uint8_t buf[16] = { 0x01, 0x03 };
|
||||
neu_protocol_unpack_buf_t pbuf = { 0 };
|
||||
struct modbus_code code = { 0 };
|
||||
|
||||
neu_protocol_unpack_buf_init(&pbuf, buf, sizeof(buf));
|
||||
|
||||
modbus_code_unwrap(&pbuf, &code);
|
||||
|
||||
EXPECT_EQ(0x1, code.slave_id);
|
||||
EXPECT_EQ(0x3, code.function);
|
||||
}
|
||||
|
||||
TEST(test_modbus_address_wrap, should_return_right_address_value)
|
||||
{
|
||||
uint8_t buf[16] = { 0 };
|
||||
neu_protocol_pack_buf_t pbuf = { 0 };
|
||||
uint16_t start = 0x1;
|
||||
uint16_t n_register = 0x2;
|
||||
enum modbus_action action = MODBUS_ACTION_DEFAULT;
|
||||
|
||||
neu_protocol_pack_buf_init(&pbuf, buf, sizeof(buf));
|
||||
|
||||
modbus_address_wrap(&pbuf, start, n_register, action);
|
||||
|
||||
struct modbus_address *address =
|
||||
(struct modbus_address *) neu_protocol_unpack_buf(
|
||||
&pbuf, sizeof(struct modbus_address));
|
||||
|
||||
EXPECT_EQ(0x1, ntohs(address->start_address));
|
||||
EXPECT_EQ(0x2, ntohs(address->n_reg));
|
||||
}
|
||||
|
||||
TEST(test_modbus_address_unwrap, should_return_right_address_value)
|
||||
{
|
||||
uint8_t buf[16] = { 0x00, 0x01, 0x00, 0x02 };
|
||||
neu_protocol_unpack_buf_t pbuf = { 0 };
|
||||
struct modbus_address out_address = { 0 };
|
||||
|
||||
neu_protocol_unpack_buf_init(&pbuf, buf, sizeof(buf));
|
||||
|
||||
modbus_address_unwrap(&pbuf, &out_address);
|
||||
|
||||
struct modbus_address *address =
|
||||
(struct modbus_address *) neu_protocol_pack_buf(
|
||||
&pbuf, sizeof(struct modbus_address));
|
||||
|
||||
EXPECT_EQ(0x1, ntohs(address->start_address));
|
||||
EXPECT_EQ(0x2, ntohs(address->n_reg));
|
||||
}
|
||||
|
||||
TEST(test_modbus_data_wrap, should_return_right_data_value)
|
||||
{
|
||||
uint8_t buf[16] = { 0 };
|
||||
neu_protocol_pack_buf_t pbuf = { 0 };
|
||||
uint8_t n_byte = 4;
|
||||
uint8_t byte[16] = { "\x11\x22\x33\x44" };
|
||||
uint8_t * bytes = byte;
|
||||
enum modbus_action action = MODBUS_ACTION_DEFAULT;
|
||||
|
||||
neu_protocol_pack_buf_init(&pbuf, buf, sizeof(buf));
|
||||
|
||||
modbus_data_wrap(&pbuf, n_byte, bytes, action);
|
||||
|
||||
struct modbus_data *data = (struct modbus_data *) neu_protocol_unpack_buf(
|
||||
&pbuf, sizeof(struct modbus_data));
|
||||
|
||||
EXPECT_EQ(n_byte, data->n_byte);
|
||||
EXPECT_EQ(0x11, data->byte[0]);
|
||||
EXPECT_EQ(0x22, data->byte[1]);
|
||||
EXPECT_EQ(0x33, data->byte[2]);
|
||||
EXPECT_EQ(0x44, data->byte[3]);
|
||||
}
|
||||
|
||||
TEST(test_modbus_data_unwrap, should_return_right_data_value)
|
||||
{
|
||||
uint8_t buf[16] = { "\x04\x11\x22\x33\x44" };
|
||||
neu_protocol_unpack_buf_t pbuf = { 0 };
|
||||
struct modbus_data data = { 0 };
|
||||
uint8_t * bytes = NULL;
|
||||
|
||||
neu_protocol_unpack_buf_init(&pbuf, buf, sizeof(buf));
|
||||
|
||||
modbus_data_unwrap(&pbuf, &data);
|
||||
bytes = neu_protocol_unpack_buf(&pbuf, 4);
|
||||
|
||||
EXPECT_EQ(4, data.n_byte);
|
||||
EXPECT_EQ(0x11, *bytes);
|
||||
EXPECT_EQ(0x22, *(bytes + 1));
|
||||
EXPECT_EQ(0x33, *(bytes + 2));
|
||||
EXPECT_EQ(0x44, *(bytes + 3));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
zlog_init("./config/dev.conf");
|
||||
neuron = zlog_get_category("neuron");
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Reference in New Issue
Block a user