Compare commits

...
37 Commits
Author SHA1 Message Date
fengzeroz aa90052653 Merge pull request #2737 from vulgraph/backport/CVE-2024-10964-v2.9
[v2.9] Backport CVE-2024-10964: plugin: buffer overflow in library strcpy
2026-09-24 09:39:59 +08:00
xiang.zhou 2824197538 plugin:buffer overflow
(cherry picked from commit 3e3a583d72)
2026-04-24 00:19:33 +08:00
fengzeroz 72cab4a0c8 Merge pull request #2491 from hxy7yx/v2.9-1
[v2.9]feat(modbus):support endianess of 8-Byte data
2025-06-16 10:55:56 +08:00
hxy7yx c21df74a33 feat(modbus):support endianess of 8-Byte data 2025-06-15 18:46:45 -07:00
fengzeroz 3d81d072d9 Merge pull request #2421 from ZhouBox/v2.9
[v2.9]increase the max group limit to 1024
2025-03-31 11:17:03 +08:00
xiang.zhou 534c699da3 increase the max group limit to 1024 2025-03-31 11:09:36 +08:00
fengzeroz 52e30c87ad Merge pull request #2412 from hxy7yx/v2.9-1
[v2.9]fix(allow float-tag to write integers)
2025-03-19 15:59:37 +08:00
hxy7yx f4a36fe47e fix(allow float-tag to write integers) 2025-03-18 20:29:08 -07:00
fengzeroz 7696321182 Merge pull request #2406 from hxy7yx/v2.9-1
[v2.9]allow float-tag to write integers
2025-03-18 11:25:37 +08:00
hxy7yx e4954c40a9 allow float-tag to write integers 2025-03-16 20:13:00 -07:00
fengzeroz a8c9dccab7 Merge pull request #2347 from hxy7yx/v2.9-1
[v2.9]fix(modbus):clear recv buf before sending
2024-12-24 09:50:15 +08:00
hxy7yx 33519663f0 fix(modbus):clear recv buf before sending 2024-12-23 17:18:08 +08:00
fengzeroz 0125fcfe17 Merge pull request #2317 from hxy7yx/v2.9-2
[v2.9]fix(mqtt):separate MQTT and API for JSON(read resp)
2024-11-19 10:06:50 +08:00
hxy7yx ac9b57fff4 fix(mqtt):separate MQTT and API for JSON(read resp) 2024-11-19 09:37:27 +08:00
fengzeroz 71d93753f5 Merge pull request #2312 from fengzeroz/v2.9
version: 2.9.5
2024-11-11 17:07:30 +08:00
fengzero 639c55ea97 version: 2.9.5 2024-11-11 09:05:34 +00:00
fengzeroz 5b7724bdfe Merge pull request #2308 from fengzeroz/v2.9
conn buf size: 8192
2024-11-11 16:30:50 +08:00
fengzero a420e91048 conn buf size: 8192 2024-11-11 08:29:21 +00:00
fengzeroz 1a5a8e0b8a Merge pull request #2283 from fengzeroz/v2.9
mqtt port limit
2024-11-04 16:58:01 +08:00
fengzero 206c3055ed mqtt port limit 2024-11-04 08:53:04 +00:00
fengzeroz cc32019de9 Merge pull request #2272 from hxy7yx/v2.9-2
[2.9]fix(write):correct write value verification
2024-11-01 11:39:39 +08:00
fengzeroz 919a24f264 Merge pull request #2276 from fengzeroz/v2.9
V2.9
2024-11-01 11:36:58 +08:00
fengzero 9d0ee222d0 update_im: not check subscribe 2024-11-01 03:35:53 +00:00
fengzero bd49739b39 Revert "cyclic reporting does not detect change"
This reverts commit 2d230366a1.
2024-11-01 03:35:14 +00:00
hxy7yx 0e87862532 fix(write):correct write value verification 2024-11-01 11:22:38 +08:00
fengzeroz f7a5604047 Merge pull request #2259 from fengzeroz/v2.9
version: 2.9.4
2024-10-21 14:02:18 +08:00
fengzero 69ca20eb37 version: 2.9.4 2024-10-21 05:59:20 +00:00
fengzeroz ca444a71c1 Merge pull request #2245 from fengzeroz/v2.9
cyclic reporting does not detect change
2024-09-26 14:28:14 +08:00
fengzero 2d230366a1 cyclic reporting does not detect change 2024-09-26 06:27:41 +00:00
fengzeroz 0789deb82a Merge pull request #2222 from hxy7yx/v2.9-1
[2.9]fix(read paginate):handle only_write tags
2024-09-19 10:46:14 +08:00
fengzeroz 12c8046301 Merge pull request #2225 from fengzeroz/v2.9
Revert "cyclic reporting does not detect change"
2024-09-19 10:15:29 +08:00
fengzero ccf61815d0 Revert "cyclic reporting does not detect change"
This reverts commit 99309d2695.
2024-09-19 02:10:44 +00:00
hxy7yx 9bf877a8e7 fix(read paginate):handle only_write tags 2024-09-18 16:31:09 +08:00
fengzeroz 3b98edebe3 Merge pull request #2215 from fengzeroz/v2.9
cyclic reporting does not detect change
2024-09-14 10:23:05 +08:00
fengzero 99309d2695 cyclic reporting does not detect change 2024-09-14 02:22:06 +00:00
fengzeroz 2e1444573c Merge pull request #2205 from fengzeroz/v2.9
ci: clang-format
2024-09-09 11:08:27 +08:00
fengzero 367e0a9842 ci: clang-format 2024-09-09 02:58:41 +00:00
28 changed files with 620 additions and 317 deletions
+2 -2
View File
@@ -9,7 +9,7 @@ on:
jobs:
clang_format_check:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
# checkout
@@ -18,7 +18,7 @@ jobs:
submodules: recursive
- name: Run clang-format style check for C/C++ programs.
uses: DoozyX/clang-format-lint-action@v0.12
uses: DoozyX/clang-format-lint-action@v0.18
with:
source: 'src plugins include tests'
exclude: 'include/neuron/utils/uthash.h include/neuron/utils/utarray.h include/neuron/utils/utlist.h include/neuron/utils/zlog.h'
+7 -7
View File
@@ -8,13 +8,13 @@ on:
- published
env:
VERSION: 2.9.3
VERSION: 2.9.5
UI_VERSION: 2.6.1
BRANCH: v2.9
jobs:
cross-build:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
strategy:
matrix:
arch:
@@ -52,14 +52,14 @@ jobs:
run: |
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-$VERSION
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: neuron-sdk
name: neuron-sdk-${{ matrix.arch[2] }}
path: |
neuron-sdk-*.tar.gz
build-debug-sdk:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
strategy:
matrix:
arch:
@@ -83,7 +83,7 @@ jobs:
run: |
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-debug-$VERSION
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: neuron-sdk
path: |
@@ -102,7 +102,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: neuron-sdk
@@ -254,6 +254,8 @@ ssize_t neu_conn_recv(neu_conn_t *conn, uint8_t *buf, ssize_t len);
ssize_t neu_conn_udp_recvfrom(neu_conn_t *conn, uint8_t *buf, ssize_t len,
void *src);
void neu_conn_clear_recv_buffer(neu_conn_t *conn);
/**
* @brief Specify the client to send data.
*
+2 -2
View File
@@ -24,7 +24,7 @@
#define NEU_VERSION_MAJOR 2
#define NEU_VERSION_MINOR 9
#define NEU_VERSION_FIX 3
#define NEU_VERSION_FIX 5
#define NEU_GET_VERSION_MAJOR(V) ((0xffff0000 & V) >> 16)
#define NEU_GET_VERSION_MINOR(V) ((0x0000ff00 & V) >> 8)
@@ -34,7 +34,7 @@
#define NEU_TAG_NAME_LEN 128
#define NEU_TAG_ADDRESS_LEN 128
#define NEU_TAG_DESCRIPTION_LEN 128
#define NEU_GROUP_MAX_PER_NODE 512
#define NEU_GROUP_MAX_PER_NODE 1024
#define NEU_GROUP_NAME_LEN 128
#define NEU_GROUP_INTERVAL_LIMIT 100
#define NEU_DEFAULT_GROUP_INTERVAL 100
+1
View File
@@ -63,6 +63,7 @@ typedef struct {
int neu_json_encode_read_resp(void *json_object, void *param);
int neu_json_encode_read_resp1(void *json_object, void *param);
int neu_json_encode_read_resp2(void *json_object, void *param);
int neu_json_encode_read_paginate_resp(void *json_object, void *param);
typedef struct {
+5
View File
@@ -44,6 +44,10 @@ typedef enum {
NEU_DATATAG_ENDIAN_BL32 = 5, // #BL 2,1,4,3
NEU_DATATAG_ENDIAN_L64 = 6, // #L 8,7,6,5,4,3,2,1
NEU_DATATAG_ENDIAN_B64 = 7, // #B 1,2,3,4,5,6,7,8
NEU_DATATAG_ENDIAN_LL64 = 8,
NEU_DATATAG_ENDIAN_LB64 = 9,
NEU_DATATAG_ENDIAN_BB64 = 10,
NEU_DATATAG_ENDIAN_BL64 = 11,
} neu_datatag_endian_e;
typedef enum {
@@ -63,6 +67,7 @@ typedef union {
} value32;
struct {
neu_datatag_endian_e endian;
bool is_default;
} value64;
struct {
uint16_t length;
+36
View File
@@ -738,6 +738,42 @@ static inline uint64_t neu_htonll(uint64_t u)
return ret;
}
static inline uint64_t neu_htonlb(uint64_t u)
{
uint8_t *in = (uint8_t *) &u;
uint64_t out = 0;
uint8_t *out_bytes = (uint8_t *) &out;
out_bytes[0] = in[1];
out_bytes[1] = in[0];
out_bytes[2] = in[3];
out_bytes[3] = in[2];
out_bytes[4] = in[5];
out_bytes[5] = in[4];
out_bytes[6] = in[7];
out_bytes[7] = in[6];
return out;
}
static inline uint64_t neu_htonbl(uint64_t u)
{
uint8_t *in = (uint8_t *) &u;
uint64_t out = 0;
uint8_t *out_bytes = (uint8_t *) &out;
out_bytes[0] = in[6];
out_bytes[1] = in[7];
out_bytes[2] = in[4];
out_bytes[3] = in[5];
out_bytes[4] = in[2];
out_bytes[5] = in[3];
out_bytes[6] = in[0];
out_bytes[7] = in[1];
return out;
}
static inline uint64_t neu_ntohll(uint64_t u)
{
return neu_htonll(u);
+32 -3
View File
@@ -18,11 +18,11 @@
},
{
"type": 7,
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
},
{
"type": 8,
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
},
{
"type": 9,
@@ -30,7 +30,7 @@
},
{
"type": 10,
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
},
{
"type": 11,
@@ -106,6 +106,35 @@
"max": 10000
}
},
"endianess_64": {
"name": "Endianess of 8-Byte Data",
"name_zh": "8 字节数据字节序",
"description": "Tag byte order, applicable to int64, uint64 and double types",
"description_zh": "点位字节序,适用于 int64,uint64 和 double 类型",
"attribute": "required",
"type": "map",
"default": 1,
"valid": {
"map": [
{
"key": "12 34 56 78",
"value": 1
},
{
"key": "21 43 65 87",
"value": 2
},
{
"key": "87 65 43 21",
"value": 3
},
{
"key": "78 56 34 12",
"value": 4
}
]
}
},
"interval": {
"name": "Send Interval",
"name_zh": "指令发送间隔",
+32 -3
View File
@@ -18,11 +18,11 @@
},
{
"type": 7,
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
},
{
"type": 8,
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
},
{
"type": 9,
@@ -30,7 +30,7 @@
},
{
"type": 10,
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
},
{
"type": 11,
@@ -112,6 +112,35 @@
"max": 10000
}
},
"endianess_64": {
"name": "Endianess of 8-Byte Data",
"name_zh": "8 字节数据字节序",
"description": "Tag byte order, applicable to int64, uint64 and double types",
"description_zh": "点位字节序,适用于 int64,uint64 和 double 类型",
"attribute": "required",
"type": "map",
"default": 1,
"valid": {
"map": [
{
"key": "12 34 56 78",
"value": 1
},
{
"key": "21 43 65 87",
"value": 2
},
{
"key": "87 65 43 21",
"value": 3
},
{
"key": "78 56 34 12",
"value": 4
}
]
}
},
"interval": {
"name": "Send Interval",
"name_zh": "指令发送间隔",
+7
View File
@@ -66,6 +66,13 @@ typedef enum modbus_area {
MODBUS_AREA_HOLD_REGISTER = 4,
} modbus_area_e;
typedef enum modbus_endianess_64 {
MODBUS_LL = 1, // 12 34 56 78
MODBUS_LB = 2, // 21 43 65 87
MODBUS_BB = 3, // 87 65 43 21
MODBUS_BL = 4, // 78 56 34 12
} modbus_endianess_64;
struct modbus_header {
uint16_t seq;
uint16_t protocol;
+34 -6
View File
@@ -230,7 +230,8 @@ modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte)
return sort_result;
}
int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option,
modbus_endianess_64 endianess_64, bool default_tag_endian_64)
{
int n = 0;
switch (type) {
@@ -249,6 +250,9 @@ int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
case NEU_TYPE_DOUBLE:
case NEU_TYPE_INT64:
case NEU_TYPE_UINT64:
if (default_tag_endian_64) {
modbus_convert_endianess_64(value, endianess_64);
}
n = sizeof(uint64_t);
value->u64 = neu_htonll(value->u64);
break;
@@ -282,7 +286,8 @@ int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
return n;
}
modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags)
modbus_write_cmd_sort_t *
modbus_write_tags_sort(UT_array *tags, modbus_endianess_64 endianess_64)
{
neu_tag_sort_result_t *result =
neu_tag_sort(tags, tag_sort_write, tag_cmp_write);
@@ -304,14 +309,17 @@ modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags)
utarray_foreach(result->sorts[i].tags, modbus_point_write_t **, tag_s)
{
if ((*tag_s)->point.area == MODBUS_AREA_COIL) {
n_byte_tag = cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
(*tag_s)->point.option);
n_byte_tag =
cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
(*tag_s)->point.option, endianess_64, true);
data_bit[k / 8] += ((*tag_s)->value.i8) << k % 8;
n_byte += n_byte_tag;
k++;
} else {
n_byte_tag = cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
(*tag_s)->point.option);
n_byte_tag =
cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
(*tag_s)->point.option, endianess_64,
(*tag_s)->point.option.value64.is_default);
memcpy(sort_result->cmd[i].bytes +
2 *
((*tag_s)->point.start_address -
@@ -521,4 +529,24 @@ static bool tag_sort_write(neu_tag_sort_t *sort, void *tag,
}
return true;
}
void modbus_convert_endianess_64(neu_value_u * value,
modbus_endianess_64 endianess_64)
{
switch (endianess_64) {
case MODBUS_LL:
break;
case MODBUS_BB:
value->u64 = neu_htonll(value->u64);
break;
case MODBUS_LB:
value->u64 = neu_htonlb(value->u64);
break;
case MODBUS_BL:
value->u64 = neu_htonbl(value->u64);
break;
default:
break;
}
}
+7 -3
View File
@@ -79,9 +79,13 @@ typedef struct modbus_write_cmd_sort {
modbus_write_cmd_t *cmd;
} modbus_write_cmd_sort_t;
modbus_read_cmd_sort_t * modbus_tag_sort(UT_array *tags, uint16_t max_byte);
modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags);
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs);
modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte);
modbus_write_cmd_sort_t *
modbus_write_tags_sort(UT_array *tags, modbus_endianess_64 endianess_64);
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs);
void modbus_convert_endianess_64(neu_value_u * value,
modbus_endianess_64 endianess_64);
#ifdef __cplusplus
}
+10 -1
View File
@@ -107,6 +107,8 @@ int modbus_send_msg(void *ctx, uint16_t n_byte, uint8_t *bytes)
neu_plugin_t *plugin = (neu_plugin_t *) ctx;
int ret = 0;
neu_conn_clear_recv_buffer(plugin->conn);
plog_send_protocol(plugin, bytes, n_byte);
if (plugin->is_server) {
@@ -412,6 +414,10 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
case NEU_TYPE_DOUBLE:
case NEU_TYPE_INT64:
case NEU_TYPE_UINT64:
if ((*p_tag)->option.value64.is_default) {
modbus_convert_endianess_64(&dvalue.value,
plugin->endianess_64);
}
dvalue.value.u64 = neu_ntohll(dvalue.value.u64);
break;
case NEU_TYPE_BIT: {
@@ -675,6 +681,9 @@ int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
case NEU_TYPE_DOUBLE:
case NEU_TYPE_INT64:
case NEU_TYPE_UINT64:
if (tag->option.value64.is_default) {
modbus_convert_endianess_64(&value, plugin->endianess_64);
}
value.u64 = neu_htonll(value.u64);
n_byte = sizeof(uint64_t);
break;
@@ -742,7 +751,7 @@ int modbus_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags)
utarray_push_back(gtags->tags, &p);
}
gtags->cmd_sort = modbus_write_tags_sort(gtags->tags);
gtags->cmd_sort = modbus_write_tags_sort(gtags->tags, plugin->endianess_64);
for (uint16_t i = 0; i < gtags->cmd_sort->n_cmd; i++) {
uint16_t response_size = 0;
+3 -1
View File
@@ -43,7 +43,9 @@ struct neu_plugin {
uint16_t interval;
uint16_t retry_interval;
uint16_t max_retries;
uint16_t check_header;
modbus_endianess_64 endianess_64;
uint16_t check_header;
};
void modbus_conn_connected(void *data, int fd);
+10
View File
@@ -167,6 +167,9 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
neu_json_elem_t retry_interval = { .name = "retry_interval",
.t = NEU_JSON_INT };
neu_json_elem_t endianess_64 = { .name = "endianess_64",
.t = NEU_JSON_INT };
ret = neu_parse_param((char *) config, &err_param, 3, &link, &timeout,
&interval);
if (ret != 0) {
@@ -206,9 +209,16 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
retry_interval.v.val_int = 0;
}
ret = neu_parse_param((char *) config, &err_param, 1, &endianess_64);
if (ret != 0) {
free(err_param);
endianess_64.v.val_int = MODBUS_LL;
}
param.log = plugin->common.log;
plugin->max_retries = max_retries.v.val_int;
plugin->retry_interval = retry_interval.v.val_int;
plugin->endianess_64 = endianess_64.v.val_int;
if (link.v.val_int == 0) {
param.type = NEU_CONN_TTY_CLIENT;
+9
View File
@@ -163,6 +163,8 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
.t = NEU_JSON_INT };
neu_json_elem_t check_header = { .name = "check_header",
.t = NEU_JSON_INT };
neu_json_elem_t endianess_64 = { .name = "endianess_64",
.t = NEU_JSON_INT };
ret = neu_parse_param((char *) config, &err_param, 5, &port, &host, &mode,
&timeout, &interval);
@@ -191,6 +193,12 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
retry_interval.v.val_int = 0;
}
ret = neu_parse_param((char *) config, &err_param, 1, &endianess_64);
if (ret != 0) {
free(err_param);
endianess_64.v.val_int = MODBUS_LL;
}
ret = neu_parse_param((char *) config, &err_param, 1, &check_header);
if (ret != 0) {
free(err_param);
@@ -201,6 +209,7 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
plugin->interval = interval.v.val_int;
plugin->max_retries = max_retries.v.val_int;
plugin->retry_interval = retry_interval.v.val_int;
plugin->endianess_64 = endianess_64.v.val_int;
plugin->check_header = check_header.v.val_int;
if (mode.v.val_int == 1) {
+246 -246
View File
@@ -1,247 +1,247 @@
{
"client-id": {
"name": "Client ID",
"name_zh": "客户端 ID",
"description": "MQTT client id",
"description_zh": "MQTT 客户端 ID",
"type": "string",
"attribute": "required",
"default": "neuron_${random_str}",
"valid": {
"length": 255
}
},
"qos": {
"name": "QoS Level",
"name_zh": "QoS 等级",
"description": "MQTT QoS level for message delivery",
"description_zh": "MQTT 消息传输使用的服务质量等级",
"type": "map",
"attribute": "optional",
"default": 0,
"valid": {
"map": [
{
"key": "QoS 0",
"value": 0
},
{
"key": "QoS 1",
"value": 1
},
{
"key": "QoS 2",
"value": 2
}
]
}
},
"format": {
"name": "Upload Format",
"name_zh": "上报数据格式",
"description": "JSON format of the data reported. In values-mode, data are split into `values` and `errors` sub objects. In tags-mode, tag data are put in a single array.",
"description_zh": "上报数据的 JSON 格式。在 values-format 格式下,数据被分为 `values` 和 `errors` 两个子对象。在 tags-format 格式下,数据被放在一个数组中。",
"attribute": "required",
"type": "map",
"default": 0,
"valid": {
"map": [
{
"key": "values-format",
"value": 0
},
{
"key": "tags-format",
"value": 1
}
]
}
},
"write-req-topic": {
"name": "Write Request Topic",
"name_zh": "写请求主题",
"description": "MQTT topic to receive write request messages.",
"description_zh": "接收点位写入请求的 MQTT 主题。",
"attribute": "required",
"type": "string",
"default": "/neuron/${random_str}/write/req",
"valid": {
"length": 255
}
},
"write-resp-topic": {
"name": "Write Response Topic",
"name_zh": "写响应主题",
"description": "MQTT topic to send write response messages.",
"description_zh": "发送点位写入响应的 MQTT 主题。",
"attribute": "required",
"type": "string",
"default": "/neuron/${random_str}/write/resp",
"valid": {
"length": 255
}
},
"offline-cache": {
"name": "Offline Data Caching",
"name_zh": "离线缓存",
"description": "Offline caching switch. Cache MQTT messages when offline, and sync cached messages when back online.",
"description_zh": "离线缓存开关。连接断开时缓存 MQTT 消息,连接重建时同步缓存的 MQTT 消息到服务器。",
"attribute": "optional",
"type": "bool",
"default": false,
"valid": {}
},
"cache-mem-size": {
"name": "Cache Memory Size (MB)",
"name_zh": "缓存内存大小(MB)",
"description": "Max in-memory cache size in megabytes when MQTT connection exception occurs. Should be smaller than cache disk size.",
"description_zh": "当 MQTT 连接异常时,最大的内存缓存大小(单位:MB)。应该小于缓存磁盘大小。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"valid": {
"min": 1,
"max": 1024
}
},
"cache-disk-size": {
"name": "Cache Disk Size (MB)",
"name_zh": "缓存磁盘大小(MB)",
"description": "Max in-disk cache size in megabytes when MQTT connection exception occurs. Should be larger than cache memory size. If nonzero, cache memory size should also be nonzero.",
"description_zh": "当 MQTT 连接异常时,最大的磁盘缓存大小(单位:MB)。应该大于缓存内存大小。如果不为 0,缓存内存大小也应该不为 0。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"valid": {
"min": 1,
"max": 10240
}
},
"cache-sync-interval": {
"name": "Cache Sync Interval (MS)",
"name_zh": "缓存消息重传间隔(MS)",
"description": "When MQTT connection restores, cached messages will be synchronised to the broker. This controls the interval in milliseconds between each message to synchronise.",
"description_zh": "当 MQTT 连接重建后,缓存的消息会被同步到服务器。此配置项控制消息重传时每条消息之间的时间间隔,以毫秒为单位。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"default": 100,
"valid": {
"min": 10,
"max": 120000
}
},
"host": {
"name": "Broker Host",
"name_zh": "服务器地址",
"description": "MQTT broker host",
"description_zh": "MQTT 服务器地址",
"attribute": "required",
"type": "string",
"default": "broker.emqx.io",
"valid": {
"length": 255
}
},
"port": {
"name": "Broker Port",
"name_zh": "服务器端口",
"description": "MQTT broker port",
"description_zh": "MQTT 服务器端口",
"attribute": "required",
"type": "int",
"default": 1883,
"valid": {
"min": 1024,
"max": 65535
}
},
"username": {
"name": "Username",
"name_zh": "用户名",
"description": "MQTT user name",
"description_zh": "MQTT 用户名",
"attribute": "optional",
"type": "string",
"default": "",
"valid": {
"length": 255
}
},
"password": {
"name": "Password",
"name_zh": "密码",
"description": "MQTT user password",
"description_zh": "MQTT 用户密码",
"attribute": "optional",
"type": "string",
"default": "",
"valid": {
"length": 255
}
},
"ssl": {
"name": "SSL",
"name_zh": "SSL",
"description": "Enable SSL connection",
"description_zh": "是否启用 SSL 连接",
"attribute": "optional",
"type": "bool",
"default": false,
"valid": {}
},
"ca": {
"name": "CA",
"name_zh": "CA 证书",
"description": "CA certificate which signs the server certificate",
"description_zh": "签发服务器证书的 CA 证书",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
},
"cert": {
"name": "Client Cert",
"name_zh": "客户端证书",
"description": "Client x509 certificate when using two way authentication",
"description_zh": "使用双向认证时,客户端的 x509 证书",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
},
"key": {
"name": "Client Private Key",
"name_zh": "客户端私钥",
"description": "Client private key when using two way authentication",
"description_zh": "使用双向认证时,客户端的私钥",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
}
}
"client-id": {
"name": "Client ID",
"name_zh": "客户端 ID",
"description": "MQTT client id",
"description_zh": "MQTT 客户端 ID",
"type": "string",
"attribute": "required",
"default": "neuron_${random_str}",
"valid": {
"length": 255
}
},
"qos": {
"name": "QoS Level",
"name_zh": "QoS 等级",
"description": "MQTT QoS level for message delivery",
"description_zh": "MQTT 消息传输使用的服务质量等级",
"type": "map",
"attribute": "optional",
"default": 0,
"valid": {
"map": [
{
"key": "QoS 0",
"value": 0
},
{
"key": "QoS 1",
"value": 1
},
{
"key": "QoS 2",
"value": 2
}
]
}
},
"format": {
"name": "Upload Format",
"name_zh": "上报数据格式",
"description": "JSON format of the data reported. In values-mode, data are split into `values` and `errors` sub objects. In tags-mode, tag data are put in a single array.",
"description_zh": "上报数据的 JSON 格式。在 values-format 格式下,数据被分为 `values` 和 `errors` 两个子对象。在 tags-format 格式下,数据被放在一个数组中。",
"attribute": "required",
"type": "map",
"default": 0,
"valid": {
"map": [
{
"key": "values-format",
"value": 0
},
{
"key": "tags-format",
"value": 1
}
]
}
},
"write-req-topic": {
"name": "Write Request Topic",
"name_zh": "写请求主题",
"description": "MQTT topic to receive write request messages.",
"description_zh": "接收点位写入请求的 MQTT 主题。",
"attribute": "required",
"type": "string",
"default": "/neuron/${random_str}/write/req",
"valid": {
"length": 255
}
},
"write-resp-topic": {
"name": "Write Response Topic",
"name_zh": "写响应主题",
"description": "MQTT topic to send write response messages.",
"description_zh": "发送点位写入响应的 MQTT 主题。",
"attribute": "required",
"type": "string",
"default": "/neuron/${random_str}/write/resp",
"valid": {
"length": 255
}
},
"offline-cache": {
"name": "Offline Data Caching",
"name_zh": "离线缓存",
"description": "Offline caching switch. Cache MQTT messages when offline, and sync cached messages when back online.",
"description_zh": "离线缓存开关。连接断开时缓存 MQTT 消息,连接重建时同步缓存的 MQTT 消息到服务器。",
"attribute": "optional",
"type": "bool",
"default": false,
"valid": {}
},
"cache-mem-size": {
"name": "Cache Memory Size (MB)",
"name_zh": "缓存内存大小(MB)",
"description": "Max in-memory cache size in megabytes when MQTT connection exception occurs. Should be smaller than cache disk size.",
"description_zh": "当 MQTT 连接异常时,最大的内存缓存大小(单位:MB)。应该小于缓存磁盘大小。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"valid": {
"min": 1,
"max": 1024
}
},
"cache-disk-size": {
"name": "Cache Disk Size (MB)",
"name_zh": "缓存磁盘大小(MB)",
"description": "Max in-disk cache size in megabytes when MQTT connection exception occurs. Should be larger than cache memory size. If nonzero, cache memory size should also be nonzero.",
"description_zh": "当 MQTT 连接异常时,最大的磁盘缓存大小(单位:MB)。应该大于缓存内存大小。如果不为 0,缓存内存大小也应该不为 0。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"valid": {
"min": 1,
"max": 10240
}
},
"cache-sync-interval": {
"name": "Cache Sync Interval (MS)",
"name_zh": "缓存消息重传间隔(MS)",
"description": "When MQTT connection restores, cached messages will be synchronised to the broker. This controls the interval in milliseconds between each message to synchronise.",
"description_zh": "当 MQTT 连接重建后,缓存的消息会被同步到服务器。此配置项控制消息重传时每条消息之间的时间间隔,以毫秒为单位。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"default": 100,
"valid": {
"min": 10,
"max": 120000
}
},
"host": {
"name": "Broker Host",
"name_zh": "服务器地址",
"description": "MQTT broker host",
"description_zh": "MQTT 服务器地址",
"attribute": "required",
"type": "string",
"default": "broker.emqx.io",
"valid": {
"length": 255
}
},
"port": {
"name": "Broker Port",
"name_zh": "服务器端口",
"description": "MQTT broker port",
"description_zh": "MQTT 服务器端口",
"attribute": "required",
"type": "int",
"default": 1883,
"valid": {
"min": 1,
"max": 65535
}
},
"username": {
"name": "Username",
"name_zh": "用户名",
"description": "MQTT user name",
"description_zh": "MQTT 用户名",
"attribute": "optional",
"type": "string",
"default": "",
"valid": {
"length": 255
}
},
"password": {
"name": "Password",
"name_zh": "密码",
"description": "MQTT user password",
"description_zh": "MQTT 用户密码",
"attribute": "optional",
"type": "string",
"default": "",
"valid": {
"length": 255
}
},
"ssl": {
"name": "SSL",
"name_zh": "SSL",
"description": "Enable SSL connection",
"description_zh": "是否启用 SSL 连接",
"attribute": "optional",
"type": "bool",
"default": false,
"valid": {}
},
"ca": {
"name": "CA",
"name_zh": "CA 证书",
"description": "CA certificate which signs the server certificate",
"description_zh": "签发服务器证书的 CA 证书",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
},
"cert": {
"name": "Client Cert",
"name_zh": "客户端证书",
"description": "Client x509 certificate when using two way authentication",
"description_zh": "使用双向认证时,客户端的 x509 证书",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
},
"key": {
"name": "Client Private Key",
"name_zh": "客户端私钥",
"description": "Client private key when using two way authentication",
"description_zh": "使用双向认证时,客户端的私钥",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
}
}
+1 -1
View File
@@ -70,7 +70,7 @@ char *generate_upload_json(neu_plugin_t *plugin, neu_reqresp_trans_data_t *data,
neu_json_encode_read_periodic_resp,
&json_str);
} else if (MQTT_UPLOAD_FORMAT_TAGS == format) { // tags
neu_json_encode_with_mqtt(&json, neu_json_encode_read_resp, &header,
neu_json_encode_with_mqtt(&json, neu_json_encode_read_resp2, &header,
neu_json_encode_read_periodic_resp,
&json_str);
} else {
+2 -2
View File
@@ -40,7 +40,7 @@ void handle_add_plugin(nng_aio *aio)
header.ctx = aio;
header.type = NEU_REQ_ADD_PLUGIN;
strcpy(cmd.library, req->library);
strncpy(cmd.library, req->library, NEU_PLUGIN_LIBRARY_LEN);
cmd.schema_file = req->schema_file;
cmd.so_file = req->so_file;
ret = neu_plugin_op(plugin, header, &cmd);
@@ -64,7 +64,7 @@ void handle_update_plugin(nng_aio *aio)
header.ctx = aio;
header.type = NEU_REQ_UPDATE_PLUGIN;
strcpy(cmd.library, req->library);
strncpy(cmd.library, req->library, NEU_PLUGIN_LIBRARY_LEN);
cmd.schema_file = req->schema_file;
cmd.so_file = req->so_file;
ret = neu_plugin_op(plugin, header, &cmd);
+54 -17
View File
@@ -237,8 +237,7 @@ static void update_im(neu_adapter_t *adapter, const char *group,
}
neu_datatag_t *first = utarray_front(tags);
if (first == NULL ||
!neu_tag_attribute_test(first, NEU_ATTRIBUTE_SUBSCRIBE)) {
if (first == NULL) {
utarray_free(tags);
nlog_debug("update immediately, driver: %s, "
"group: %s, tag: %s, type: %s, "
@@ -757,9 +756,17 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
case NEU_TYPE_LWORD:
switch (tag->option.value64.endian) {
case NEU_DATATAG_ENDIAN_B64:
case NEU_DATATAG_ENDIAN_BB64:
value->value.u64 = neu_ntohll(value->value.u64);
break;
case NEU_DATATAG_ENDIAN_LB64:
value->value.u64 = neu_htonlb(value->value.u64);
break;
case NEU_DATATAG_ENDIAN_BL64:
value->value.u64 = neu_htonbl(value->value.u64);
break;
case NEU_DATATAG_ENDIAN_L64:
case NEU_DATATAG_ENDIAN_LL64:
default:
break;
}
@@ -860,7 +867,8 @@ int check_value_decimal(neu_type_e write_type, double result, int64_t value_min,
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
} else if (result < value_min || result > value_max) {
return NEU_ERR_PLUGIN_TAG_VALUE_OUT_OF_RANGE;
} else if (almost_equal(ceil(result), result, EPSILON)) {
} else if (almost_equal(ceil(result), result, EPSILON) ||
almost_equal(floor(result), result, EPSILON)) {
return NEU_ERR_SUCCESS;
} else {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
@@ -910,27 +918,26 @@ int is_value_in_range(neu_type_e tag_type, int64_t value, double value_d,
case NEU_TYPE_UINT64:
if (write_type != NEU_TYPE_INT64 && write_type != NEU_TYPE_DOUBLE) {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
} else if (almost_equal(ceil(result), result, EPSILON)) {
} else if (almost_equal(ceil(result), result, EPSILON) ||
almost_equal(floor(result), result, EPSILON)) {
return NEU_ERR_SUCCESS;
} else {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
}
case NEU_TYPE_FLOAT:
if (write_type != NEU_TYPE_DOUBLE) {
if (write_type != NEU_TYPE_DOUBLE && write_type != NEU_TYPE_INT64) {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
} else if (result < (int64_t) -FLT_MAX ||
result > (int64_t) FLT_MAX) {
}
if (result < (int64_t) -FLT_MAX || result > (int64_t) FLT_MAX) {
return NEU_ERR_PLUGIN_TAG_VALUE_OUT_OF_RANGE;
} else {
return NEU_ERR_SUCCESS;
}
case NEU_TYPE_DOUBLE:
if (write_type != NEU_TYPE_DOUBLE) {
if (write_type != NEU_TYPE_DOUBLE && write_type != NEU_TYPE_INT64) {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
} else {
return NEU_ERR_SUCCESS;
}
return check_value(write_type, result, INT16_MIN, INT16_MAX);
return NEU_ERR_SUCCESS;
case NEU_TYPE_STRING:
case NEU_TYPE_BOOL:
case NEU_TYPE_BIT:
@@ -974,20 +981,19 @@ int is_value_in_range(neu_type_e tag_type, int64_t value, double value_d,
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
}
case NEU_TYPE_FLOAT:
if (write_type != NEU_TYPE_DOUBLE) {
if (write_type != NEU_TYPE_DOUBLE && write_type != NEU_TYPE_INT64) {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
} else if (value < (int64_t) -FLT_MAX ||
value > (int64_t) FLT_MAX) {
}
if (value < (int64_t) -FLT_MAX || value > (int64_t) FLT_MAX) {
return NEU_ERR_PLUGIN_TAG_VALUE_OUT_OF_RANGE;
} else {
return NEU_ERR_SUCCESS;
}
case NEU_TYPE_DOUBLE:
if (write_type != NEU_TYPE_DOUBLE) {
if (write_type != NEU_TYPE_DOUBLE && write_type != NEU_TYPE_INT64) {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
} else {
return NEU_ERR_SUCCESS;
}
return NEU_ERR_SUCCESS;
case NEU_TYPE_STRING:
if (write_type != NEU_TYPE_STRING) {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
@@ -2180,9 +2186,17 @@ static void read_report_group(int64_t timestamp, int64_t timeout,
case NEU_TYPE_UINT64:
switch (tag->option.value64.endian) {
case NEU_DATATAG_ENDIAN_B64:
case NEU_DATATAG_ENDIAN_BB64:
value.value.value.u64 = neu_htonll(value.value.value.u64);
break;
case NEU_DATATAG_ENDIAN_LB64:
value.value.value.u64 = neu_htonlb(value.value.value.u64);
break;
case NEU_DATATAG_ENDIAN_BL64:
value.value.value.u64 = neu_htonbl(value.value.value.u64);
break;
case NEU_DATATAG_ENDIAN_L64:
case NEU_DATATAG_ENDIAN_LL64:
default:
break;
}
@@ -2345,9 +2359,17 @@ static void read_group(int64_t timestamp, int64_t timeout,
case NEU_TYPE_UINT64:
switch (tag->option.value64.endian) {
case NEU_DATATAG_ENDIAN_B64:
case NEU_DATATAG_ENDIAN_BB64:
value.value.value.u64 = neu_htonll(value.value.value.u64);
break;
case NEU_DATATAG_ENDIAN_LB64:
value.value.value.u64 = neu_htonlb(value.value.value.u64);
break;
case NEU_DATATAG_ENDIAN_BL64:
value.value.value.u64 = neu_htonbl(value.value.value.u64);
break;
case NEU_DATATAG_ENDIAN_L64:
case NEU_DATATAG_ENDIAN_LL64:
default:
break;
}
@@ -2456,6 +2478,13 @@ static void read_group_paginate(int64_t timestamp, int64_t timeout,
tag_value.datatag.option = tag->option;
memcpy(tag_value.datatag.meta, tag->meta, NEU_TAG_META_LENGTH);
if (tag->attribute == NEU_ATTRIBUTE_WRITE) {
tag_value.value.type = NEU_TYPE_STRING;
tag_value.value.value.str[0] = 0;
utarray_push_back(tag_values, &tag_value);
continue;
}
if (neu_driver_cache_meta_get(cache, group, tag->name, &value,
tag_value.metas,
NEU_TAG_META_SIZE) != 0) {
@@ -2517,9 +2546,17 @@ static void read_group_paginate(int64_t timestamp, int64_t timeout,
case NEU_TYPE_UINT64:
switch (tag->option.value64.endian) {
case NEU_DATATAG_ENDIAN_B64:
case NEU_DATATAG_ENDIAN_BB64:
value.value.value.u64 = neu_htonll(value.value.value.u64);
break;
case NEU_DATATAG_ENDIAN_LB64:
value.value.value.u64 = neu_htonlb(value.value.value.u64);
break;
case NEU_DATATAG_ENDIAN_BL64:
value.value.value.u64 = neu_htonbl(value.value.value.u64);
break;
case NEU_DATATAG_ENDIAN_L64:
case NEU_DATATAG_ENDIAN_LL64:
default:
break;
}
+2 -2
View File
@@ -315,8 +315,8 @@ UT_array *neu_group_query_read_tag_paginate(neu_group_t *group,
};
pthread_mutex_lock(&group->mtx);
array = filter_tags_by_page(group->tags, is_readable_and_match_query, &q,
current_page, page_size, total_count);
array = filter_tags_by_page(group->tags, match_query, &q, current_page,
page_size, total_count);
pthread_mutex_unlock(&group->mtx);
return array;
+27 -13
View File
@@ -255,21 +255,35 @@ int neu_datatag_parse_addr_option(const neu_datatag_t * datatag,
case NEU_TYPE_UINT64: {
char *op = find_last_character(datatag->address, '#');
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
option->value64.is_default = true;
if (op != NULL) {
char e = 0;
sscanf(op, "#%c", &e);
char e1 = 0;
char e2 = 0;
int n = sscanf(op, "#%c%c", &e1, &e2);
switch (e) {
case 'B':
option->value64.endian = NEU_DATATAG_ENDIAN_B64;
break;
case 'L':
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
break;
default:
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
break;
if (n == 2) {
if (e1 == 'B' && e2 == 'B') {
option->value64.endian = NEU_DATATAG_ENDIAN_BB64;
option->value64.is_default = false;
} else if (e1 == 'B' && e2 == 'L') {
option->value64.endian = NEU_DATATAG_ENDIAN_BL64;
option->value64.is_default = false;
} else if (e1 == 'L' && e2 == 'L') {
option->value64.endian = NEU_DATATAG_ENDIAN_LL64;
option->value64.is_default = false;
} else if (e1 == 'L' && e2 == 'B') {
option->value64.endian = NEU_DATATAG_ENDIAN_LB64;
option->value64.is_default = false;
}
} else if (n == 1) {
if (e1 == 'B') {
option->value64.endian = NEU_DATATAG_ENDIAN_B64;
option->value64.is_default = false;
} else if (e1 == 'L') {
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
option->value64.is_default = false;
}
}
}
+35 -1
View File
@@ -99,7 +99,7 @@ neu_conn_t *neu_conn_new(neu_conn_param_t *param, void *data,
conn->disconnected = disconnected;
conn->connected = connected;
conn->buf_size = 2048;
conn->buf_size = 8192;
conn->buf = calloc(conn->buf_size, 1);
conn->offset = 0;
conn->stop = false;
@@ -407,6 +407,40 @@ ssize_t neu_conn_send(neu_conn_t *conn, uint8_t *buf, ssize_t len)
return ret;
}
void neu_conn_clear_recv_buffer(neu_conn_t *conn)
{
if (!conn->is_connected) {
return;
}
uint8_t temp_buf[256];
ssize_t ret;
switch (conn->param.type) {
case NEU_CONN_TCP_CLIENT:
do {
ret = recv(conn->fd, temp_buf, sizeof(temp_buf), MSG_DONTWAIT);
if (ret > 0) {
continue;
} else if (ret == 0) {
zlog_info(conn->param.log,
"Connection closed while clearing buffer.");
break;
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
break;
} else {
zlog_error(conn->param.log, "Error clearing buffer: %s",
strerror(errno));
break;
}
} while (ret > 0);
break;
default:
break;
}
}
ssize_t neu_conn_recv(neu_conn_t *conn, uint8_t *buf, ssize_t len)
{
ssize_t ret = 0;
+1 -1
View File
@@ -66,7 +66,7 @@ struct event_data {
bool use;
};
#define EVENT_SIZE 1400
#define EVENT_SIZE 2800
struct neu_events {
int epoll_fd;
+47
View File
@@ -291,6 +291,53 @@ int neu_json_encode_read_resp1(void *json_object, void *param)
return ret;
}
int neu_json_encode_read_resp2(void *json_object, void *param)
{
int ret = 0;
neu_json_read_resp_t *resp = (neu_json_read_resp_t *) param;
void * tag_array = neu_json_array();
neu_json_read_resp_tag_t *p_tag = resp->tags;
for (int i = 0; i < resp->n_tag; i++) {
neu_json_elem_t tag_elems[2 + NEU_TAG_META_SIZE] = { 0 };
tag_elems[0].name = "name";
tag_elems[0].t = NEU_JSON_STR;
tag_elems[0].v.val_str = p_tag->name;
if (p_tag->error != 0) {
tag_elems[1].name = "error";
tag_elems[1].t = NEU_JSON_INT;
tag_elems[1].v.val_int = p_tag->error;
} else {
tag_elems[1].name = "value";
tag_elems[1].t = p_tag->t;
tag_elems[1].v = p_tag->value;
tag_elems[1].precision = p_tag->precision;
}
for (int k = 0; k < p_tag->n_meta; k++) {
tag_elems[2 + k].name = p_tag->metas[k].name;
tag_elems[2 + k].t = p_tag->metas[k].t;
tag_elems[2 + k].v = p_tag->metas[k].value;
}
tag_array =
neu_json_encode_array(tag_array, tag_elems, 2 + p_tag->n_meta);
p_tag++;
}
neu_json_elem_t resp_elems[] = { {
.name = "tags",
.t = NEU_JSON_OBJECT,
.v.val_object = tag_array,
} };
ret = neu_json_encode_field(json_object, resp_elems,
NEU_JSON_ELEM_SIZE(resp_elems));
return ret;
}
int neu_json_decode_write_req(char *buf, neu_json_write_req_t **result)
{
void *json_obj = neu_json_decode_new(buf);
-4
View File
@@ -563,10 +563,6 @@ class TestModbus:
assert 400 == response.status_code
assert error.NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH == response.json()['error']
response = api.write_tag(node=param[0], group='group', tag=hold_float[0]['name'], value=1)
assert 400 == response.status_code
assert error.NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH == response.json()['error']
response = api.write_tags(node=param[0], group='group', tag_values=[
{"tag": hold_int16[0]['name'], "value": 32768},
{"tag": hold_uint16[0]['name'], "value": 2},
+5 -1
View File
@@ -348,12 +348,16 @@ class TestHttp:
@description(given="running neuron", when="put drivers with too many groups", then="should fail")
def test_put_drivers_with_too_many_groups(self):
driver = {
"name": driver_1["name"],
"plugin": driver_1["plugin"],
"params": driver_1["params"],
"groups": [{"group": "grp", "interval": 1000, "tags": []} for _ in range(1000)]
"groups": []
}
for i in range(1025):
driver["groups"].append({"group": "grp" + str(i), "interval": 1000, "tags": []})
response = api.put_drivers([driver])
assert 400 == response.status_code
assert error.NEU_ERR_GROUP_MAX_GROUPS == response.json()['error']
+1 -1
View File
@@ -1 +1 @@
2.9.3
2.9.5