mirror of
https://github.com/emqx/neuron.git
synced 2026-10-29 23:19:18 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa90052653 | ||
|
|
2824197538 | ||
|
|
72cab4a0c8 | ||
|
|
c21df74a33 | ||
|
|
3d81d072d9 | ||
|
|
534c699da3 | ||
|
|
52e30c87ad | ||
|
|
f4a36fe47e | ||
|
|
7696321182 | ||
|
|
e4954c40a9 | ||
|
|
a8c9dccab7 | ||
|
|
33519663f0 | ||
|
|
0125fcfe17 | ||
|
|
ac9b57fff4 | ||
|
|
71d93753f5 | ||
|
|
639c55ea97 | ||
|
|
5b7724bdfe | ||
|
|
a420e91048 | ||
|
|
1a5a8e0b8a | ||
|
|
206c3055ed | ||
|
|
cc32019de9 | ||
|
|
919a24f264 | ||
|
|
9d0ee222d0 | ||
|
|
bd49739b39 | ||
|
|
0e87862532 | ||
|
|
f7a5604047 | ||
|
|
69ca20eb37 | ||
|
|
ca444a71c1 | ||
|
|
2d230366a1 | ||
|
|
0789deb82a | ||
|
|
12c8046301 | ||
|
|
ccf61815d0 | ||
|
|
9bf877a8e7 | ||
|
|
3b98edebe3 | ||
|
|
99309d2695 | ||
|
|
2e1444573c | ||
|
|
367e0a9842 |
@@ -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'
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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": "指令发送间隔",
|
||||
|
||||
@@ -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": "指令发送间隔",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -66,7 +66,7 @@ struct event_data {
|
||||
bool use;
|
||||
};
|
||||
|
||||
#define EVENT_SIZE 1400
|
||||
#define EVENT_SIZE 2800
|
||||
|
||||
struct neu_events {
|
||||
int epoll_fd;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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']
|
||||
|
||||
Reference in New Issue
Block a user