diff --git a/plugins/modbus/modbus_point.c b/plugins/modbus/modbus_point.c index 817aba0c..1556a15d 100644 --- a/plugins/modbus/modbus_point.c +++ b/plugins/modbus/modbus_point.c @@ -111,10 +111,15 @@ int modbus_tag_to_point(const neu_datatag_t *tag, modbus_point_t *point) switch (point->type) { case NEU_TYPE_BIT: + case NEU_TYPE_BOOL: + case NEU_TYPE_INT8: + case NEU_TYPE_UINT8: + case NEU_TYPE_PTR: point->n_register = 1; break; case NEU_TYPE_UINT16: case NEU_TYPE_INT16: + case NEU_TYPE_WORD: if (point->area == MODBUS_AREA_COIL || point->area == MODBUS_AREA_INPUT) { ret = NEU_ERR_TAG_TYPE_NOT_SUPPORT; @@ -125,6 +130,9 @@ int modbus_tag_to_point(const neu_datatag_t *tag, modbus_point_t *point) case NEU_TYPE_UINT32: case NEU_TYPE_INT32: case NEU_TYPE_FLOAT: + case NEU_TYPE_DWORD: + case NEU_TYPE_TIME: + case NEU_TYPE_DATA_AND_TIME: if (point->area == MODBUS_AREA_COIL || point->area == MODBUS_AREA_INPUT) { ret = NEU_ERR_TAG_TYPE_NOT_SUPPORT; @@ -135,6 +143,7 @@ int modbus_tag_to_point(const neu_datatag_t *tag, modbus_point_t *point) case NEU_TYPE_UINT64: case NEU_TYPE_INT64: case NEU_TYPE_DOUBLE: + case NEU_TYPE_LWORD: if (point->area == MODBUS_AREA_COIL || point->area == MODBUS_AREA_INPUT) { ret = NEU_ERR_TAG_TYPE_NOT_SUPPORT; diff --git a/src/parser/neu_json_group_config.c b/src/parser/neu_json_group_config.c index 21034020..61fba977 100644 --- a/src/parser/neu_json_group_config.c +++ b/src/parser/neu_json_group_config.c @@ -234,19 +234,6 @@ int neu_json_encode_get_driver_group_resp(void *json_object, void *param) return ret; } -int neu_json_decode_get_driver_group_resp( - char *buf, neu_json_get_driver_group_resp_t **result) -{ - json_t *json_obj = neu_json_decode_new(buf); - if (NULL == json_obj) { - return -1; - } - - int ret = neu_json_decode_get_driver_group_resp_json(json_obj, result); - neu_json_decode_free(json_obj); - return ret; -} - int neu_json_decode_get_driver_group_resp_json( void *json_obj, neu_json_get_driver_group_resp_t **result) { @@ -684,11 +671,6 @@ void neu_json_decode_subscribe_groups_req_free( neu_json_subscribe_groups_req_t *req) { if (req) { - free(req->app); - for (int i = 0; i < req->n_group; ++i) { - neu_json_decode_subscribe_groups_info_fini(&req->groups[i]); - } - free(req->groups); free(req); } } diff --git a/src/parser/neu_json_group_config.h b/src/parser/neu_json_group_config.h index 55881c24..379ed802 100644 --- a/src/parser/neu_json_group_config.h +++ b/src/parser/neu_json_group_config.h @@ -91,8 +91,6 @@ typedef struct { } neu_json_get_driver_group_resp_t; int neu_json_encode_get_driver_group_resp(void *json_object, void *param); -int neu_json_decode_get_driver_group_resp( - char *buf, neu_json_get_driver_group_resp_t **result); int neu_json_decode_get_driver_group_resp_json( void *json_obj, neu_json_get_driver_group_resp_t **result); void neu_json_decode_get_driver_group_resp_free( diff --git a/tests/ft/app/test_app.py b/tests/ft/app/test_app.py index 78ac7eaa..7224a5c1 100644 --- a/tests/ft/app/test_app.py +++ b/tests/ft/app/test_app.py @@ -124,6 +124,13 @@ class TestDriver: assert 200 == response.status_code assert error.NEU_ERR_SUCCESS == response.json()['error'] + @description(given="mqtt node", when="subscribe with err body", then="subscribe failed") + def test_mqtt_sub_err(self): + response = api.subscribe_groups(app='mqtt-1', groups=[{"driver": "modbus-tcp-1", "group": "group-1", "params":{"topic":"/neuron"}}, + {"driver": "modbus-tcp-1", "group": "group-2"}, + {"driver": "modbus-tcp-1", "err": "group-3"}]) + assert 400 == response.status_code + @description(given="mqtt node", when="subscribe/unsubscribe modbus group", then="return correct sub_group_count in node state") def test_mqtt_sub_group_count(self): response = api.get_nodes_state(node='mqtt-1') diff --git a/tests/ft/driver/test_modbus.py b/tests/ft/driver/test_modbus.py index d447fc1d..96ad4123 100644 --- a/tests/ft/driver/test_modbus.py +++ b/tests/ft/driver/test_modbus.py @@ -472,7 +472,10 @@ class TestModbus: api.add_tags_check(node=param[0], group='group', tags=hold_double_s) api.add_tags_check(node=param[0], group='group', tags=hold_string_s) - time.sleep(0.3) + time.sleep(0.5) + + response = api.get_tags(node=param[0], group="group") + assert 200 == response.status_code assert 1 == api.read_tag(node=param[0], group='group', tag=hold_int16_s[0]['name']) assert 1 == api.read_tag(node=param[0], group='group', tag=hold_uint16_s[0]['name']) diff --git a/tests/ft/neuron/config.py b/tests/ft/neuron/config.py index 6130ec6f..528e65a2 100644 --- a/tests/ft/neuron/config.py +++ b/tests/ft/neuron/config.py @@ -42,6 +42,7 @@ NEU_TYPE_ERROR = 15 NEU_TYPE_WORD = 16 NEU_TYPE_DWORD = 17 NEU_TYPE_LWORD = 18 +NEU_TYPE_PTR = 19 NEU_TYPE_TIME = 20 NEU_TYPE_DATA_AND_TIME = 21 diff --git a/tests/ft/persist/test_persist.py b/tests/ft/persist/test_persist.py index 0dd625aa..2cb1a74f 100644 --- a/tests/ft/persist/test_persist.py +++ b/tests/ft/persist/test_persist.py @@ -5,6 +5,7 @@ import neuron.process as process from neuron.error import * import shutil import os +import time hold_bit = [{"name": "hold_bit", "address": "1!400001.15", "attribute": NEU_TAG_ATTRIBUTE_READ_SUBSCRIBE, "type": NEU_TYPE_BIT}] @@ -15,6 +16,25 @@ hold_uint16 = [{"name": "hold_uint16", "address": "1!400002", hold_int16_to_int32 = [{"name": "hold_int16", "address": "1!400002", "attribute": NEU_TAG_ATTRIBUTE_RW, "type": NEU_TYPE_INT32}] +hold_int8 = [{"name": "hold_int8", "address": "1!400001", + "attribute": NEU_TAG_ATTRIBUTE_WRITE, "type": NEU_TYPE_INT8}] +hold_uint8 = [{"name": "hold_uint8", "address": "1!400001", + "attribute": NEU_TAG_ATTRIBUTE_WRITE, "type": NEU_TYPE_UINT8}] +hold_bool = [{"name": "hold_bool", "address": "1!400001.15", + "attribute": NEU_TAG_ATTRIBUTE_WRITE, "type": NEU_TYPE_BOOL}] +hold_word = [{"name": "hold_word", "address": "1!400001", + "attribute": NEU_TAG_ATTRIBUTE_WRITE, "type": NEU_TYPE_WORD}] +hold_dword = [{"name": "hold_dword", "address": "1!400001", + "attribute": NEU_TAG_ATTRIBUTE_WRITE, "type": NEU_TYPE_DWORD}] +hold_lword = [{"name": "hold_lword", "address": "1!400001", + "attribute": NEU_TAG_ATTRIBUTE_WRITE, "type": NEU_TYPE_LWORD}] +hold_ptr = [{"name": "hold_ptr", "address": "1!400001", + "attribute": NEU_TAG_ATTRIBUTE_WRITE, "type": NEU_TYPE_PTR}] +hold_dt = [{"name": "hold_dt", "address": "1!400001", + "attribute": NEU_TAG_ATTRIBUTE_WRITE, "type": NEU_TYPE_DATA_AND_TIME}] +hold_t = [{"name": "hold_t", "address": "1!400001", + "attribute": NEU_TAG_ATTRIBUTE_WRITE, "type": NEU_TYPE_TIME}] + class TestPersist: @@ -456,4 +476,42 @@ class TestPersist: shutil.rmtree('./build/certs/') - p.stop() \ No newline at end of file + p.stop() + + @description(given="new schema", when="upload schema , restart and add tags", then="success") + def test_all_datatag_type(self): + process.remove_persistence() + dst_file = './build/plugins/schema/modbus-tcp.json' + dst_backup = dst_file + '_backup' + os.rename(dst_file, dst_backup) + + try: + shutil.copy2('./tests/ft/tag/modbus-tcp.json', dst_file) + except Exception as e: + if os.path.exists(dst_backup): + os.rename(dst_backup, dst_file) + return + + p = process.NeuronProcess() + p.start() + + api.add_node_check(node="modbus-tcp-1", plugin=PLUGIN_MODBUS_TCP) + api.add_group_check(node='modbus-tcp-1', group='group-tag', interval=1000) + + api.add_tags(node='modbus-tcp-1', group='group-tag', tags=hold_int8) + api.add_tags(node='modbus-tcp-1', group='group-tag', tags=hold_uint8) + api.add_tags(node='modbus-tcp-1', group='group-tag', tags=hold_bool) + api.add_tags(node='modbus-tcp-1', group='group-tag', tags=hold_word) + api.add_tags(node='modbus-tcp-1', group='group-tag', tags=hold_dword) + api.add_tags(node='modbus-tcp-1', group='group-tag', tags=hold_lword) + api.add_tags(node='modbus-tcp-1', group='group-tag', tags=hold_ptr) + api.add_tags(node='modbus-tcp-1', group='group-tag', tags=hold_dt) + api.add_tags(node='modbus-tcp-1', group='group-tag', tags=hold_t) + + response = api.del_group(node="modbus-tcp-1", group='group-tag') + assert 200 == response.status_code + + p.stop() + + os.remove(dst_file) + os.rename(dst_backup, dst_file) \ No newline at end of file diff --git a/tests/ft/tag/modbus-tcp.json b/tests/ft/tag/modbus-tcp.json new file mode 100644 index 00000000..fd2540a5 --- /dev/null +++ b/tests/ft/tag/modbus-tcp.json @@ -0,0 +1,179 @@ +{ + "tag_regex": [ + { + "type": 1, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 2, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 3, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 4, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 5, + "regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$" + }, + { + "type": 6, + "regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$" + }, + { + "type": 7, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 8, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 9, + "regex": "^[0-9]+![3-4][0-9]+(#BB|#BL|#LL|#LB|)$" + }, + { + "type": 10, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 11, + "regex": "^[0-9]+!([0-1][0-9]+|[3-4][0-9]+\\.([0-9]|[0-1][0-5]))$" + }, + { + "type": 12, + "regex": "^[0-9]+!([0-1][0-9]+|[3-4][0-9]+\\.([0-9]|[0-1][0-5]))$" + }, + { + "type": 13, + "regex": "^[0-9]+![3-4][0-9]+\\.[0-9]+(H|L|)$" + }, + { + "type": 14, + "regex": "^[0-9]+![3-4][0-9]+\\.[0-9]+$" + }, + { + "type": 16, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 17, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 18, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 19, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 20, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + }, + { + "type": 21, + "regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$" + } + ], + "group_interval": 1000, + "connection_mode": { + "name": "Connection Mode", + "name_zh": "连接模式", + "description": "Neuron as the client, or as the server", + "description_zh": "Neuron 作为客户端或服务端", + "attribute": "required", + "type": "map", + "default": 0, + "valid": { + "map": [ + { + "key": "Client", + "value": 0 + }, + { + "key": "Server", + "value": 1 + } + ] + } + }, + "max_retries": { + "name": "Maximum Retry Times", + "name_zh": "最大重试次数", + "description": "The maximum number of retries after a failed attempt to send a read command", + "description_zh": "发送读指令失败后最大重试次数", + "attribute": "required", + "type": "int", + "default": 0, + "valid": { + "min": 0, + "max": 3 + } + }, + "retry_interval": { + "name": "Retry Interval", + "name_zh": "指令重新发送间隔", + "description": "Resend reading instruction interval(ms) after a failed attempt to send a read command", + "description_zh": "发送读指令失败后重新发送读指令时间间隔,单位为毫秒", + "attribute": "required", + "type": "int", + "default": 0, + "valid": { + "min": 0, + "max": 10000 + } + }, + "interval": { + "name": "Send Interval", + "name_zh": "指令发送间隔", + "description": "Send reading instruction interval(ms)", + "description_zh": "发送指令时间间隔,单位为毫秒", + "attribute": "required", + "type": "int", + "default": 20, + "valid": { + "min": 0, + "max": 3000 + } + }, + "host": { + "name": "IP Address", + "name_zh": "IP地址", + "description": "Local IP in server mode, remote device IP in client mode", + "description_zh": "服务端模式中填写本地 IP,客户端模式中填写目标设备 IP", + "attribute": "required", + "type": "string" + }, + "port": { + "name": "Port", + "name_zh": "端口号", + "description": "Local port in server mode, remote device port in client mode", + "description_zh": "服务端模式中填写本地端口号,客户端模式中填写远程设备端口号", + "attribute": "required", + "type": "int", + "default": 502, + "valid": { + "min": 1, + "max": 65535 + } + }, + "timeout": { + "name": "Connection Timeout", + "name_zh": "连接超时时间", + "description": "Connection timeout(ms)", + "description_zh": "连接超时时间,单位为毫秒", + "attribute": "required", + "type": "int", + "default": 3000, + "valid": { + "min": 1000, + "max": 65535 + } + } +} \ No newline at end of file