diff --git a/include/neuron/tag.h b/include/neuron/tag.h index 9fb5d71a0..f26591893 100644 --- a/include/neuron/tag.h +++ b/include/neuron/tag.h @@ -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; diff --git a/include/neuron/type.h b/include/neuron/type.h index 4d2684794..06fbb154e 100644 --- a/include/neuron/type.h +++ b/include/neuron/type.h @@ -853,6 +853,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); diff --git a/plugins/modbus/modbus-rtu.json b/plugins/modbus/modbus-rtu.json index 03ce615de..f7f78e1e6 100644 --- a/plugins/modbus/modbus-rtu.json +++ b/plugins/modbus/modbus-rtu.json @@ -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": "开始地址", diff --git a/plugins/modbus/modbus-tcp.json b/plugins/modbus/modbus-tcp.json index 6df5d7385..729e42ee0 100644 --- a/plugins/modbus/modbus-tcp.json +++ b/plugins/modbus/modbus-tcp.json @@ -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": "开始地址", diff --git a/plugins/modbus/modbus.h b/plugins/modbus/modbus.h index 388e71be1..933f701f6 100644 --- a/plugins/modbus/modbus.h +++ b/plugins/modbus/modbus.h @@ -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, diff --git a/plugins/modbus/modbus_point.c b/plugins/modbus/modbus_point.c index b4d2ef14f..fd5fc1ae7 100644 --- a/plugins/modbus/modbus_point.c +++ b/plugins/modbus/modbus_point.c @@ -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; + } } \ No newline at end of file diff --git a/plugins/modbus/modbus_point.h b/plugins/modbus/modbus_point.h index 4d074919b..000ad13c7 100644 --- a/plugins/modbus/modbus_point.h +++ b/plugins/modbus/modbus_point.h @@ -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 } diff --git a/plugins/modbus/modbus_req.c b/plugins/modbus/modbus_req.c index 0ce56dbf0..1b4caa385 100644 --- a/plugins/modbus/modbus_req.c +++ b/plugins/modbus/modbus_req.c @@ -455,6 +455,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: { @@ -712,6 +716,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; @@ -804,7 +811,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, >ags->cmd_sort->cmd[i], req); if (ret <= 0) { diff --git a/plugins/modbus/modbus_req.h b/plugins/modbus/modbus_req.h index 7f386aeb0..70e7429ed 100644 --- a/plugins/modbus/modbus_req.h +++ b/plugins/modbus/modbus_req.h @@ -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; diff --git a/plugins/modbus/modbus_rtu.c b/plugins/modbus/modbus_rtu.c index 93a0306c5..a8d2b3c30 100644 --- a/plugins/modbus/modbus_rtu.c +++ b/plugins/modbus/modbus_rtu.c @@ -178,6 +178,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) { @@ -239,6 +242,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; @@ -247,6 +256,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; diff --git a/plugins/modbus/modbus_tcp.c b/plugins/modbus/modbus_tcp.c index 649b3425f..9db66bf81 100644 --- a/plugins/modbus/modbus_tcp.c +++ b/plugins/modbus/modbus_tcp.c @@ -174,6 +174,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 }; ret = neu_parse_param((char *) config, &err_param, 5, &port, &host, &mode, &timeout, &interval); @@ -229,6 +231,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->interval = interval.v.val_int; plugin->max_retries = max_retries.v.val_int; @@ -238,6 +246,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) { diff --git a/src/adapter/driver/driver.c b/src/adapter/driver/driver.c index 57daf3a40..90b9ec76a 100644 --- a/src/adapter/driver/driver.c +++ b/src/adapter/driver/driver.c @@ -829,9 +829,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; } @@ -2506,9 +2514,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; } @@ -2673,9 +2689,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; } @@ -2854,9 +2878,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; } diff --git a/src/base/tag.c b/src/base/tag.c index 97662f14c..b1247f63b 100644 --- a/src/base/tag.c +++ b/src/base/tag.c @@ -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; + } } }