Merge pull request #1452 from hxy7yx/v2.5-1

feat(modbus):write multiple tags
This commit is contained in:
fengzeroz
2023-08-23 17:27:12 +08:00
committed by GitHub
14 changed files with 434 additions and 32 deletions
+13
View File
@@ -48,6 +48,13 @@ ${input_bit_1_name_wrong} {"name": "input_bit", "address": "1!100001",
${input_bit_1_attribute_unmatch} {"name": "input_bit_1", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
${input_bit_1_type_unmatch} {"name": "input_bit_1", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
${hold_int16_1} {"name": "hold_int16_1", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
${hold_int16_2} {"name": "hold_int16_2", "address": "1!400002", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
${hold_int16_3} {"name": "hold_int16_3", "address": "1!400003", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
${hold_string_tags_1} {"name": "hold_string_tags_1", "address": "1!40001.4", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_STRING}}
${hold_string_tags_2} {"name": "hold_string_tags_2", "address": "1!40003.4", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_STRING}}
${hold_string_tags_3} {"name": "hold_string_tags_3", "address": "1!40005.4", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_STRING}}
*** Test Cases ***
Set a node with right settings, it should be success.
[Template] Set a ${node} with right ${node_settings}, it will be success.
@@ -146,6 +153,12 @@ Update a tag with unmatch address and types and attribute, it should be failure.
${input_bit_1} ${input_bit_1_type_unmatch} ${modbus_rtu_node} 200 ${NEU_ERR_TAG_TYPE_NOT_SUPPORT}
${input_bit_1} ${input_bit_1_name_wrong} ${modbus_rtu_node} 200 ${NEU_ERR_TAG_NOT_EXIST}
Write 3 tags 1 time, it should return success
[Template] Write and Read ${tag_data1}, ${tag_data2} and ${tag_data3} named ${tag1}, ${tag2} and ${tag3} from ${node}, using ${check} to check the ${value1}, ${value2} and ${value3}, it will be success.
${hold_int16_1} ${hold_int16_2} ${hold_int16_3} hold_int16_1 hold_int16_2 hold_int16_3 ${modbus_rtu_node} Compare Tag Value As Int 1 2 3
${coil_bit_1} ${coil_bit_2} ${coil_bit_3} coil_bit_1 coil_bit_2 coil_bit_3 ${modbus_rtu_node} Compare Tag Value As Int 1 0 1
${hold_string_tags_1} ${hold_string_tags_2} ${hold_string_tags_3} hold_string_tags_1 hold_string_tags_2 hold_string_tags_3 ${modbus_rtu_node} Compare Tag Value As Strings "a" "b" "c"
Write a value to a tag that don't exit in plc or neuron, it will be failure.
[Template] Write a ${value} to a ${tag} with named ${tag_name} that don't exist in neuron or plc from ${node}, it will be failure.
12 ${input_bit_1} input ${modbus_rtu_node}
+13
View File
@@ -69,6 +69,13 @@ ${hold_double_decimal} {"name": "hold_double_decimal", "address": "1!400027",
${hold_float_precision} {"name": "hold_float_precision", "address": "1!400030", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_FLOAT}, "precision": 2}
${hold_double_precision} {"name": "hold_double_precision", "address": "1!400040", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_DOUBLE}, "precision": 2}
${hold_int16_1} {"name": "hold_int16_1", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
${hold_int16_2} {"name": "hold_int16_2", "address": "1!400002", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
${hold_int16_3} {"name": "hold_int16_3", "address": "1!400003", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
${hold_string_tags_1} {"name": "hold_string_tags_1", "address": "1!40001.4", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_STRING}}
${hold_string_tags_2} {"name": "hold_string_tags_2", "address": "1!40003.4", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_STRING}}
${hold_string_tags_3} {"name": "hold_string_tags_3", "address": "1!40005.4", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_STRING}}
*** Test Cases ***
Set a node with right settings, it should be success.
[Template] Set a ${node} with right ${node_settings}, it will be success.
@@ -167,6 +174,12 @@ Update a tag with right address and types and attribute, it will be success
${hold_int16} ${hold_int16_address_update} hold_int16 ${modbus_tcp_node} Compare Tag Value As Int 120
${hold_int16} ${hold_int16_type_update} hold_int16 ${modbus_tcp_node} Compare Tag Value As Int 120
Write 3 tags 1 time, it should return success
[Template] Write and Read ${tag_data1}, ${tag_data2} and ${tag_data3} named ${tag1}, ${tag2} and ${tag3} from ${node}, using ${check} to check the ${value1}, ${value2} and ${value3}, it will be success.
${hold_int16_1} ${hold_int16_2} ${hold_int16_3} hold_int16_1 hold_int16_2 hold_int16_3 ${modbus_tcp_node} Compare Tag Value As Int 1 2 3
${coil_bit_1} ${coil_bit_2} ${coil_bit_3} coil_bit_1 coil_bit_2 coil_bit_3 ${modbus_tcp_node} Compare Tag Value As Int 1 0 1
${hold_string_tags_1} ${hold_string_tags_2} ${hold_string_tags_3} hold_string_tags_1 hold_string_tags_2 hold_string_tags_3 ${modbus_tcp_node} Compare Tag Value As Strings "a" "b" "c"
Add a tag with decimal, it should return success
[Template] Add a ${tag} with right address and type and attribute from ${node}, it will be success.
${hold_int16_decimal} ${modbus_tcp_node}
+6
View File
@@ -186,6 +186,12 @@ Write Tags
${res} = Object response body
[RETURN] ${res}[0]
Write 3 Tags 1 Time
[Arguments] ${node} ${group} ${tag1} ${value1} ${tag2} ${value2} ${tag3} ${value3}
POST /api/v2/write/tags {"node": "${node}", "group": "${group}", "tags": [{"tag": "${tag1}", "value": ${value1}}, {"tag": "${tag2}", "value": ${value2}}, {"tag": "${tag3}", "value": ${value3}}]}
${res} = Object response body
[RETURN] ${res}[0]
Add Template
[Arguments] ${name} ${plugin} ${groups}
${data} = Evaluate json.dumps(${groups}) json
+34
View File
@@ -293,3 +293,37 @@ Write and read a ${value} to a ${tag} named ${tag_name} when the ${node} is stop
Check Tag Error As Int ${res}[tags] ${tag_name} ${NEU_ERR_PLUGIN_NOT_RUNNING}
[Teardown] Del Group ${node} group
Write and Read ${tag_data1}, ${tag_data2} and ${tag_data3} named ${tag1}, ${tag2} and ${tag3} from ${node}, using ${check} to check the ${value1}, ${value2} and ${value3}, it will be success.
[Tags] Driver 18
${res}= Add Group ${node} group 100
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res}= Add Tags ${node} group ${tag_data1}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res}= Add Tags ${node} group ${tag_data2}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res}= Add Tags ${node} group ${tag_data3}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Sleep 290ms
${res}= Write 3 Tags 1 Time ${node} group ${tag1} ${value1} ${tag2} ${value2} ${tag3} ${value3}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Sleep 100ms
${res}= Read Tags ${node} group
Check Response Status ${res} 200
Run Keyword ${check} ${res}[tags] ${tag1} ${value1}
Run Keyword ${check} ${res}[tags] ${tag2} ${value2}
Run Keyword ${check} ${res}[tags] ${tag3} ${value3}
[Teardown] Del Group ${node} group
+3 -3
View File
@@ -80,7 +80,7 @@
"name": "Maximum Retry Times",
"name_zh": "最大重试次数",
"description": "The maximum number of retries after a failed attempt to send a read command",
"description_zh": "发送读取指令失败后最大重试次数",
"description_zh": "发送读指令失败后最大重试次数",
"attribute": "required",
"type": "int",
"default": 0,
@@ -93,7 +93,7 @@
"name": "Retry Interval",
"name_zh": "指令重新发送间隔",
"description": "Resend reading instruction interval(ms) after a failed attempt to send a read command",
"description_zh": "发送读取指令失败后重新发送读指令时间间隔,单位为毫秒",
"description_zh": "发送读指令失败后重新发送读指令时间间隔,单位为毫秒",
"attribute": "required",
"type": "int",
"default": 0,
@@ -106,7 +106,7 @@
"name": "Send Interval",
"name_zh": "指令发送间隔",
"description": "Send reading instruction interval(ms)",
"description_zh": "发送读指令时间间隔,单位为毫秒",
"description_zh": "发送指令时间间隔,单位为毫秒",
"attribute": "required",
"type": "int",
"default": 20,
+3 -3
View File
@@ -92,7 +92,7 @@
"name": "Maximum Retry Times",
"name_zh": "最大重试次数",
"description": "The maximum number of retries after a failed attempt to send a read command",
"description_zh": "发送读取指令失败后最大重试次数",
"description_zh": "发送读指令失败后最大重试次数",
"attribute": "required",
"type": "int",
"default": 0,
@@ -105,7 +105,7 @@
"name": "Retry Interval",
"name_zh": "指令重新发送间隔",
"description": "Resend reading instruction interval(ms) after a failed attempt to send a read command",
"description_zh": "发送读取指令失败后重新发送读指令时间间隔,单位为毫秒",
"description_zh": "发送读指令失败后重新发送读指令时间间隔,单位为毫秒",
"attribute": "required",
"type": "int",
"default": 0,
@@ -118,7 +118,7 @@
"name": "Send Interval",
"name_zh": "指令发送间隔",
"description": "Send reading instruction interval(ms)",
"description_zh": "发送读指令时间间隔,单位为毫秒",
"description_zh": "发送指令时间间隔,单位为毫秒",
"attribute": "required",
"type": "int",
"default": 20,
+206 -1
View File
@@ -31,6 +31,9 @@ static __thread uint16_t modbus_read_max_byte = 250;
static int tag_cmp(neu_tag_sort_elem_t *tag1, neu_tag_sort_elem_t *tag2);
static bool tag_sort(neu_tag_sort_t *sort, void *tag, void *tag_to_be_sorted);
static int tag_cmp_write(neu_tag_sort_elem_t *tag1, neu_tag_sort_elem_t *tag2);
static bool tag_sort_write(neu_tag_sort_t *sort, void *tag,
void *tag_to_be_sorted);
int modbus_tag_to_point(const neu_datatag_t *tag, modbus_point_t *point)
{
@@ -165,6 +168,15 @@ int modbus_tag_to_point(const neu_datatag_t *tag, modbus_point_t *point)
return ret;
}
int modbus_write_tag_to_point(const neu_plugin_tag_value_t *tag,
modbus_point_write_t * point)
{
int ret = NEU_ERR_SUCCESS;
ret = modbus_tag_to_point(tag->tag, &point->point);
point->value = tag->value;
return ret;
}
modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte)
{
modbus_read_max_byte = max_byte;
@@ -193,6 +205,112 @@ 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 n = 0;
switch (type) {
case NEU_TYPE_UINT16:
case NEU_TYPE_INT16:
n = sizeof(uint16_t);
value->u16 = htons(value->u16);
break;
case NEU_TYPE_FLOAT:
case NEU_TYPE_UINT32:
case NEU_TYPE_INT32:
n = sizeof(uint32_t);
value->u32 = htonl(value->u32);
break;
case NEU_TYPE_DOUBLE:
case NEU_TYPE_INT64:
case NEU_TYPE_UINT64:
n = sizeof(uint64_t);
value->u64 = neu_htonll(value->u64);
break;
case NEU_TYPE_BIT: {
n = sizeof(uint8_t);
break;
}
case NEU_TYPE_STRING: {
n = option.string.length;
switch (option.string.type) {
case NEU_DATATAG_STRING_TYPE_H:
break;
case NEU_DATATAG_STRING_TYPE_L:
neu_datatag_string_ltoh(value->str, option.string.length);
break;
case NEU_DATATAG_STRING_TYPE_D:
break;
case NEU_DATATAG_STRING_TYPE_E:
break;
}
break;
}
default:
assert(1 == 0);
break;
}
return n;
}
modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags)
{
neu_tag_sort_result_t *result =
neu_tag_sort(tags, tag_sort_write, tag_cmp_write);
modbus_write_cmd_sort_t *sort_result =
calloc(1, sizeof(modbus_write_cmd_sort_t));
sort_result->n_cmd = result->n_sort;
sort_result->cmd = calloc(result->n_sort, sizeof(modbus_write_cmd_t));
for (uint16_t i = 0; i < result->n_sort; i++) {
modbus_point_write_t *tag =
*(modbus_point_write_t **) utarray_front(result->sorts[i].tags);
struct modbus_sort_ctx *ctx = result->sorts[i].info.context;
int num_tags = utarray_len(result->sorts[i].tags);
sort_result->cmd[i].bytes = calloc(num_tags, sizeof(neu_value_u));
int n_byte = 0, n_byte_tag = 0;
uint8_t *data_bit = calloc((num_tags + 7) / 8, sizeof(uint8_t));
int k = 0;
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);
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);
memcpy(sort_result->cmd[i].bytes +
2 *
((*tag_s)->point.start_address -
tag->point.start_address),
&((*tag_s)->value), n_byte_tag);
n_byte += n_byte_tag;
}
}
if ((*(modbus_point_write_t **) utarray_front(result->sorts[i].tags))
->point.area == MODBUS_AREA_COIL) {
memcpy(sort_result->cmd[i].bytes, data_bit, (k + 7) / 8);
}
sort_result->cmd[i].tags = utarray_clone(result->sorts[i].tags);
sort_result->cmd[i].slave_id = tag->point.slave_id;
sort_result->cmd[i].area = tag->point.area;
sort_result->cmd[i].start_address = tag->point.start_address;
sort_result->cmd[i].n_register = ctx->end - ctx->start;
sort_result->cmd[i].n_byte = n_byte;
free(data_bit);
free(result->sorts[i].info.context);
}
neu_tag_sort_free(result);
return sort_result;
}
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs)
{
for (uint16_t i = 0; i < cs->n_cmd; i++) {
@@ -266,7 +384,7 @@ static bool tag_sort(neu_tag_sort_t *sort, void *tag, void *tag_to_be_sorted)
switch (t1->area) {
case MODBUS_AREA_COIL:
case MODBUS_AREA_INPUT:
if ((ctx->end - ctx->start) / 8 >= modbus_read_max_byte - 1) {
if ((ctx->end - ctx->start + 7) / 8 >= modbus_read_max_byte) {
return false;
}
break;
@@ -288,3 +406,90 @@ static bool tag_sort(neu_tag_sort_t *sort, void *tag, void *tag_to_be_sorted)
return true;
}
static int tag_cmp_write(neu_tag_sort_elem_t *tag1, neu_tag_sort_elem_t *tag2)
{
modbus_point_write_t *p_t1 = (modbus_point_write_t *) tag1->tag;
modbus_point_write_t *p_t2 = (modbus_point_write_t *) tag2->tag;
if (p_t1->point.slave_id > p_t2->point.slave_id) {
return 1;
} else if (p_t1->point.slave_id < p_t2->point.slave_id) {
return -1;
}
if (p_t1->point.area > p_t2->point.area) {
return 1;
} else if (p_t1->point.area < p_t2->point.area) {
return -1;
}
if (p_t1->point.start_address > p_t2->point.start_address) {
return 1;
} else if (p_t1->point.start_address < p_t2->point.start_address) {
return -1;
}
if (p_t1->point.n_register > p_t2->point.n_register) {
return 1;
} else if (p_t1->point.n_register < p_t2->point.n_register) {
return -1;
}
return 0;
}
static bool tag_sort_write(neu_tag_sort_t *sort, void *tag,
void *tag_to_be_sorted)
{
modbus_point_write_t * t1 = (modbus_point_write_t *) tag;
modbus_point_write_t * t2 = (modbus_point_write_t *) tag_to_be_sorted;
struct modbus_sort_ctx *ctx = NULL;
if (sort->info.context == NULL) {
sort->info.context = calloc(1, sizeof(struct modbus_sort_ctx));
ctx = (struct modbus_sort_ctx *) sort->info.context;
ctx->start = t1->point.start_address;
ctx->end = t1->point.start_address + t1->point.n_register;
return true;
}
ctx = (struct modbus_sort_ctx *) sort->info.context;
if (t1->point.slave_id != t2->point.slave_id) {
return false;
}
if (t1->point.area != t2->point.area) {
return false;
}
if (t2->point.start_address > ctx->end) {
return false;
}
switch (t1->point.area) {
case MODBUS_AREA_COIL:
case MODBUS_AREA_INPUT:
if ((ctx->end - ctx->start) / 8 >= modbus_read_max_byte - 1) {
return false;
}
break;
case MODBUS_AREA_INPUT_REGISTER:
case MODBUS_AREA_HOLD_REGISTER: {
uint16_t now_bytes = (ctx->end - ctx->start) * 2;
uint16_t add_now = now_bytes + t2->point.n_register * 2;
if (add_now >= modbus_read_max_byte) {
return false;
}
break;
}
}
if (t2->point.start_address + t2->point.n_register > ctx->end) {
ctx->end = t2->point.start_address + t2->point.n_register;
}
return true;
}
+26 -2
View File
@@ -40,7 +40,14 @@ typedef struct modbus_point {
char name[NEU_TAG_NAME_LEN];
} modbus_point_t;
typedef struct modbus_point_write {
modbus_point_t point;
neu_value_u value;
} modbus_point_write_t;
int modbus_tag_to_point(const neu_datatag_t *tag, modbus_point_t *point);
int modbus_write_tag_to_point(const neu_plugin_tag_value_t *tag,
modbus_point_write_t * point);
typedef struct modbus_read_cmd {
uint8_t slave_id;
@@ -56,8 +63,25 @@ typedef struct modbus_read_cmd_sort {
modbus_read_cmd_t *cmd;
} modbus_read_cmd_sort_t;
modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte);
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs);
typedef struct modbus_write_cmd {
uint8_t slave_id;
modbus_area_e area;
uint16_t start_address;
uint16_t n_register;
uint8_t n_byte;
uint8_t * bytes;
UT_array *tags;
} modbus_write_cmd_t;
typedef struct modbus_write_cmd_sort {
uint16_t n_cmd;
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);
#ifdef __cplusplus
}
+79 -3
View File
@@ -29,6 +29,11 @@ struct modbus_group_data {
modbus_read_cmd_sort_t *cmd_sort;
};
struct modbus_write_tags_data {
UT_array * tags;
modbus_write_cmd_sort_t *cmd_sort;
};
static void plugin_group_free(neu_plugin_group_t *pgp);
static int process_protocol_buf(neu_plugin_t *plugin, uint8_t slave_id,
uint16_t response_size);
@@ -445,7 +450,7 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
}
int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value)
neu_value_u value, bool response)
{
modbus_point_t point = { 0 };
int ret = modbus_tag_to_point(tag, &point);
@@ -498,12 +503,83 @@ int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
uint16_t response_size = 0;
ret = modbus_stack_write(plugin->stack, req, point.slave_id, point.area,
point.start_address, point.n_register, value.bytes,
n_byte, &response_size);
n_byte, &response_size, response);
if (ret > 0) {
process_protocol_buf(plugin, point.slave_id, response_size);
}
return 0;
return ret;
}
int modbus_write_tag(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value)
{
int ret = 0;
ret = modbus_write(plugin, req, tag, value, true);
return ret;
}
int modbus_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags)
{
struct modbus_write_tags_data *gtags = NULL;
int ret = 0;
int rv = 0;
gtags = calloc(1, sizeof(struct modbus_write_tags_data));
utarray_new(gtags->tags, &ut_ptr_icd);
utarray_foreach(tags, neu_plugin_tag_value_t *, tag)
{
modbus_point_write_t *p = calloc(1, sizeof(modbus_point_write_t));
ret = modbus_write_tag_to_point(tag, p);
assert(ret == 0);
utarray_push_back(gtags->tags, &p);
}
gtags->cmd_sort = modbus_write_tags_sort(gtags->tags);
for (uint16_t i = 0; i < gtags->cmd_sort->n_cmd; i++) {
uint16_t response_size = 0;
ret = modbus_stack_write(
plugin->stack, req, gtags->cmd_sort->cmd[i].slave_id,
gtags->cmd_sort->cmd[i].area, gtags->cmd_sort->cmd[i].start_address,
gtags->cmd_sort->cmd[i].n_register, gtags->cmd_sort->cmd[i].bytes,
gtags->cmd_sort->cmd[i].n_byte, &response_size, false);
if (ret > 0) {
process_protocol_buf(plugin, gtags->cmd_sort->cmd[i].slave_id,
response_size);
}
if (ret <= 0) {
rv = 1;
}
if (plugin->interval > 0) {
struct timespec t1 = { .tv_sec = plugin->interval / 1000,
.tv_nsec = 1000 * 1000 *
(plugin->interval % 1000) };
struct timespec t2 = { 0 };
nanosleep(&t1, &t2);
}
}
if (rv == 0) {
plugin->common.adapter_callbacks->driver.write_response(
plugin->common.adapter, req, NEU_ERR_SUCCESS);
} else {
plugin->common.adapter_callbacks->driver.write_response(
plugin->common.adapter, req, NEU_ERR_PLUGIN_DISCONNECTED);
}
for (uint16_t i = 0; i < gtags->cmd_sort->n_cmd; i++) {
utarray_free(gtags->cmd_sort->cmd[i].tags);
free(gtags->cmd_sort->cmd[i].bytes);
}
free(gtags->cmd_sort->cmd);
free(gtags->cmd_sort);
utarray_foreach(gtags->tags, modbus_point_write_t **, tag) { free(*tag); }
utarray_free(gtags->tags);
free(gtags);
return ret;
}
int modbus_write_resp(void *ctx, void *req, int error)
+4 -1
View File
@@ -58,7 +58,10 @@ int modbus_send_msg(void *ctx, uint16_t n_byte, uint8_t *bytes);
int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
uint8_t *bytes, int error);
int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value);
neu_value_u value, bool response);
int modbus_write_tag(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value);
int modbus_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags);
int modbus_write_resp(void *ctx, void *req, int error);
#endif
+8 -2
View File
@@ -42,6 +42,7 @@ static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag);
static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group);
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value);
static int driver_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags);
static const neu_plugin_intf_funs_t plugin_intf_funs = {
.open = driver_open,
@@ -57,7 +58,7 @@ static const neu_plugin_intf_funs_t plugin_intf_funs = {
.driver.group_timer = driver_group_timer,
.driver.write_tag = driver_write,
.driver.tag_validator = driver_tag_validator,
.driver.write_tags = NULL,
.driver.write_tags = driver_write_tags,
.driver.add_tags = NULL,
.driver.load_tags = NULL,
.driver.del_tags = NULL,
@@ -316,5 +317,10 @@ static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value)
{
return modbus_write(plugin, req, tag, value);
return modbus_write_tag(plugin, req, tag, value);
}
static int driver_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags)
{
return modbus_write_tags(plugin, req, tags);
}
+24 -12
View File
@@ -225,7 +225,7 @@ int modbus_stack_read(modbus_stack_t *stack, uint8_t slave_id,
int modbus_stack_write(modbus_stack_t *stack, void *req, uint8_t slave_id,
enum modbus_area area, uint16_t start_address,
uint16_t n_reg, uint8_t *bytes, uint8_t n_byte,
uint16_t *response_size)
uint16_t *response_size, bool response)
{
static __thread neu_protocol_pack_buf_t pbuf = { 0 };
modbus_action_e m_action = MODBUS_ACTION_DEFAULT;
@@ -239,13 +239,21 @@ int modbus_stack_write(modbus_stack_t *stack, void *req, uint8_t slave_id,
switch (area) {
case MODBUS_AREA_COIL:
if (*bytes > 0) {
modbus_address_wrap(&pbuf, start_address, 0xff00, m_action);
if (n_byte > 1) {
n_reg = n_byte;
modbus_data_wrap(&pbuf, (n_byte + 7) / 8, bytes, m_action);
modbus_address_wrap(&pbuf, start_address, n_reg, m_action);
modbus_code_wrap(&pbuf, slave_id, MODBUS_WRITE_M_COIL);
break;
} else {
modbus_address_wrap(&pbuf, start_address, 0, m_action);
if (*bytes > 0) {
modbus_address_wrap(&pbuf, start_address, 0xff00, m_action);
} else {
modbus_address_wrap(&pbuf, start_address, 0, m_action);
}
modbus_code_wrap(&pbuf, slave_id, MODBUS_WRITE_S_COIL);
break;
}
modbus_code_wrap(&pbuf, slave_id, MODBUS_WRITE_S_COIL);
break;
case MODBUS_AREA_HOLD_REGISTER:
m_action = MODBUS_ACTION_HOLD_REG_WRITE;
modbus_data_wrap(&pbuf, n_byte, bytes, m_action);
@@ -275,13 +283,17 @@ int modbus_stack_write(modbus_stack_t *stack, void *req, uint8_t slave_id,
int ret = stack->send_fn(stack->ctx, neu_protocol_pack_buf_used_size(&pbuf),
neu_protocol_pack_buf_get(&pbuf));
if (ret > 0) {
stack->write_resp(stack->ctx, req, NEU_ERR_SUCCESS);
plog_notice((neu_plugin_t *) stack->ctx, "send write req, %hhu!%hu",
slave_id, start_address);
if (response) {
stack->write_resp(stack->ctx, req, NEU_ERR_SUCCESS);
plog_notice((neu_plugin_t *) stack->ctx, "send write req, %hhu!%hu",
slave_id, start_address);
}
} else {
stack->write_resp(stack->ctx, req, NEU_ERR_PLUGIN_DISCONNECTED);
plog_warn((neu_plugin_t *) stack->ctx, "send write req fail, %hhu!%hu",
slave_id, start_address);
if (response) {
stack->write_resp(stack->ctx, req, NEU_ERR_PLUGIN_DISCONNECTED);
plog_warn((neu_plugin_t *) stack->ctx,
"send write req fail, %hhu!%hu", slave_id, start_address);
}
}
return ret;
}
+1 -1
View File
@@ -52,7 +52,7 @@ int modbus_stack_read(modbus_stack_t *stack, uint8_t slave_id,
int modbus_stack_write(modbus_stack_t *stack, void *req, uint8_t slave_id,
enum modbus_area area, uint16_t start_address,
uint16_t n_reg, uint8_t *bytes, uint8_t n_byte,
uint16_t *response_size);
uint16_t *response_size, bool response);
bool modbus_stack_is_rtu(modbus_stack_t *stack);
#endif
+14 -4
View File
@@ -42,6 +42,7 @@ static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag);
static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group);
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value);
static int driver_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags);
static const neu_plugin_intf_funs_t plugin_intf_funs = {
.open = driver_open,
@@ -57,7 +58,7 @@ static const neu_plugin_intf_funs_t plugin_intf_funs = {
.driver.group_timer = driver_group_timer,
.driver.write_tag = driver_write,
.driver.tag_validator = driver_tag_validator,
.driver.write_tags = NULL,
.driver.write_tags = driver_write_tags,
.driver.add_tags = NULL,
.driver.load_tags = NULL,
.driver.del_tags = NULL,
@@ -148,7 +149,9 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
char * err_param = NULL;
neu_json_elem_t port = { .name = "port", .t = NEU_JSON_INT };
neu_json_elem_t timeout = { .name = "timeout", .t = NEU_JSON_INT };
neu_json_elem_t host = { .name = "host", .t = NEU_JSON_STR };
neu_json_elem_t host = { .name = "host",
.t = NEU_JSON_STR,
.v.val_str = NULL };
neu_json_elem_t interval = { .name = "interval", .t = NEU_JSON_INT };
neu_json_elem_t mode = { .name = "connection_mode", .t = NEU_JSON_INT };
neu_json_elem_t tmode = { .name = "transport_mode", .t = NEU_JSON_INT };
@@ -163,7 +166,9 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
if (ret != 0) {
plog_error(plugin, "config: %s, decode error: %s", config, err_param);
free(err_param);
free(host.v.val_str);
if (host.v.val_str != NULL) {
free(host.v.val_str);
}
return -1;
}
@@ -279,5 +284,10 @@ static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value)
{
return modbus_write(plugin, req, tag, value);
return modbus_write_tag(plugin, req, tag, value);
}
static int driver_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags)
{
return modbus_write_tags(plugin, req, tags);
}