diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e7f11df..8d0d4a4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,6 +147,8 @@ file(COPY ${CMAKE_SOURCE_DIR}/default_plugins.json DESTINATION ${CMAKE_BINARY_DI add_subdirectory(plugins/modbus) add_subdirectory(plugins/mqtt) add_subdirectory(plugins/ekuiper) +add_subdirectory(plugins/file) + add_subdirectory(simulator) diff --git a/plugins/file/CMakeLists.txt b/plugins/file/CMakeLists.txt new file mode 100644 index 00000000..0dc1ebb6 --- /dev/null +++ b/plugins/file/CMakeLists.txt @@ -0,0 +1,11 @@ +set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/plugins") + +set(CMAKE_BUILD_RPATH ./) +file(COPY ${CMAKE_SOURCE_DIR}/plugins/file/file.json DESTINATION ${CMAKE_BINARY_DIR}/plugins/schema/) + +set(PLUGIN_NAME plugin-file) +set(PLUGIN_SOURCES file_plugin.c file_req.c) +add_library(${PLUGIN_NAME} SHARED) +target_include_directories(${PLUGIN_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include/neuron) +target_sources(${PLUGIN_NAME} PRIVATE ${PLUGIN_SOURCES}) +target_link_libraries(${PLUGIN_NAME} neuron-base) \ No newline at end of file diff --git a/plugins/file/file.json b/plugins/file/file.json new file mode 100644 index 00000000..fb713cb5 --- /dev/null +++ b/plugins/file/file.json @@ -0,0 +1,18 @@ +{ + "tag_regex": [ + { + "type": 13, + "regex": "" + } + ], + "file_length": { + "name": "file_length", + "description": "", + "attribute": "required", + "type": "int", + "default": 512, + "valid": { + "min": 1 + } + } +} \ No newline at end of file diff --git a/plugins/file/file_plugin.c b/plugins/file/file_plugin.c new file mode 100644 index 00000000..7e14b081 --- /dev/null +++ b/plugins/file/file_plugin.c @@ -0,0 +1,155 @@ +/** + * NEURON IIoT System for Industry 4.0 + * Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **/ + +#include "file_req.h" + +static neu_plugin_t *driver_open(void); + +static int driver_close(neu_plugin_t *plugin); +static int driver_init(neu_plugin_t *plugin); +static int driver_uninit(neu_plugin_t *plugin); +static int driver_start(neu_plugin_t *plugin); +static int driver_stop(neu_plugin_t *plugin); +static int driver_config(neu_plugin_t *plugin, const char *config); +static int driver_request(neu_plugin_t *plugin, neu_reqresp_head_t *head, + void *data); + +static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group); +static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag); +static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag, + neu_value_u value); + +static const neu_plugin_intf_funs_t plugin_intf_funs = { + .open = driver_open, + .close = driver_close, + .init = driver_init, + .uninit = driver_uninit, + .start = driver_start, + .stop = driver_stop, + .setting = driver_config, + .request = driver_request, + + .driver.validate_tag = driver_validate_tag, + .driver.group_timer = driver_group_timer, + .driver.write_tag = driver_write, +}; + +const neu_plugin_module_t neu_plugin_module = { + .version = NEURON_PLUGIN_VER_1_0, + .module_name = "file", + .module_descr = "The plugin is used to read and write files.", + .module_descr_zh = "该插件用于读写文件。", + .intf_funs = &plugin_intf_funs, + .kind = NEU_PLUGIN_KIND_SYSTEM, + .type = NEU_NA_TYPE_DRIVER, + .display = true, + .single = false, +}; + +static neu_plugin_t *driver_open(void) +{ + neu_plugin_t *plugin = calloc(1, sizeof(neu_plugin_t)); + + neu_plugin_common_init(&plugin->common); + + return plugin; +} + +static int driver_close(neu_plugin_t *plugin) +{ + free(plugin); + + return 0; +} + +static int driver_init(neu_plugin_t *plugin) +{ + plugin->events = neu_event_new(); + plugin->common.link_state = NEU_NODE_LINK_STATE_CONNECTED; + + return 0; +} + +static int driver_uninit(neu_plugin_t *plugin) +{ + neu_event_close(plugin->events); + plog_info(plugin, "node; file uininit ok"); + + return 0; +} + +static int driver_start(neu_plugin_t *plugin) +{ + (void) plugin; + + return 0; +} + +static int driver_stop(neu_plugin_t *plugin) +{ + (void) plugin; + + return 0; +} + +static int driver_config(neu_plugin_t *plugin, const char *config) +{ + char * err_param = NULL; + neu_json_elem_t file_length = { .name = "file_length", .t = NEU_JSON_INT }; + + int ret = neu_parse_param((char *) config, &err_param, 1, &file_length); + if (ret != 0) { + plog_warn(plugin, "config:%s, decode error: %s", config, err_param); + free(err_param); + return -1; + } + + plugin->file_length = file_length.v.val_int; + + return 0; +} + +static int driver_request(neu_plugin_t *plugin, neu_reqresp_head_t *head, + void *data) +{ + (void) plugin; + (void) head; + (void) data; + + return 0; +} + +static int driver_validate_tag(neu_plugin_t *plugin, neu_datatag_t *tag) +{ + plog_debug(plugin, "validate tag success, name:%s, address:%s,type:%d ", + tag->name, tag->address, tag->type); + + return 0; +} + +static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group) +{ + return file_group_timer(plugin, group); +} + +static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag, + neu_value_u value) +{ + return file_write(plugin, req, tag, value); +} diff --git a/plugins/file/file_req.c b/plugins/file/file_req.c new file mode 100644 index 00000000..49459d39 --- /dev/null +++ b/plugins/file/file_req.c @@ -0,0 +1,128 @@ +/** + * NEURON IIoT System for Industry 4.0 + * Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **/ + +#include +#include +#include + +#include "file_req.h" + +struct file_group_data { + UT_array *tags; + char * group; +}; + +static void plugin_group_free(neu_plugin_group_t *pgp); + +int file_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group) +{ + struct file_group_data *gd = NULL; + int length = plugin->file_length; + + if (group->user_data == NULL) { + gd = calloc(1, sizeof(struct file_group_data)); + group->user_data = gd; + group->group_free = plugin_group_free; + utarray_new(gd->tags, &ut_ptr_icd); + + gd->group = strdup(group->group_name); + } + + utarray_foreach(group->tags, neu_datatag_t *, tag) + { + FILE * f = NULL; + struct stat st = { 0 }; + char * buf = calloc(1, length); + neu_dvalue_t dvalue = { 0 }; + + if (stat(tag->address, &st) != 0) { + dvalue.type = NEU_TYPE_ERROR; + dvalue.value.i32 = NEU_ERR_FILE_NOT_EXIST; + goto dvalue_result; + } + if ((f = fopen(tag->address, "rb+")) == NULL) { + nlog_error("open file:%s", tag->address); + dvalue.type = NEU_TYPE_ERROR; + dvalue.value.i32 = NEU_ERR_PLUGIN_READ_FAILURE; + goto dvalue_result; + } + + int ret = fread(buf, sizeof(char), length, f); + if (ret == 0) { + nlog_error("read file failed:%s", tag->address); + dvalue.type = NEU_TYPE_ERROR; + dvalue.value.i32 = NEU_ERR_PLUGIN_READ_FAILURE; + goto dvalue_result; + } + + fseek(f, 0, SEEK_END); + int size = ftell(f); + if (size > length) { + dvalue.type = NEU_TYPE_ERROR; + dvalue.value.i32 = NEU_ERR_PLUGIN_READ_FAILURE; + goto dvalue_result; + } + + dvalue.type = NEU_TYPE_STRING; + strncpy(dvalue.value.str, buf, strlen(buf)); + fclose(f); + + dvalue_result: + plugin->common.adapter_callbacks->driver.update( + plugin->common.adapter, group->group_name, tag->name, dvalue); + + free(buf); + } + + return 0; +} + +static void plugin_group_free(neu_plugin_group_t *pgp) +{ + struct file_group_data *gd = (struct file_group_data *) pgp->user_data; + + utarray_foreach(gd->tags, neu_datatag_t **, tag) { free(*tag); } + + utarray_free(gd->tags); + free(gd->group); + + free(gd); +} + +int file_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag, + neu_value_u value) +{ + FILE *fp = fopen(tag->address, "w"); + int ret = 0; + + if (0 == fwrite(value.str, sizeof(char), strlen(value.str), fp)) { + nlog_error("write file failed:%s", tag->address); + ret = NEU_ERR_PLUGIN_WRITE_FAILURE; + goto dvalue_result; + } + + neu_datatag_string_ltoh(value.str, strlen(value.str)); + +dvalue_result: + fclose(fp); + plugin->common.adapter_callbacks->driver.write_response( + plugin->common.adapter, req, ret); + + return 0; +} \ No newline at end of file diff --git a/plugins/file/file_req.h b/plugins/file/file_req.h new file mode 100644 index 00000000..ffdf34ce --- /dev/null +++ b/plugins/file/file_req.h @@ -0,0 +1,37 @@ +/** + * NEURON IIoT System for Industry 4.0 + * Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + **/ + +#ifndef _NEU_M_PLUGIN_file_REQ_H_ +#define _NEU_M_PLUGIN_file_REQ_H_ + +#include + +struct neu_plugin { + neu_plugin_common_t common; + + neu_events_t *events; + + int file_length; +}; + +int file_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group); +int file_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag, + neu_value_u value); + +#endif \ No newline at end of file