Merge pull request #2499 from hxy7yx/main-1

feat(modbus):support endianess of 8-Byte data
This commit is contained in:
fengzeroz
2025-06-16 11:24:35 +08:00
committed by GitHub
13 changed files with 247 additions and 38 deletions
+5
View File
@@ -43,6 +43,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 {
@@ -62,6 +66,7 @@ typedef union {
} value32;
struct {
neu_datatag_endian_e endian;
bool is_default;
} value64;
struct {
uint16_t length;
+36
View File
@@ -890,6 +890,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);
+34 -5
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,
@@ -158,8 +158,8 @@
}
},
"endianess": {
"name": "Endianess",
"name_zh": "字节序",
"name": "Endianess of 4-Byte Data",
"name_zh": "4 字节数据字节序",
"description": "Tag byte order, ABCD corresponds to 1234",
"description_zh": "点位字节序,ABCD 对应 1234",
"attribute": "required",
@@ -186,6 +186,35 @@
]
}
},
"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
}
]
}
},
"address_base": {
"name": "Start Address",
"name_zh": "开始地址",
+34 -5
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,
@@ -166,8 +166,8 @@
}
},
"endianess": {
"name": "Endianess",
"name_zh": "字节序",
"name": "Endianess of 4-Byte Data",
"name_zh": "4 字节数据字节序",
"description": "Tag byte order, ABCD corresponds to 1234",
"description_zh": "点位字节序,ABCD 对应 1234",
"attribute": "required",
@@ -194,6 +194,35 @@
]
}
},
"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
}
]
}
},
"address_base": {
"name": "Start Address",
"name_zh": "开始地址",
+7
View File
@@ -73,6 +73,13 @@ typedef enum modbus_endianess {
MODBUS_CDAB = 4,
} modbus_endianess;
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;
typedef enum modbus_address_base {
base_0 = 0,
base_1 = 1,
+36 -10
View File
@@ -238,7 +238,8 @@ modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte)
}
int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option,
modbus_endianess endianess, bool default_tag_endian)
modbus_endianess endianess, bool default_tag_endian,
modbus_endianess_64 endianess_64, bool default_tag_endian_64)
{
int n = 0;
switch (type) {
@@ -260,6 +261,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;
@@ -293,8 +297,9 @@ 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_endianess endianess)
modbus_write_cmd_sort_t *
modbus_write_tags_sort(UT_array *tags, modbus_endianess endianess,
modbus_endianess_64 endianess_64)
{
neu_tag_sort_result_t *result =
neu_tag_sort(tags, tag_sort_write, tag_cmp_write);
@@ -316,17 +321,18 @@ 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, endianess, true);
n_byte_tag = cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
(*tag_s)->point.option, endianess, true,
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, endianess,
(*tag_s)->point.option.value32.is_default);
n_byte_tag = cal_n_byte(
(*tag_s)->point.type, &(*tag_s)->value,
(*tag_s)->point.option, endianess,
(*tag_s)->point.option.value32.is_default, endianess_64,
(*tag_s)->point.option.value64.is_default);
memcpy(sort_result->cmd[i].bytes +
2 *
((*tag_s)->point.start_address -
@@ -558,4 +564,24 @@ void modbus_convert_endianess(neu_value_u *value, modbus_endianess endianess)
default:
break;
}
}
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 -4
View File
@@ -81,12 +81,15 @@ 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,
modbus_endianess endianess);
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 endianess,
modbus_endianess_64 endianess_64);
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs);
void modbus_convert_endianess(neu_value_u *value, modbus_endianess endianess);
void modbus_convert_endianess_64(neu_value_u * value,
modbus_endianess_64 endianess_64);
#ifdef __cplusplus
}
+9 -1
View File
@@ -472,6 +472,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: {
@@ -729,6 +733,9 @@ static uint8_t convert_value(neu_plugin_t *plugin, neu_value_u *value,
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;
@@ -821,7 +828,8 @@ 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, plugin->endianess);
gtags->cmd_sort = modbus_write_tags_sort(gtags->tags, plugin->endianess,
plugin->endianess_64);
for (uint16_t i = 0; i < gtags->cmd_sort->n_cmd; i++) {
ret = write_modbus_points(plugin, &gtags->cmd_sort->cmd[i], req);
if (ret <= 0) {
+1
View File
@@ -40,6 +40,7 @@ struct neu_plugin {
modbus_protocol_e protocol;
modbus_endianess endianess;
modbus_endianess_64 endianess_64;
modbus_address_base address_base;
uint16_t interval;
+10
View File
@@ -183,6 +183,9 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
neu_json_elem_t address_base = { .name = "address_base",
.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) {
@@ -244,6 +247,12 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
address_base.v.val_int = base_1;
}
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;
@@ -252,6 +261,7 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
plugin->degrade_time = degrade_time.v.val_int;
plugin->endianess = endianess.v.val_int;
plugin->address_base = address_base.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
@@ -190,6 +190,8 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
neu_json_elem_t endianess = { .name = "endianess", .t = NEU_JSON_INT };
neu_json_elem_t address_base = { .name = "address_base",
.t = NEU_JSON_INT };
neu_json_elem_t endianess_64 = { .name = "endianess_64",
.t = NEU_JSON_INT };
neu_json_elem_t backup_ip = { .name = "backup_host",
.t = NEU_JSON_STR,
@@ -260,6 +262,12 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
backup = true;
}
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;
param_backup.log = plugin->common.log;
plugin->interval = interval.v.val_int;
@@ -270,6 +278,7 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
plugin->degrade_cycle = degrade_cycle.v.val_int;
plugin->degrade_time = degrade_time.v.val_int;
plugin->endianess = endianess.v.val_int;
plugin->endianess_64 = endianess_64.v.val_int;
plugin->address_base = address_base.v.val_int;
if (mode.v.val_int == 1) {
+32
View File
@@ -947,9 +947,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;
}
@@ -2614,9 +2622,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;
}
@@ -2780,9 +2796,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;
}
@@ -2960,9 +2984,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;
}
+27 -13
View File
@@ -262,21 +262,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;
}
}
}