diff --git a/APP_Framework/Applications/Makefile b/APP_Framework/Applications/Makefile index 8c92833cd..118c80ac5 100644 --- a/APP_Framework/Applications/Makefile +++ b/APP_Framework/Applications/Makefile @@ -2,7 +2,7 @@ include $(KERNEL_ROOT)/.config ifeq ($(CONFIG_ADD_NUTTX_FETURES),y) include $(APPDIR)/Make.defs - CSRCS += framework_init.c + CSRCS += include $(APPDIR)/Application.mk endif @@ -10,7 +10,7 @@ endif ifeq ($(CONFIG_ADD_XIZI_FETURES),y) SRC_DIR := general_functions app_test - SRC_FILES := main.c framework_init.c + SRC_FILES := main.c ifeq ($(CONFIG_LIB_LV),y) SRC_DIR += lv_app endif diff --git a/APP_Framework/Applications/general_functions/Makefile b/APP_Framework/Applications/general_functions/Makefile index 57265e81c..564fc2a05 100644 --- a/APP_Framework/Applications/general_functions/Makefile +++ b/APP_Framework/Applications/general_functions/Makefile @@ -1,3 +1,3 @@ -SRC_DIR := list +SRC_DIR := list circular_area include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/APP_Framework/Applications/general_functions/circular_area/Makefile b/APP_Framework/Applications/general_functions/circular_area/Makefile new file mode 100644 index 000000000..30616891b --- /dev/null +++ b/APP_Framework/Applications/general_functions/circular_area/Makefile @@ -0,0 +1,11 @@ +include $(KERNEL_ROOT)/.config +ifeq ($(CONFIG_ADD_NUTTX_FETURES),y) + include $(APPDIR)/Make.defs + CSRCS += circular_area_app.c + include $(APPDIR)/Application.mk +endif + +ifeq ($(CONFIG_ADD_XIZI_FETURES),y) + SRC_FILES := circular_area_app.c + include $(KERNEL_ROOT)/compiler.mk +endif \ No newline at end of file diff --git a/APP_Framework/Applications/general_functions/circular_area/SConscript b/APP_Framework/Applications/general_functions/circular_area/SConscript new file mode 100644 index 000000000..0268174f0 --- /dev/null +++ b/APP_Framework/Applications/general_functions/circular_area/SConscript @@ -0,0 +1,11 @@ +import os +from building import * +Import('RTT_ROOT') +Import('rtconfig') +cwd = GetCurrentDir() +DEPENDS = [""] + +SOURCES = ['circular_area_app.c'] +path = [cwd] +objs = DefineGroup('circular_area', src = SOURCES, depend = DEPENDS,CPPPATH = path) +Return("objs") \ No newline at end of file diff --git a/APP_Framework/Applications/general_functions/circular_area/circular_area_app.c b/APP_Framework/Applications/general_functions/circular_area/circular_area_app.c new file mode 100644 index 000000000..25e81c39c --- /dev/null +++ b/APP_Framework/Applications/general_functions/circular_area/circular_area_app.c @@ -0,0 +1,281 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: circular_area_app.c +* @brief: circular area file for applications +* @version: 3.0 +* @author: AIIT XUOS Lab +* @date: 2022/11/21 +* +*/ + +#include "circular_area_app.h" + +/** + * This function will return whether the circular_area is full or not + * + * @param circular_area CircularAreaApp descriptor + */ +int CircularAreaAppIsFull(CircularAreaAppType circular_area) +{ + CA_PARAM_CHECK(circular_area); + + if((circular_area->readidx == circular_area->writeidx) && (circular_area->b_status)) { + printf("the circular area is full\n"); + return 1; + } else { + return 0; + } +} + +/** + * This function will return whether the circular_area is empty or not + * + * @param circular_area CircularAreaApp descriptor + */ +int CircularAreaAppIsEmpty(CircularAreaAppType circular_area) +{ + CA_PARAM_CHECK(circular_area); + + if((circular_area->readidx == circular_area->writeidx) && (!circular_area->b_status)) { + printf("the circular area is empty\n"); + return 1; + } else { + return 0; + } +} + +/** + * This function will reset the circular_area and set the descriptor to default + * + * @param circular_area CircularAreaApp descriptor + */ +void CircularAreaAppReset(CircularAreaAppType circular_area) +{ + circular_area->writeidx = 0; + circular_area->readidx = 0; + circular_area->b_status = 0; +} + +/** + * This function will release the circular_area descriptor and free the memory + * + * @param circular_area CircularAreaApp descriptor + */ +void CircularAreaAppRelease(CircularAreaAppType circular_area) +{ + circular_area->readidx = 0; + circular_area->writeidx = 0; + circular_area->p_head = NULL; + circular_area->p_tail = NULL; + circular_area->b_status = 0; + circular_area->area_length = 0; + + PrivFree(circular_area->data_buffer); + PrivFree(circular_area); +} + +/** + * This function will get the circual_area max length + * + * @param circular_area CircularAreaApp descriptor + */ +uint32_t CircularAreaAppGetMaxLength(CircularAreaAppType circular_area) +{ + CA_PARAM_CHECK(circular_area); + + return circular_area->area_length; +} + +/** + * This function will get the data length of the circular_area + * + * @param circular_area CircularAreaApp descriptor + */ +uint32_t CircularAreaAppGetDataLength(CircularAreaAppType circular_area) +{ + CA_PARAM_CHECK(circular_area); + + if(CircularAreaAppIsFull(circular_area)) { + return circular_area->area_length; + } else { + return (circular_area->writeidx - circular_area->readidx + circular_area->area_length) % circular_area->area_length; + } +} + +/** + * This function will return whether it is need to divide the read data into two parts or not + * + * @param circular_area CircularAreaApp descriptor + * @param data_length output data length + */ +static uint32_t CircularAreaAppDivideRdData(CircularAreaAppType circular_area, uint32_t data_length) +{ + CA_PARAM_CHECK(circular_area); + + if(circular_area->readidx + data_length <= circular_area->area_length) { + return 0; + } else { + return 1; + } +} + +/** + * This function will return whether it is need to divide the write data into two parts or not + * + * @param circular_area CircularAreaApp descriptor + * @param data_length input data length + */ +static uint32_t CircularAreaAppDivideWrData(CircularAreaAppType circular_area, uint32_t data_length) +{ + CA_PARAM_CHECK(circular_area); + + if(circular_area->writeidx + data_length <= circular_area->area_length) { + return 0; + } else { + return 1; + } +} + +/** + * This function will read data from the circular_area + * + * @param circular_area CircularAreaApp descriptor + * @param output_buffer output data buffer poniter + * @param data_length output data length + */ +int CircularAreaAppRead(CircularAreaAppType circular_area, uint8_t *output_buffer, uint32_t data_length) +{ + CA_PARAM_CHECK(circular_area); + CA_PARAM_CHECK(output_buffer); + CHECK(data_length > 0); + + if(CircularAreaAppIsEmpty(circular_area)) { + return -1; + } + + uint32_t read_length = (data_length > CircularAreaAppGetDataLength(circular_area)) ? CircularAreaAppGetDataLength(circular_area) : data_length; + // if (data_length > CircularAreaAppGetDataLength(circular_area)) { + // return -1; + // } + + if(CircularAreaAppDivideRdData(circular_area, read_length)) { + uint32_t read_len_up = circular_area->area_length - circular_area->readidx; + uint32_t read_len_down = read_length - read_len_up; + + memcpy(output_buffer, &circular_area->data_buffer[circular_area->readidx], read_len_up); + memcpy(output_buffer + read_len_up, circular_area->p_head, read_len_down); + + circular_area->readidx = read_len_down; + } else { + memcpy(output_buffer, &circular_area->data_buffer[circular_area->readidx], read_length); + circular_area->readidx = (circular_area->readidx + read_length) % circular_area->area_length; + } + + circular_area->b_status = 0; + + return read_length; +} + +/** + * This function will write data to the circular_area + * + * @param circular_area CircularAreaApp descriptor + * @param input_buffer input data buffer poniter + * @param data_length input data length + * @param b_force whether to force to write data disregard the length limit + */ +int CircularAreaAppWrite(CircularAreaAppType circular_area, uint8_t *input_buffer, uint32_t data_length, int b_force) +{ + CA_PARAM_CHECK(circular_area); + CA_PARAM_CHECK(input_buffer); + CHECK(data_length > 0); + + if(CircularAreaAppIsFull(circular_area) && (!b_force)) { + return -1; + } + + uint32_t write_data_length = circular_area->area_length - CircularAreaAppGetDataLength(circular_area); + //data_length = (data_length > write_data_length) ? write_data_length : data_length; + if (data_length > write_data_length) { + return -1; + } + + if(CircularAreaAppDivideWrData(circular_area, data_length)) { + uint32_t write_len_up = circular_area->area_length - circular_area->writeidx; + uint32_t write_len_down = data_length - write_len_up; + + memcpy(&circular_area->data_buffer[circular_area->writeidx], input_buffer, write_len_up); + memcpy(circular_area->p_head, input_buffer + write_len_up, write_len_down); + + circular_area->writeidx = write_len_down; + } else { + memcpy(&circular_area->data_buffer[circular_area->writeidx], input_buffer, data_length); + circular_area->writeidx = (circular_area->writeidx + data_length) % circular_area->area_length; + } + + circular_area->b_status = 1; + + if(b_force) { + circular_area->readidx = circular_area->writeidx; + } + + return 0; +} + +static struct CircularAreaAppOps CircularAreaAppOperations = +{ + CircularAreaAppRead, + CircularAreaAppWrite, + CircularAreaAppRelease, + CircularAreaAppReset, +}; + +/** + * This function will initialize the circular_area + * + * @param circular_area_length circular_area length + */ +CircularAreaAppType CircularAreaAppInit(uint32_t circular_area_length) +{ + CHECK(circular_area_length > 0); + + circular_area_length = CA_ALIGN_DOWN(circular_area_length, 8); + + CircularAreaAppType circular_area = PrivMalloc(sizeof(struct CircularAreaApp)); + if(NULL == circular_area) { + printf("CircularAreaAppInit malloc struct circular_area failed\n"); + PrivFree(circular_area); + return NULL; + } + + CircularAreaAppReset(circular_area); + + circular_area->data_buffer = PrivMalloc(circular_area_length); + if(NULL == circular_area->data_buffer) { + printf("CircularAreaAppInit malloc circular_area data_buffer failed\n"); + PrivFree(circular_area->data_buffer); + return NULL; + } + + circular_area->p_head = circular_area->data_buffer; + circular_area->p_tail = circular_area->data_buffer + circular_area_length; + circular_area->area_length = circular_area_length; + + printf("CircularAreaAppInit done p_head %8p p_tail %8p length %u\n", + circular_area->p_head, circular_area->p_tail, circular_area->area_length); + + circular_area->CircularAreaAppOperations = &CircularAreaAppOperations; + + return circular_area; +} diff --git a/APP_Framework/Applications/general_functions/circular_area/circular_area_app.h b/APP_Framework/Applications/general_functions/circular_area/circular_area_app.h new file mode 100644 index 000000000..7533248d3 --- /dev/null +++ b/APP_Framework/Applications/general_functions/circular_area/circular_area_app.h @@ -0,0 +1,100 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: circular_area_app.h +* @brief: function declaration and structure defintion of circular area for applications +* @version: 3.0 +* @author: AIIT XUOS Lab +* @date: 2022/11/21 +* +*/ + +#ifndef CIRCULAR_AREA_APP_H +#define CIRCULAR_AREA_APP_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CA_PARAM_CHECK(param) \ + do \ + { \ + if(param == NULL) { \ + KPrintf("PARAM CHECK FAILED ...%s %d %s is NULL.\n", __func__, __LINE__, #param); \ + while(1); \ + } \ + }while (0) + +#define CA_ALIGN_DOWN(size, align) ((size)/(align)*(align)) + +typedef struct CircularAreaApp *CircularAreaAppType; + +struct CircularAreaAppOps +{ + int (*read) (CircularAreaAppType circular_area, uint8_t *output_buffer, uint32_t data_length); + int (*write) (CircularAreaAppType circular_area, uint8_t *input_buffer, uint32_t data_length, int b_force); + void (*release) (CircularAreaAppType circular_area); + void (*reset) (CircularAreaAppType circular_area); +}; + +struct CircularAreaApp +{ + uint8_t *data_buffer; + + uint32_t readidx; + uint32_t writeidx; + + uint8_t *p_head; + uint8_t *p_tail; + + uint32_t area_length; + int b_status; + + struct CircularAreaAppOps *CircularAreaAppOperations; +}; + +/*This function will return whether the circular_area is full or not*/ +int CircularAreaAppIsFull(CircularAreaAppType circular_area); + +/*This function will return whether the circular_area is empty or not*/ +int CircularAreaAppIsEmpty(CircularAreaAppType circular_area); + +/*This function will reset the circular_area and set the descriptor to default*/ +void CircularAreaAppReset(CircularAreaAppType circular_area); + +/*This function will release the circular_area descriptor and free the memory*/ +void CircularAreaAppRelease(CircularAreaAppType circular_area); + +/*This function will read data from the circular_area*/ +int CircularAreaAppRead(CircularAreaAppType circular_area, uint8_t *output_buffer, uint32_t data_length); + +/*This function will write data to the circular_area*/ +int CircularAreaAppWrite(CircularAreaAppType circular_area, uint8_t *input_buffer, uint32_t data_length, int b_force); + +/*This function will get the circual_area max length*/ +uint32_t CircularAreaAppGetMaxLength(CircularAreaAppType circular_area); + +/*This function will get the data length of the circular_area*/ +uint32_t CircularAreaAppGetDataLength(CircularAreaAppType circular_area); + +/*This function will initialize the circular_area*/ +CircularAreaAppType CircularAreaAppInit(uint32_t circular_area_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/APP_Framework/Framework/Makefile b/APP_Framework/Framework/Makefile index d9e3e101e..10b9168ba 100644 --- a/APP_Framework/Framework/Makefile +++ b/APP_Framework/Framework/Makefile @@ -1,3 +1,4 @@ +SRC_FILES := framework_init.c SRC_DIR := transform_layer ifeq ($(CONFIG_SUPPORT_SENSOR_FRAMEWORK),y) diff --git a/APP_Framework/Framework/connection/adapter.c b/APP_Framework/Framework/connection/adapter.c index eb1356c14..3ac510f84 100644 --- a/APP_Framework/Framework/connection/adapter.c +++ b/APP_Framework/Framework/connection/adapter.c @@ -21,11 +21,8 @@ #include static DoublelistType adapter_list; -#ifdef ADD_XIZI_FETURES -static int adapter_list_lock; -#else static pthread_mutex_t adapter_list_lock; -#endif + /** * @description: Init adapter framework * @return 0 diff --git a/APP_Framework/Framework/control/Kconfig b/APP_Framework/Framework/control/Kconfig index 8c7e89ac4..e9e0a1753 100755 --- a/APP_Framework/Framework/control/Kconfig +++ b/APP_Framework/Framework/control/Kconfig @@ -2,8 +2,28 @@ menuconfig SUPPORT_CONTROL_FRAMEWORK bool "support control framework" default n select TRANSFORM_LAYER_ATTRIUBUTE + select BSP_USING_LWIP + select BSP_USING_SDIO + select MOUNT_SDCARD_FS + select LIB_USING_CJSON if SUPPORT_CONTROL_FRAMEWORK - source "$APP_DIR/Framework/control/ipc_protocol/Kconfig" - source "$APP_DIR/Framework/control/plc_protocol/Kconfig" + config CONTROL_RECIPE_FILE + string "control framework recipe file name" + default "test_recipe.json" + + menuconfig CONTROL_IPC_PROTOCOL + bool "Using ipc protocol" + default n + if CONTROL_IPC_PROTOCOL + source "$APP_DIR/Framework/control/ipc_protocol/Kconfig" + endif + + menuconfig CONTROL_PLC_PROTOCOL + bool "Using plc protocol" + default n + if CONTROL_PLC_PROTOCOL + source "$APP_DIR/Framework/control/plc_protocol/Kconfig" + endif + endif diff --git a/APP_Framework/Framework/control/Makefile b/APP_Framework/Framework/control/Makefile index b2fb7da93..3db840df4 100755 --- a/APP_Framework/Framework/control/Makefile +++ b/APP_Framework/Framework/control/Makefile @@ -1,3 +1,11 @@ -SRC_DIR := ipc_protocol plc_protocol shared +SRC_DIR := shared + +ifeq ($(CONFIG_CONTROL_IPC_PROTOCOL), y) + SRC_DIR += ipc_protocol +endif + +ifeq ($(CONFIG_CONTROL_PLC_PROTOCOL), y) + SRC_DIR += plc_protocol +endif include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/control/ipc_protocol/Kconfig b/APP_Framework/Framework/control/ipc_protocol/Kconfig index 139597f9c..bc72c4672 100755 --- a/APP_Framework/Framework/control/ipc_protocol/Kconfig +++ b/APP_Framework/Framework/control/ipc_protocol/Kconfig @@ -1,2 +1,8 @@ +config CONTROL_PROTOCOL_MODBUS_TCP + bool "Using modbus_tcp control protocol" + default n +config CONTROL_PROTOCOL_MODBUS_UART + bool "Using modbus_uart control protocol" + default n diff --git a/APP_Framework/Framework/control/ipc_protocol/Makefile b/APP_Framework/Framework/control/ipc_protocol/Makefile index 4c33eaf37..a22240e9a 100755 --- a/APP_Framework/Framework/control/ipc_protocol/Makefile +++ b/APP_Framework/Framework/control/ipc_protocol/Makefile @@ -1,4 +1,10 @@ -SRC_DIR := modbus_tcp modbus_uart +ifeq ($(CONFIG_CONTROL_PROTOCOL_MODBUS_TCP), y) + SRC_DIR := modbus_tcp +endif + +ifeq ($(CONFIG_CONTROL_PROTOCOL_MODBUS_UART), y) + SRC_DIR := modbus_uart +endif include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/control/plc/interoperability/socket/plc_socket.c b/APP_Framework/Framework/control/plc/interoperability/socket/plc_socket.c deleted file mode 100755 index 5c0dc8867..000000000 --- a/APP_Framework/Framework/control/plc/interoperability/socket/plc_socket.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (c) 2022 AIIT XUOS Lab - * XiUOS is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -/** - * @file plc_socket.c - * @brief Demo for PLC socket communication function - * @version 1.0 - * @author AIIT XUOS Lab - * @date 2022.03.16 - */ - -#include "transform.h" -#include "plc_socket.h" -#include "sys_arch.h" -#include "lwip/sockets.h" -#include "control_file.h" - -// max support plc socket test commands number -#define PLC_SOCK_CMD_NUM CTL_CMD_NUM -#define PLC_SOCK_TIMEOUT 50000 - -// for saving PLC command index -int plc_cmd_index = 0; - -// only for test -#define SUPPORT_PLC_SIEMENS - -//siemens test -PlcBinCmdType TestPlcCmd[PLC_SOCK_CMD_NUM] = {0}; - -//Test information -//SIEMENS ip: 192.168.250.9 port: 102 -//S7-200 ip: 192.168.250.8 port: 102 -//S7-1200 ip: 192.168.250.6 port: 102 -//OML ip: 192.168.250.3 port: 9600 - -PlcSocketParamType plc_socket_demo_data = { -#ifdef SUPPORT_PLC_SIEMENS - .ip = {192, 168, 250, 6}, - .port = 102, - .device_type = PLC_DEV_TYPE_SIEMENS, - .socket_type = SOCK_STREAM, - .cmd_num = 3, -#else - .ip = {192, 168, 250, 3}, - .port = 9600, - .device_type = PLC_DEV_TYPE_OML, - .socket_type = SOCK_DGRAM, - .cmd_num = 1, -#endif - .recv_len = PLC_RECV_BUF_LEN, - .recv_buf = NULL, -}; - -#define OML_HEADER_LEN 78 -#define CHECK_OML_HEADER(_s) ((0xC0 == *(_s)) && (0x00 == *(_s + 1)) && (0x02 == *(_s + 2)) && (0x00 == *(_s + 3))) - -/******************************************************************************/ - -static void plc_print_array(char *title, int size, uint8_t *cmd) -{ - lw_notice("%s : %d - ", title, size); - for(int i = 0; i < size; i++) - { - lw_notice(" %#x", cmd[i]); - } - lw_notice("\n"); -} - -static void *PlcSocketStart(void *arg) -{ - int fd = -1; - int timeout, recv_len; - struct sockaddr_in sock_addr; - socklen_t addr_len = sizeof(struct sockaddr_in); - PlcSocketParamType *param = (PlcSocketParamType *)&plc_socket_demo_data; - - plc_print("start %d.%d.%d.%d:%d dev %d sock %d\n", - param->ip[0], - param->ip[1], - param->ip[2], - param->ip[3], - param->port, - param->device_type, - param->socket_type); - - param->recv_len = PLC_RECV_BUF_LEN; - - //malloc memory - param->recv_buf = (char *)malloc(param->recv_len); - if (param->recv_buf == NULL) - { - plc_error("No memory\n"); - return NULL; - } - - fd = socket(AF_INET, param->socket_type, 0); - if (fd < 0) - { - plc_error("Socket error %d\n", param->socket_type); - free(param->recv_buf); - return NULL; - } - - plc_print("start %d.%d.%d.%d:%d\n", param->ip[0], param->ip[1], param->ip[2], param->ip[3], param->port); - - sock_addr.sin_family = AF_INET; - sock_addr.sin_port = htons(param->port); - sock_addr.sin_addr.s_addr = PP_HTONL(LWIP_MAKEU32(param->ip[0], param->ip[1], param->ip[2], param->ip[3])); - memset(&(sock_addr.sin_zero), 0, sizeof(sock_addr.sin_zero)); - - if (connect(fd, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr)) < 0) - { - plc_error("Unable to connect\n"); - closesocket(fd); - free(param->recv_buf); - return NULL; - } - - lw_notice("client %s connected\n", inet_ntoa(sock_addr.sin_addr)); - - for(int i = 0; i < param->cmd_num; i ++) - { - PlcBinCmdType *cmd = &TestPlcCmd[i]; - sendto(fd, cmd->cmd, cmd->cmd_len, 0, (struct sockaddr*)&sock_addr, addr_len); - plc_print_array("Send cmd", cmd->cmd_len, cmd->cmd); - - MdelayKTask(cmd->delay_ms); - timeout = PLC_SOCK_TIMEOUT; - memset(param->recv_buf, 0, param->recv_len); - while(timeout --) - { - recv_len = recvfrom(fd, param->recv_buf, param->recv_len, 0, (struct sockaddr *)&sock_addr, &addr_len); - if(recv_len > 0) - { - if(param->device_type == PLC_DEV_TYPE_OML) - { - if((recv_len == OML_HEADER_LEN) && (CHECK_OML_HEADER(param->recv_buf))) - { - lw_notice("This is Oml package!!!\n"); - } - } - lw_notice("Receive from : %s\n", inet_ntoa(sock_addr.sin_addr)); - plc_print_array("Receive data", recv_len, param->recv_buf); - break; - } - } - } - - closesocket(fd); - free(param->recv_buf); - return NULL; -} - -void PlcGetParamCmd(char *cmd) -{ - const char s[2] = ","; - char *token; - uint16_t cmd_index = 0; - char bin_cmd[PLC_BIN_CMD_LEN] = {0}; - token = strtok(cmd, s); - while(token != NULL) - { - sscanf(token, "%x", &bin_cmd[cmd_index]); - plc_print("%d - %s %d\n", cmd_index, token, bin_cmd[cmd_index]); - token = strtok(NULL, s); - cmd_index ++; - } - TestPlcCmd[plc_cmd_index].cmd_len = cmd_index; - memcpy(TestPlcCmd[plc_cmd_index].cmd, bin_cmd, cmd_index); - plc_print("get %d cmd len %d\n", plc_cmd_index, TestPlcCmd[plc_cmd_index].cmd_len); - plc_cmd_index ++; - plc_socket_demo_data.cmd_num = plc_cmd_index; -} - -void PlcShowUsage(void) -{ - plc_notice("------------------------------------\n"); - plc_notice("PlcSocket [ip].[ip].[ip].[ip]:[port]\n"); - plc_notice("PlcSocket support other param:\n"); - plc_notice("plc=[] 0: OML 1:SIEMENS\n"); - plc_notice("tcp=[] 0: udp 1:tcp\n"); - plc_notice("ip=[ip.ip.ip.ip]\n"); - plc_notice("port=port\n"); - plc_notice("file: use %s\n", PLC_SOCK_FILE_NAME); - plc_notice("------------------------------------\n"); -} - -#if defined(MOUNT_SDCARD) && defined(LIB_USING_CJSON) -void PlcGetParamFromFile(char *file_name) -{ - PlcSocketParamType *param = &plc_socket_demo_data; - - char *file_buf = malloc(CTL_FILE_LEN); - if(file_buf == NULL) - { - plc_error("No enough buffer %d\n", CTL_FILE_LEN); - return; - } - memset(file_buf, 0, CTL_FILE_LEN); - - if(CtlFileReadWithFilename(file_name, CTL_FILE_LEN, file_buf) != EOK) - { - plc_error("Can't open file %s\n", file_name); - //try again default file - if(strcmp(file_name, PLC_SOCK_FILE_NAME) != 0) - { - if(CtlFileReadWithFilename(PLC_SOCK_FILE_NAME, CTL_FILE_LEN, file_buf) != EOK) - { - plc_error("Can't open file %s\n", file_name); - return; - } - } - else - { - return; - } - } - CtlParseJsonData(file_buf); - - memcpy(param->ip, ctl_file_param.ip, 4); - param->port = ctl_file_param.port; - param->cmd_num = ctl_file_param.cmd_num; - param->socket_type = ctl_file_param.tcp ? SOCK_STREAM : SOCK_DGRAM; - - for(int i = 0; i < param->cmd_num; i++) - { - TestPlcCmd[i].cmd_len = ctl_file_param.cmd_len[i]; - memcpy(TestPlcCmd[i].cmd, ctl_file_param.cmd[i], TestPlcCmd[i].cmd_len); - } - - plc_print("ip: %d.%d.%d.%d\n", param->ip[0], param->ip[1], param->ip[2], param->ip[3]); - plc_print("port: %d", param->port); - plc_print("tcp: %d", param->socket_type); - plc_print("cmd number: %d\n", param->cmd_num); - - for(int i = 0; i < param->cmd_num; i++) - { - plc_print_array("cmd", TestPlcCmd[i].cmd_len, TestPlcCmd[i].cmd); - } - free(file_buf); -} - -#endif - -void PlcCheckParam(int argc, char *argv[]) -{ - int i; - PlcSocketParamType *param = &plc_socket_demo_data; - plc_cmd_index = 0; - - for(i = 0; i < argc; i++) - { - char *str = argv[i]; - int is_tcp = 0; - char cmd_str[PLC_BIN_CMD_LEN] = {0}; - - plc_print("check %d %s\n", i, str); - -#if defined(MOUNT_SDCARD) && defined(LIB_USING_CJSON) - if(strncmp(str, "file", 4) == 0) - { - char file_name[CTL_FILE_NAME_LEN] = {0}; - if(sscanf(str, "file=%s", file_name) == EOF) - { - strcpy(file_name, PLC_SOCK_FILE_NAME); - } - plc_notice("get %s parameter file %s\n", str, file_name); - PlcGetParamFromFile(file_name); - return; - } -#endif - if(sscanf(str, "ip=%d.%d.%d.%d", - ¶m->ip[0], - ¶m->ip[1], - ¶m->ip[2], - ¶m->ip[3]) == 4) - { - plc_print("find ip %d %d %d %d\n", param->ip[0], param->ip[1], param->ip[2], param->ip[3]); - continue; - } - - if(sscanf(str, "port=%d", ¶m->port) == 1) - { - plc_print("find port %d\n", param->port); - continue; - } - - if(sscanf(str, "tcp=%d", &is_tcp) == 1) - { - plc_print("find tcp %d\n", is_tcp); - param->socket_type = is_tcp ? SOCK_STREAM:SOCK_DGRAM; - continue; - } - - if(sscanf(str, "plc=%d", ¶m->device_type) == 1) - { - plc_print("find device %d\n", param->device_type); - continue; - } - - if(sscanf(str, "cmd=%s", cmd_str) == 1) - { - plc_print("find cmd %s\n", cmd_str); - PlcGetParamCmd(cmd_str); - continue; - } - } - - if(argc >= 2) - { - if(sscanf(argv[1], "%d.%d.%d.%d:%d", - ¶m->ip[0], - ¶m->ip[1], - ¶m->ip[2], - ¶m->ip[3], - ¶m->port) != EOF) - { - return; - } - - if(sscanf(argv[1], "%d.%d.%d.%d", - ¶m->ip[0], - ¶m->ip[1], - ¶m->ip[2], - ¶m->ip[3]) != EOF) - { - return; - } - } - else - { - PlcShowUsage(); - } -} - -void PlcSocketTask(int argc, char *argv[]) -{ - int result = 0; - pthread_t th_id; - uint8_t enet_port = 0; ///< test enet port 0 - - pthread_attr_t attr; - attr.schedparam.sched_priority = LWIP_DEMO_TASK_PRIO; - attr.stacksize = LWIP_TASK_STACK_SIZE; - PlcSocketParamType *param = &plc_socket_demo_data; - - PlcCheckParam(argc, argv); - - lwip_config_net(enet_port, lwip_ipaddr, lwip_netmask, param->ip); - PrivTaskCreate(&th_id, &attr, PlcSocketStart, param); -} - -SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3), - PlcSocket, PlcSocketTask, Test PLC Socket); - diff --git a/APP_Framework/Framework/control/plc_protocol/Kconfig b/APP_Framework/Framework/control/plc_protocol/Kconfig index 139597f9c..9839fe26e 100755 --- a/APP_Framework/Framework/control/plc_protocol/Kconfig +++ b/APP_Framework/Framework/control/plc_protocol/Kconfig @@ -1,2 +1,15 @@ +config CONTROL_PROTOCOL_FINS + bool "Using fins control protocol" + default n +config CONTROL_PROTOCOL_MELSEC + bool "Using melsec control protocol" + default n +config CONTROL_PROTOCOL_OPCUA + bool "Using opcua control protocol" + default n + +config CONTROL_PROTOCOL_S7 + bool "Using s7 control protocol" + default n diff --git a/APP_Framework/Framework/control/plc_protocol/Makefile b/APP_Framework/Framework/control/plc_protocol/Makefile index ff2e46798..66e467295 100755 --- a/APP_Framework/Framework/control/plc_protocol/Makefile +++ b/APP_Framework/Framework/control/plc_protocol/Makefile @@ -1,4 +1,17 @@ -SRC_DIR := fins melsec opcua s7 +ifeq ($(CONFIG_CONTROL_PROTOCOL_FINS), y) + SRC_DIR := fins +endif + +ifeq ($(CONFIG_CONTROL_PROTOCOL_MELSEC), y) + SRC_DIR := melsec +endif + +ifeq ($(CONFIG_CONTROL_PROTOCOL_OPCUA), y) + SRC_DIR := opcua +endif + +ifeq ($(CONFIG_CONTROL_PROTOCOL_S7), y) + SRC_DIR := s7 +endif include $(KERNEL_ROOT)/compiler.mk - diff --git a/APP_Framework/Framework/control/plc_protocol/fins/Makefile b/APP_Framework/Framework/control/plc_protocol/fins/Makefile index 608656f03..020d8567a 100755 --- a/APP_Framework/Framework/control/plc_protocol/fins/Makefile +++ b/APP_Framework/Framework/control/plc_protocol/fins/Makefile @@ -1,4 +1,4 @@ -SRC_FILES := +SRC_FILES := fins.c include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/control/plc_protocol/fins/fins.c b/APP_Framework/Framework/control/plc_protocol/fins/fins.c new file mode 100644 index 000000000..0cbfeec88 --- /dev/null +++ b/APP_Framework/Framework/control/plc_protocol/fins/fins.c @@ -0,0 +1,368 @@ +/* +* Copyright (c) 2022 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** + * @file fins.c + * @brief plc protocol fins + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2022-10-08 + */ + +#include + +#define FINS_COMMAND_LENGTH 34 + +static struct CircularAreaApp *circular_area; + +static uint8_t handshake_require_command[] = {0x46, 0x49, 0x4E, 0x53, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static uint8_t handshake_respond_buff[24] = {0}; +static uint8_t recv_buff[1024] = {0}; + +static uint8_t FinsAreaCode(char area_char, FinsDataType type) +{ + uint8_t area_code = 0; + if (area_char == 'C') + area_code = (type == FINS_DATA_TYPE_BIT ? 0x30 : 0xB0); + if (area_char == 'W') + area_code = (type == FINS_DATA_TYPE_BIT ? 0x31 : 0xB1); + if (area_char == 'H') + area_code = (type == FINS_DATA_TYPE_BIT ? 0x32 : 0xB2); + if (area_char == 'D') + area_code = (type == FINS_DATA_TYPE_BIT ? 0x02 : 0x82); + return area_code; +} + +static uint16_t FinsCommandGenerate(uint8_t *p_command, uint16_t plc_ip_4, uint16_t pc_ip_4, FinsCommandCode command_code, char area_char, + FinsDataType data_type, uint16_t start_address, uint8_t bit_address, uint16_t data_length) +{ + uint8_t index = 0; + p_command[index++] = (uint8_t)(FINS_HEADER_HEAD >> (3 * 8)); + p_command[index++] = (uint8_t)(FINS_HEADER_HEAD >> (2 * 8)); + p_command[index++] = (uint8_t)(FINS_HEADER_HEAD >> (1 * 8)); + p_command[index++] = (uint8_t)FINS_HEADER_HEAD; + p_command[index++] = (uint8_t)FINS_HEADER_READ_COMMAND_LENGTH >> (3 * 8); + p_command[index++] = (uint32_t)FINS_HEADER_READ_COMMAND_LENGTH >> (2 * 8); + p_command[index++] = (uint32_t)FINS_HEADER_READ_COMMAND_LENGTH >> (1 * 8); + p_command[index++] = (uint32_t)FINS_HEADER_READ_COMMAND_LENGTH; + p_command[index++] = (uint32_t)FINS_HEADER_COMMAND >> (3 * 8); + p_command[index++] = (uint32_t)FINS_HEADER_COMMAND >> (2 * 8); + p_command[index++] = (uint32_t)FINS_HEADER_COMMAND >> (1 * 8); + p_command[index++] = (uint32_t)FINS_HEADER_COMMAND; + p_command[index++] = (uint32_t)FINS_HEADER_ERROR_CODE >> (3 * 8); + p_command[index++] = (uint32_t)FINS_HEADER_ERROR_CODE >> (2 * 8); + p_command[index++] = (uint32_t)FINS_HEADER_ERROR_CODE >> (1 * 8); + p_command[index++] = (uint32_t)FINS_HEADER_ERROR_CODE; + p_command[index++] = FINS_ICF; + p_command[index++] = FINS_RSV; + p_command[index++] = FINS_GCT; + + p_command[index++] = FINS_DNA; + p_command[index++] = plc_ip_4; + p_command[index++] = FINS_DA2; + + p_command[index++] = FINS_SNA; + p_command[index++] = pc_ip_4; + p_command[index++] = FINS_SA2; + + p_command[index++] = FINS_SID; + + p_command[index++] = command_code >> 8; + p_command[index++] = command_code; + p_command[index++] = FinsAreaCode(area_char, data_type); + p_command[index++] = start_address >> 8; + p_command[index++] = start_address; + p_command[index++] = bit_address; + p_command[index++] = data_length >> 8; + p_command[index++] = data_length; + + return index; +} + +static int FinsTransformRecvBuffToData(FinsReadItem *p_read_item, uint8_t *recv_buff) +{ + FinsDataInfo *p_fins_data_info = &(p_read_item->data_info); + uint8_t error_code = recv_buff[3]; + if (error_code) { + printf("Data abnormal, abnormal error code is %08x!", error_code); + return -1; + } + recv_buff += 30; + + FinsCommandCode command_code = p_fins_data_info->command_code; + if (FINS_COMMAND_CODE_READ == command_code) { + + uint16_t data_length = p_read_item->data_length; + ControlPrintList("DATA", recv_buff, data_length * (FINS_DATA_TYPE_BIT == p_read_item->data_type ? 1 : 2)); + printf("Receive data is "); + + if (FINS_DATA_TYPE_BIT == p_read_item->data_type) { + memcpy(p_fins_data_info->base_data_info.p_data, recv_buff, data_length); + + printf("%02x", p_fins_data_info->base_data_info.p_data[0]); + } else { + uint8_t *p_data = p_fins_data_info->base_data_info.p_data; + + for (uint16_t i = 0; i < data_length; i ++) { + p_data[2 * i] = recv_buff[2 * (data_length - i - 1)]; + p_data[2 * i + 1] = recv_buff[2 * (data_length - i - 1) + 1]; + printf("%03x%03x", p_data[2 * i], p_data[2 * i + 1]); + } + } + + printf("\nRead fins plc data success!\n"); + } else if (FINS_COMMAND_CODE_WRITE == command_code) { + /*to do*/ + printf("Write fins plc cmd success!\n"); + } + + return 0; +} + +static int FinsHandshake(int32_t socket, uint16_t local_ip_4) +{ + handshake_require_command[18] = (uint8_t)(local_ip_4 >> 8); + handshake_require_command[19] = (uint8_t)local_ip_4; + uint8_t try_count = 0; + + while (try_count < 10) { + ControlPrintList("SEND", (uint8_t *)handshake_require_command, sizeof(handshake_require_command)); + int32_t write_error = socket_write(socket, handshake_require_command, sizeof(handshake_require_command)); + if (write_error < 0) { + printf("Write socket error, errno is %d!", errno); + } else { + int32_t recv_length = socket_read(socket, (uint8_t *)handshake_respond_buff, sizeof(handshake_respond_buff)); + if (recv_length < 0) { + printf("Read socket error, errno is %d!", errno); + } else { + ControlPrintList("RECV", (uint8_t *)handshake_respond_buff, recv_length); + + /*check fins handshake respond*/ + uint8_t error_code = handshake_respond_buff[15]; + if (error_code == 0 || error_code == 0x21) { + return 0; + } else { + printf("Fins handshake failed, errno is %05x!", handshake_respond_buff[15]); + return -1; + } + } + } + if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK)) { + printf("Send plc command failed, errno is %d!", errno); + continue; + } else { + break; + } + } + return -2; +} + +static int FinsGetData(int32_t socket, FinsReadItem *p_read_item, struct ControlRecipe *p_recipe) +{ + uint8_t try_count = 0; + int32_t write_error = 0; + + FinsDataInfo *p_fins_data_info = &(p_read_item->data_info); + BasicPlcDataInfo *p_base_data_info = &(p_fins_data_info->base_data_info); + + memset(recv_buff, 0, sizeof(recv_buff)); + + while (try_count < 10) { + ControlPrintList("SEND", p_base_data_info->p_command, p_base_data_info->command_length); + try_count++; + + write_error = socket_write(socket, p_base_data_info->p_command, p_base_data_info->command_length); + if (write_error < 0) { + printf("Write socket error, errno is %d!", errno); + } else { + PrivTaskDelay(20); + + int32_t recv_length = socket_read(socket, recv_buff, sizeof(recv_buff)); + if (recv_length < 0) { + printf("Read socket error, errno is %d!", errno); + } else { + ControlPrintList("RECV", recv_buff, recv_length); + return FinsTransformRecvBuffToData(p_read_item, recv_buff); + } + } + + if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK)) { + printf("Send plc command failed, errno is %d!", errno); + continue; + } else { + return -1; + } + } + return -2; +} + +static int FinsInitialDataInfo(FinsReadItem *p_read_item, uint16_t plc_ip_4, uint16_t local_ip_4, FinsCommandCode command_code, + char area_char, FinsDataType data_type, uint16_t start_address, uint8_t bit_address, uint16_t data_length, uint8_t *p_data) +{ + p_read_item->area_char = area_char; + p_read_item->data_type = data_type; + p_read_item->data_info.command_code = command_code; + p_read_item->start_address = start_address; + p_read_item->bit_address = bit_address; + p_read_item->data_length = data_length; + + BasicPlcDataInfo *p_base_data_info = &(p_read_item->data_info.base_data_info); + switch (command_code) + { + case FINS_COMMAND_CODE_READ: + data_length *= (data_type == FINS_DATA_TYPE_BIT ? 1 : 2); + p_base_data_info->command_length = FINS_COMMAND_LENGTH; + p_base_data_info->p_command = (p_data == NULL ? PrivMalloc(FINS_COMMAND_LENGTH + data_length) : PrivMalloc(FINS_COMMAND_LENGTH)); + p_base_data_info->data_size = data_length; + p_base_data_info->p_data = (p_data == NULL ? p_base_data_info->p_command + FINS_COMMAND_LENGTH : p_data); + break; + case FINS_COMMAND_CODE_WRITE: + //To Do + break; + default: + return -1; + } + uint16_t command_length = FinsCommandGenerate(p_base_data_info->p_command, plc_ip_4, local_ip_4, command_code, area_char, + data_type, start_address, bit_address, data_length); + + return 0; +} + +void *ReceivePlcDataTask(void *parameter) +{ + int i = 0; + uint8_t try_count = 0; + uint16_t data_length = 0; + uint8_t *fins_data; + uint16_t read_item_size = sizeof(FinsReadItem); + + struct ControlProtocol *control_protocol = (struct ControlProtocol *)parameter; + circular_area = (struct CircularAreaApp *)control_protocol->args; + FinsReadItem *fins_read_item = (FinsReadItem *)control_protocol->recipe->read_item; + fins_data = control_protocol->recipe->protocol_data->data; + data_length = control_protocol->recipe->protocol_data->data_length; + + BasicSocketPlc plc_socket; + memset(&plc_socket, 0, sizeof(BasicSocketPlc)); + memcpy(plc_socket.ip, control_protocol->recipe->socket_config.plc_ip, 4); + plc_socket.port = control_protocol->recipe->socket_config.port; + plc_socket.socket = -1; + plc_socket.secondary_connect_flag = 0; + + while (1) { + for (i = 0; i < control_protocol->recipe->read_item_count; i ++) { + /*only connect socket when close socket or init*/ + while (ControlConnectSocket(&plc_socket) < 0) { + PrivTaskDelay(1000); + } + + /*need to handshake after connect socket using FINS protocol*/ + if (0 == plc_socket.secondary_connect_flag) { + if (FinsHandshake(plc_socket.socket, control_protocol->recipe->socket_config.local_ip[3]) < 0) { + plc_socket.secondary_connect_flag = 0; + ControlDisconnectSocket(&plc_socket); + continue; + } + } + + plc_socket.secondary_connect_flag = 1; + + FinsGetData(plc_socket.socket, (FinsReadItem *)fins_read_item + i, control_protocol->recipe); + } + + /*read all variable item data, put them into circular_area*/ + if (i == control_protocol->recipe->read_item_count) { + CircularAreaAppWrite(circular_area, fins_data, data_length, 0); + } + + /*read data every single 200ms*/ + PrivTaskDelay(200); + } +} + +int FinsOpen(struct ControlProtocol *control_protocol) +{ + ControlProtocolOpenDef(control_protocol); + + return 0; +} + +int FinsClose(struct ControlProtocol *control_protocol) +{ + ControlProtocolCloseDef(); +} + +int FinsRead(struct ControlProtocol *control_protocol, void *buf, size_t len) +{ + return CircularAreaAppRead(circular_area, buf, len); +} + +static struct ControlDone fins_protocol_done = +{ + ._open = FinsOpen, + ._close = FinsClose, + ._read = FinsRead, + ._write = NULL, + ._ioctl = NULL, +}; + +int FinsProtocolFormatCmd(struct ControlRecipe *p_recipe, ProtocolFormatInfo *protocol_format_info) +{ + int ret = 0; + static uint8_t last_data_length = 0; + + p_recipe->read_item = PrivMalloc(sizeof(FinsReadItem) * p_recipe->read_item_count); + FinsReadItem *fins_read_item = (FinsReadItem *)(p_recipe->read_item) + protocol_format_info->read_item_index; + + fins_read_item->value_type = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "value_type")->valueint; + strncpy(fins_read_item->value_name, cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "value_name")->valuestring, 20); + + ret = FinsInitialDataInfo(fins_read_item, + p_recipe->socket_config.plc_ip[3], + p_recipe->socket_config.local_ip[3], + FINS_COMMAND_CODE_READ, + cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "area_char")->valuestring[0], + cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "data_type")->valueint, + cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "start_address")->valueint, + cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "bit_address")->valueint, + cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "data_length")->valueint, + p_recipe->protocol_data->data + last_data_length); + + ControlPrintList("CMD", fins_read_item->data_info.base_data_info.p_command, fins_read_item->data_info.base_data_info.command_length); + last_data_length = GetValueTypeMemorySize(fins_read_item->value_type); + + return ret; +} + +int FinsProtocolInit(struct ControlRecipe *p_recipe) +{ + struct ControlProtocol *p_control_protocol = CONTAINER_OF(p_recipe, struct ControlProtocol, recipe); + if (NULL == p_control_protocol) { + printf("%s get control protocol failed\n", __func__); + return -1; + } + + FinsReadItem *fins_read_item = PrivMalloc(sizeof(FinsReadItem) * p_recipe->read_item_count); + if (NULL == fins_read_item) { + PrivFree(fins_read_item); + return -1; + } + p_recipe->read_item = (void *)fins_read_item; + + p_recipe->ControlProtocolFormatCmd = FinsProtocolFormatCmd; + + p_control_protocol->done = &fins_protocol_done; + + return 0; +} + + diff --git a/APP_Framework/Framework/control/plc_protocol/fins/test_recipe_fins.json b/APP_Framework/Framework/control/plc_protocol/fins/test_recipe_fins.json new file mode 100644 index 000000000..301f67713 --- /dev/null +++ b/APP_Framework/Framework/control/plc_protocol/fins/test_recipe_fins.json @@ -0,0 +1,331 @@ +{ + "device_id": 769, + "device_name": "S01", + "communication_type": 0, + "socket_config": { + "plc_ip": "192.168.250.22", + "local_ip": "192.168.250.233", + "gateway": "192.168.250.1", + "netmask": "255.255.254.0", + "port": 9600 + }, + "protocol_type": 6, + "read_period": 100, + "read_item_list": [ + { + "value_name": "启动", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 0, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "停止", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 0, + "bit_address": 1, + "data_length": 1 + }, + { + "value_name": "使能", + "value_type": 1, + "area_char": "H", + "data_type": 0, + "start_address": 0, + "bit_address": 2, + "data_length": 1 + }, + { + "value_name": "回零", + "value_type": 1, + "area_char": "D", + "data_type": 0, + "start_address": 0, + "bit_address": 3, + "data_length": 1 + }, + { + "value_name": "急停", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 0, + "bit_address": 4, + "data_length": 1 + }, + { + "value_name": "正限位", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 10, + "bit_address": 11, + "data_length": 1 + }, + { + "value_name": "负限位", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 10, + "bit_address": 12, + "data_length": 1 + }, + { + "value_name": "自动运行中", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 200, + "bit_address": 5, + "data_length": 1 + }, + { + "value_name": "故障", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 200, + "bit_address": 6, + "data_length": 1 + }, + { + "value_name": "待机", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 200, + "bit_address": 7, + "data_length": 1 + }, + { + "value_name": "手动模式", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 300, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "自动模式", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 300, + "bit_address": 1, + "data_length": 1 + }, + { + "value_name": "运行方向", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 300, + "bit_address": 2, + "data_length": 1 + }, + { + "value_name": "复位", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 400, + "bit_address": 3, + "data_length": 1 + }, + { + "value_name": "备用1", + "value_type": 1, + "area_char": "W", + "data_type": 0, + "start_address": 400, + "bit_address": 4, + "data_length": 1 + }, + { + "value_name": "产量", + "value_type": 3, + "area_char": "D", + "data_type": 1, + "start_address": 10, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "整型1", + "value_type": 3, + "area_char": "D", + "data_type": 1, + "start_address": 11, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "整型2", + "value_type": 3, + "area_char": "D", + "data_type": 1, + "start_address": 20, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "整型3", + "value_type": 3, + "area_char": "D", + "data_type": 1, + "start_address": 100, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "整型4", + "value_type": 3, + "area_char": "W", + "data_type": 1, + "start_address": 100, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "整型5", + "value_type": 3, + "area_char": "W", + "data_type": 1, + "start_address": 101, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "整型6", + "value_type": 3, + "area_char": "W", + "data_type": 1, + "start_address": 110, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "整型7", + "value_type": 3, + "area_char": "H", + "data_type": 1, + "start_address": 10, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "整型8", + "value_type": 3, + "area_char": "H", + "data_type": 1, + "start_address": 20, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "整型9", + "value_type": 3, + "area_char": "H", + "data_type": 1, + "start_address": 21, + "bit_address": 0, + "data_length": 1 + }, + { + "value_name": "速度", + "value_type": 9, + "area_char": "D", + "data_type": 1, + "start_address": 2000, + "bit_address": 0, + "data_length": 2 + }, + { + "value_name": "加速度", + "value_type": 9, + "area_char": "D", + "data_type": 1, + "start_address": 2002, + "bit_address": 0, + "data_length": 2 + }, + { + "value_name": "减速度", + "value_type": 9, + "area_char": "D", + "data_type": 1, + "start_address": 2004, + "bit_address": 0, + "data_length": 2 + }, + { + "value_name": "起始位置", + "value_type": 9, + "area_char": "D", + "data_type": 1, + "start_address": 300, + "bit_address": 0, + "data_length": 2 + }, + { + "value_name": "终点位置", + "value_type": 9, + "area_char": "D", + "data_type": 1, + "start_address": 302, + "bit_address": 0, + "data_length": 2 + }, + { + "value_name": "张力值", + "value_type": 9, + "area_char": "W", + "data_type": 1, + "start_address": 80, + "bit_address": 0, + "data_length": 2 + }, + { + "value_name": "浮点型1", + "value_type": 8, + "area_char": "H", + "data_type": 1, + "start_address": 100, + "bit_address": 0, + "data_length": 4 + }, + { + "value_name": "浮点型2", + "value_type": 8, + "area_char": "H", + "data_type": 1, + "start_address": 104, + "bit_address": 0, + "data_length": 4 + }, + { + "value_name": "浮点型3", + "value_type": 8, + "area_char": "H", + "data_type": 1, + "start_address": 108, + "bit_address": 0, + "data_length": 4 + }, + { + "value_name": "浮点型4", + "value_type": 8, + "area_char": "H", + "data_type": 1, + "start_address": 112, + "bit_address": 0, + "data_length": 4 + } + ] +} \ No newline at end of file diff --git a/APP_Framework/Framework/control/plc_protocol/include/fins.h b/APP_Framework/Framework/control/plc_protocol/include/fins.h new file mode 100644 index 000000000..549776752 --- /dev/null +++ b/APP_Framework/Framework/control/plc_protocol/include/fins.h @@ -0,0 +1,86 @@ +/* +* Copyright (c) 2022 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** + * @file fins.h + * @brief plc protocol fins + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2022-10-08 + */ + +#ifndef FINS_H +#define FINS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define FINS_HEADER_HEAD 0x46494E53 +#define FINS_HEADER_READ_COMMAND_LENGTH 0x0000001A +#define FINS_HEADER_COMMAND 0x00000002 +#define FINS_HEADER_ERROR_CODE 0x00000000 +#define FINS_ICF 0x80 +#define FINS_RSV 0x00 +#define FINS_REPLY_ICF 0xC0 +#define FINS_GCT 0x02 +#define FINS_DNA 0x00 +#define FINS_DA2 0x00 +#define FINS_SNA 0x00 +#define FINS_SA2 0x00 +#define FINS_SID 0x00 + +typedef enum +{ + FINS_COMMAND_CODE_READ = 0x0101, + FINS_COMMAND_CODE_WRITE = 0x0102 +}FinsCommandCode; + +typedef enum +{ + FINS_DATA_TYPE_BIT, + FINS_DATA_TYPE_WORD +}FinsDataType; + +typedef struct +{ + BasicPlcDataInfo base_data_info; + FinsCommandCode command_code; +}FinsDataInfo; + +typedef struct +{ + int32_t socket; + uint16_t plc_ip_4; +}FinsHandshakeParameter; + +typedef struct +{ + FinsDataInfo data_info; + + UniformValueType value_type; + char value_name[20]; + + char area_char; + FinsDataType data_type; + uint16_t start_address; + uint8_t bit_address; + uint16_t data_length; +}FinsReadItem; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/APP_Framework/Framework/control/shared/control_file.c b/APP_Framework/Framework/control/plc_protocol/include/melsec.h old mode 100755 new mode 100644 similarity index 85% rename from APP_Framework/Framework/control/shared/control_file.c rename to APP_Framework/Framework/control/plc_protocol/include/melsec.h index 198c166ef..2586fdd4e --- a/APP_Framework/Framework/control/shared/control_file.c +++ b/APP_Framework/Framework/control/plc_protocol/include/melsec.h @@ -11,11 +11,9 @@ */ /** - * @file control_file.c - * @brief control relative file operation + * @file melsec.h + * @brief plc protocol melsec * @version 3.0 * @author AIIT XUOS Lab - * @date 2022-09-37 - */ - - + * @date 2022-10-08 + */ \ No newline at end of file diff --git a/APP_Framework/Framework/control/shared/control_file.h b/APP_Framework/Framework/control/plc_protocol/include/opcua.h old mode 100755 new mode 100644 similarity index 78% rename from APP_Framework/Framework/control/shared/control_file.h rename to APP_Framework/Framework/control/plc_protocol/include/opcua.h index 5058c4def..898d0022d --- a/APP_Framework/Framework/control/shared/control_file.h +++ b/APP_Framework/Framework/control/plc_protocol/include/opcua.h @@ -11,16 +11,9 @@ */ /** - * @file control_file.h - * @brief control file function relative API + * @file opcua.h + * @brief control protocol opcua * @version 3.0 * @author AIIT XUOS Lab - * @date 2022-09-27 - */ - -#ifndef CONTROL_FILE_H -#define CONTROL_FILE_H - - -#endif - + * @date 2022-10-08 + */ \ No newline at end of file diff --git a/APP_Framework/Framework/control/plc_protocol/include/s7.h b/APP_Framework/Framework/control/plc_protocol/include/s7.h new file mode 100644 index 000000000..f89f1f122 --- /dev/null +++ b/APP_Framework/Framework/control/plc_protocol/include/s7.h @@ -0,0 +1,19 @@ +/* +* Copyright (c) 2022 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** + * @file s7.h + * @brief plc protocol s7 + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2022-10-08 + */ \ No newline at end of file diff --git a/APP_Framework/Framework/control/shared/Makefile b/APP_Framework/Framework/control/shared/Makefile index 633191b89..e26f03b9b 100755 --- a/APP_Framework/Framework/control/shared/Makefile +++ b/APP_Framework/Framework/control/shared/Makefile @@ -1,8 +1,4 @@ -SRC_FILES := control.c - -ifeq ($(CONFIG_MOUNT_SDCARD),y) - SRC_FILES += control_file.c -endif +SRC_FILES := control.c control_def.c include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/control/shared/config.json b/APP_Framework/Framework/control/shared/config.json deleted file mode 100755 index 05b79a6a3..000000000 --- a/APP_Framework/Framework/control/shared/config.json +++ /dev/null @@ -1,38 +0,0 @@ -{ -"siemens plc": -{ - "device type": "PLC", - "control type": "HSC", - "info": - { - "plc ability" : 1, - "plc device id": 1, - "soft version" : 1, - "hardware version": 1, - "date": "2022-1-28", - "vendor": "siemens", - "model":"S300" - }, - - "serial config": - { - "serial type":"485", - "station id" : "station1", - "serial port" : 1 - }, - - "network config": - { - "ip addr" : "192.168.250.5", - "ip port" : 4840 - }, - - "interface": - { - "inhybridnet":"OPCUA", - "transport":"TCP", - "ip address": "192.168.250.5", - "attribute" : "1" - } -} -} diff --git a/APP_Framework/Framework/control/shared/control.c b/APP_Framework/Framework/control/shared/control.c index 8c880f693..6ebd1394a 100755 --- a/APP_Framework/Framework/control/shared/control.c +++ b/APP_Framework/Framework/control/shared/control.c @@ -12,16 +12,239 @@ /** * @file control.c - * @brief control framework code + * @brief code for control framework app * @version 3.0 * @author AIIT XUOS Lab * @date 2022-09-27 */ #include +#include -void control_init(void) +ControlProtocolType control_protocol; + +/** + * @description: Control Framework Find certain Protocol + * @param + * @return Control Protocol pointer + */ +ControlProtocolType ControlProtocolFind(void) { - //to do + return control_protocol; } +/** + * @description: Control Framework Protocol Init + * @param control_protocol - control protocol pointer + * @return success: 0 error : -1 + */ +static int ControlProtocolInit(ControlProtocolType control_protocol) +{ + CONTROL_PARAM_CHECK(control_protocol); + int ret = -1; + + control_protocol->protocol_status = CONTROL_INIT; + + ret = PrivMutexCreate(&control_protocol->lock, 0); + if(ret < 0) { + printf("ControlProtocolInit mutex create failed.\n"); + goto _out; + } + + ret = PrivSemaphoreCreate(&control_protocol->sem, 0, 0); + if (ret < 0) { + printf("ControlProtocolInit create sem error\n"); + goto _out; + } + +_out: + return ret; +} + +/** + * @description: Analyze Recipe + * @param control_protocol - Control Protocol pointer + * @param recipe_name - recipe name + * @return success: 0 error : -1 + */ +static int ControlAnalyzeRecipe(ControlProtocolType control_protocol, const char *recipe_name) +{ + int recipe_file_fd = -1; + struct stat recipe_file_status; + uint16_t recipe_file_length = 0; + char *recipe_file_buf; + + //Step1 : read recipe file data from SD card or other store device + recipe_file_fd = PrivOpen(recipe_name, O_RDONLY); + if (recipe_file_fd < 0) { + printf("Open recipe file %s failed\n", recipe_name); + PrivClose(recipe_file_fd); + return -1; + } + + if (0 != fstat(recipe_file_fd, &recipe_file_status)) { + printf("Get recipe file information failed!\n"); + PrivClose(recipe_file_fd); + return -1; + } else { + recipe_file_length = recipe_file_status.st_size; + } + + recipe_file_buf = PrivMalloc(recipe_file_length); + if (NULL == recipe_file_buf) { + printf("Get recipe file memory failed!\n"); + PrivFree(recipe_file_buf); + PrivClose(recipe_file_fd); + return -1; + } + + if (PrivRead(recipe_file_fd, recipe_file_buf, recipe_file_length) < 0) { + printf("Read recipe file failed!\n"); + PrivFree(recipe_file_buf); + PrivClose(recipe_file_fd); + return -1; + } + + PrivClose(recipe_file_fd); + + //Step2 : CJSON analyze +#ifdef LIB_USING_CJSON + cJSON *recipe_file_json = cJSON_Parse(recipe_file_buf); + PrivFree(recipe_file_buf); + if (NULL == recipe_file_json) { + printf("Parse recipe_file_buf failed!\n"); + return -1; + } + + control_protocol->recipe = (struct ControlRecipe *)PrivMalloc(sizeof(struct ControlRecipe)); + memset(control_protocol->recipe, 0, sizeof(struct ControlRecipe)); + + /*Get basic information from recipe file*/ + if (RecipeBasicInformation(control_protocol->recipe, control_protocol->protocol_type, recipe_file_json) < 0) { + return -1; + } + + /*Get the variable need to read from recipe file*/ + RecipeReadVariableItem(control_protocol->recipe, control_protocol->protocol_type, recipe_file_json); + + cJSON_Delete(recipe_file_json); + printf("Read and parse recipe file done!\n"); +#endif + + return 0; +} + +/*Control Framework Protocol Open*/ +int ControlProtocolOpen(struct ControlProtocol *control_protocol) +{ + CONTROL_PARAM_CHECK(control_protocol); + CONTROL_PARAM_CHECK(control_protocol->done); + int ret = -1; + + if (control_protocol->done->_open) { + ret = control_protocol->done->_open(control_protocol); + } + + return ret; +} + +/*Control Framework Protocol Close*/ +int ControlProtocolClose(struct ControlProtocol *control_protocol) +{ + CONTROL_PARAM_CHECK(control_protocol); + CONTROL_PARAM_CHECK(control_protocol->done); + int ret = -1; + + if (control_protocol->done->_close) { + ret = control_protocol->done->_close(control_protocol); + } + + return ret; +} + +/*Control Framework Protocol Read Date*/ +int ControlProtocolRead(struct ControlProtocol *control_protocol, void *buf, size_t len) +{ + CONTROL_PARAM_CHECK(control_protocol); + CONTROL_PARAM_CHECK(control_protocol->done); + int ret = -1; + + if (control_protocol->done->_read) { + ret = control_protocol->done->_read(control_protocol, buf, len); + } + + return ret; +} + +/*Control Framework Protocol Write Cmd*/ +int ControlProtocolWrite(struct ControlProtocol *control_protocol, const void *buf, size_t len) +{ + CONTROL_PARAM_CHECK(control_protocol); + CONTROL_PARAM_CHECK(control_protocol->done); + int ret = -1; + + if (control_protocol->done->_write) { + ret = control_protocol->done->_write(control_protocol, buf, len); + } + + return ret; +} + +/*Control Framework Protocol Ioctl*/ +int ControlProtocolIoctl(struct ControlProtocol *control_protocol, int cmd, void *args) +{ + CONTROL_PARAM_CHECK(control_protocol); + CONTROL_PARAM_CHECK(control_protocol->done); + int ret = -1; + + if (control_protocol->done->_ioctl) { + ret = control_protocol->done->_ioctl(control_protocol, cmd, args); + } + + return ret; +} + +/** + * @description: Control Framework Init + * @return success: 0 error : -1 + */ +int ControlFrameworkInit(void) +{ + int ret = 0; + + control_protocol = (struct ControlProtocol *)PrivMalloc(sizeof(struct ControlProtocol)); + if (NULL == control_protocol) { + printf("%s malloc control protocol failed!\n", __func__); + PrivFree(control_protocol); + ret = -1; + goto _out; + } + + //Control Protocol Struct Init + ret = ControlProtocolInit(control_protocol); + if (ret < 0) { + printf("%s failed!\n", __func__); + PrivFree(control_protocol); + goto _out; + } + + //Read Recipe File, Get Control Protocol Configure Param + ret = ControlAnalyzeRecipe(control_protocol, CONTROL_RECIPE_FILE); + if (ret < 0) { + printf("%s failed!\n", __func__); + PrivFree(control_protocol); + goto _out; + } + + control_protocol->protocol_status = CONTROL_REGISTERED; + + ret = ControlPeripheralInit(control_protocol->recipe); + if (ret < 0) { + printf("%s failed!\n", __func__); + PrivFree(control_protocol); + goto _out; + } + +_out: + return ret; +} diff --git a/APP_Framework/Framework/control/shared/control.h b/APP_Framework/Framework/control/shared/control.h index bbf5772b4..4f7fb966f 100644 --- a/APP_Framework/Framework/control/shared/control.h +++ b/APP_Framework/Framework/control/shared/control.h @@ -12,13 +12,103 @@ /** * @file control.h - * @brief control framework code + * @brief DEFINE code for control framework app * @version 3.0 * @author AIIT XUOS Lab * @date 2022-09-27 */ -#include -#include +#ifndef CONTROL_H +#define CONTROL_H +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ControlProtocol; +typedef struct ControlProtocol *ControlProtocolType; +typedef struct ControlData *ControlDataType; + +struct ControlDone +{ + int (*_open)(struct ControlProtocol *control_protocol); + int (*_close)(struct ControlProtocol *control_protocol); + int (*_read)(struct ControlProtocol *control_protocol, void *buf, size_t len); + int (*_write)(struct ControlProtocol *control_protocol, const void *buf, size_t len); + int (*_ioctl)(struct ControlProtocol *control_protocol, int cmd, void *args); +}; + +typedef enum +{ + PROTOCOL_S7 = 1, + PROTOCOL_MODBUS_TCP, + PROTOCOL_MODBUS_UART, + PROTOCOL_OPC_UA, + PROTOCOL_FINS, + PROTOCOL_MELSEC_1E, + PROTOCOL_MELSEC_3E_Q_L, + PROTOCOL_MELSEC_3E_IQ_R, + PROTOCOL_MELSEC_1C, + PROTOCOL_MELSEC_3C, + PROTOCOL_END +}ProtocolType; + +typedef enum +{ + CONTROL_INIT, + CONTROL_REGISTERED, + CONTROL_UNREGISTERED, +}ProtocolStatus; + +struct ControlProtocol +{ + char *name; + ProtocolType protocol_type; + ProtocolStatus protocol_status; + + struct ControlRecipe *recipe; + struct ControlDone *done; + + void *args; + + sem_t sem; + pthread_mutex_t lock; + //struct DoublelistNode link; +}; + +/*Control Framework Protocol Init*/ +int ControlFrameworkInit(void); + +/*Control Framework Find certain Protocol*/ +ControlProtocolType ControlProtocolFind(void); + +// /*Control Framework Protocol Register*/ +// int ControlProtocolRegister(struct ControlProtocol *control_protocol); + +// /*Control Framework Protocol Unregister*/ +// int ControlProtocolUnregister(struct ControlProtocol *control_protocol); + +/*Control Framework Protocol Open*/ +int ControlProtocolOpen(struct ControlProtocol *control_protocol); + +/*Control Framework Protocol Close*/ +int ControlProtocolClose(struct ControlProtocol *control_protocol); + +/*Control Framework Protocol Read*/ +int ControlProtocolRead(struct ControlProtocol *control_protocol, void *buf, size_t len); + +/*Control Framework Protocol Write*/ +int ControlProtocolWrite(struct ControlProtocol *control_protocol, const void *buf, size_t len); + +/*Control Framework Protocol Ioctl*/ +int ControlProtocolIoctl(struct ControlProtocol *control_protocol, int cmd, void *args); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/APP_Framework/Framework/control/shared/control_def.c b/APP_Framework/Framework/control/shared/control_def.c new file mode 100644 index 000000000..1e77cef62 --- /dev/null +++ b/APP_Framework/Framework/control/shared/control_def.c @@ -0,0 +1,364 @@ +/* +* Copyright (c) 2022 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** + * @file control_def.c + * @brief code for control framework + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2022-10-9 + */ + +#include + +/*using cirtular area to receive data*/ +#define PLC_DATA_LENGTH 1024 +struct CircularAreaApp *g_circular_area; +static pthread_t recv_plc_data_task; + +/*extern function*/ +extern void *ReceivePlcDataTask(void *parameter); + +#ifdef CONTROL_PROTOCOL_FINS +extern int FinsProtocolInit(struct ControlRecipe *p_recipe); +#endif + +/* +CONTROL FRAMEWORK READ DATA FORMAT: +| HEAD |device_id|read data length|read item count| data | +|2 Bytes| 2 Bytes | 2 Bytes | 2 Bytes |read data length Bytes| +*/ +#define CONTROL_DATA_HEAD_LENGTH 8 +#define CONTROL_DATA_HEAD_1 0xAA +#define CONTROL_DATA_HEAD_2 0xBB + +typedef int (*ControlProtocolInitFunc)(struct ControlRecipe *p_recipe); + +struct ControlProtocolInitParam +{ + int protocol_type; + const ControlProtocolInitFunc fn; +}; + +static struct ControlProtocolInitParam protocol_init[] = +{ +#ifdef CONTROL_PROTOCOL_FINS + { PROTOCOL_FINS, FinsProtocolInit }, +#endif + + { PROTOCOL_END, NULL }, +}; + +static int ControlProtocolInitDesc(struct ControlRecipe *p_recipe, struct ControlProtocolInitParam sub_protocol_desc[]) +{ + int i = 0; + int ret = 0; + for( i = 0; sub_protocol_desc[i].fn != NULL; i++ ) { + if (p_recipe->protocol_type == sub_protocol_desc[i].protocol_type) { + ret = sub_protocol_desc[i].fn(p_recipe); + printf("control protocol initialize %d %s\n", sub_protocol_desc[i].protocol_type, ret == 0 ? "success" : "failed"); + break; + } + } + return ret; +} + +static void FormatDataHeader(struct ControlRecipe *p_recipe) +{ + uint16_t plc_read_data_length = CONTROL_DATA_HEAD_LENGTH + p_recipe->total_data_length;//Head length is CONTROL_DATA_HEAD_LENGTH + uint8_t *data = p_recipe->protocol_data->data; + + data[0] = CONTROL_DATA_HEAD_1; + data[1] = CONTROL_DATA_HEAD_2; + data[2] = (p_recipe->device_id) >> 8; + data[3] = p_recipe->device_id; + data[4] = (plc_read_data_length) >> 8; + data[5] = plc_read_data_length; + data[6] = (p_recipe->read_item_count) >> 8; + data[7] = p_recipe->read_item_count; +} + +static uint16_t GetRecipeTotalDataLength(cJSON* read_item_list_json) +{ + uint16_t read_item_count = cJSON_GetArraySize(read_item_list_json); + uint16_t total_data_length = 0; + for (uint16_t read_item_index = 0; read_item_index < read_item_count; read_item_index++) { + cJSON* read_item_json = cJSON_GetArrayItem(read_item_list_json, read_item_index); + UniformValueType value_type = cJSON_GetObjectItem(read_item_json, "value_type")->valueint; + total_data_length += GetValueTypeMemorySize(value_type); + } + return total_data_length; +} + +static void ControlBasicSerialConfig(struct ControlRecipe *p_recipe, cJSON *p_recipe_file_json) +{ + cJSON *p_serial_config_json = cJSON_GetObjectItem(p_recipe_file_json, "serial_config"); + p_recipe->serial_config.baud_rate = cJSON_GetObjectItem(p_serial_config_json, "baud_rate")->valueint; + p_recipe->serial_config.data_bits = cJSON_GetObjectItem(p_serial_config_json, "data_bits")->valueint; + p_recipe->serial_config.stop_bits = cJSON_GetObjectItem(p_serial_config_json, "stop_bits")->valueint; + p_recipe->serial_config.check_mode = cJSON_GetObjectItem(p_serial_config_json, "check_mode")->valueint; + printf("Serial_config: baud_rate: %d, data_bits: %d, stop_bits: %d, check_mode is %d\n", + p_recipe->serial_config.baud_rate, p_recipe->serial_config.data_bits, p_recipe->serial_config.stop_bits, p_recipe->serial_config.check_mode); +} + +static void ControlBasicSocketConfig(struct ControlRecipe *p_recipe, cJSON *p_recipe_file_json) +{ + cJSON *p_socket_address_json = cJSON_GetObjectItem(p_recipe_file_json, "socket_config"); + char *plc_ip_string = cJSON_GetObjectItem(p_socket_address_json, "plc_ip")->valuestring; + sscanf(plc_ip_string, "%d.%d.%d.%d", + p_recipe->socket_config.plc_ip, + p_recipe->socket_config.plc_ip + 1, + p_recipe->socket_config.plc_ip + 2, + p_recipe->socket_config.plc_ip + 3); + + char *local_ip_string = cJSON_GetObjectItem(p_socket_address_json, "local_ip")->valuestring; + sscanf(local_ip_string, "%d.%d.%d.%d", + p_recipe->socket_config.local_ip, + p_recipe->socket_config.local_ip + 1, + p_recipe->socket_config.local_ip + 2, + p_recipe->socket_config.local_ip + 3); + + char *gateway_ip_string = cJSON_GetObjectItem(p_socket_address_json, "gateway")->valuestring; + sscanf(gateway_ip_string, "%d.%d.%d.%d", + p_recipe->socket_config.gateway, + p_recipe->socket_config.gateway + 1, + p_recipe->socket_config.gateway + 2, + p_recipe->socket_config.gateway + 3); + + char *netmask_string = cJSON_GetObjectItem(p_socket_address_json, "netmask")->valuestring; + sscanf(netmask_string, "%d.%d.%d.%d", + p_recipe->socket_config.netmask, + p_recipe->socket_config.netmask + 1, + p_recipe->socket_config.netmask + 2, + p_recipe->socket_config.netmask + 3); + + p_recipe->socket_config.port = cJSON_GetObjectItem(p_socket_address_json, "port")->valueint; + printf("Socket_config: local ip is %s, plc ip is %s, gateway is %s, port is %d.\n", + local_ip_string, plc_ip_string, gateway_ip_string, p_recipe->socket_config.port); +} + +void ControlPrintList(char name[5], uint8_t *number_list, uint16_t length) +{ + printf("\n******************%5s****************\n", name); + for (int32_t i = 0;i < length;i ++) { + printf("%03x ", number_list[i]); + } + printf("\n**************************************\n"); +} + +int ControlConnectSocket(BasicSocketPlc *p_plc) +{ + if (p_plc->socket >= 0) + return 0; + + struct sockaddr_in plc_addr_in; + plc_addr_in.sin_family = AF_INET; + plc_addr_in.sin_port = htons(p_plc->port); + + char ip_string[20] = {0}; + sprintf(ip_string, "%u.%u.%u.%u", p_plc->ip[0], p_plc->ip[1], p_plc->ip[2], p_plc->ip[3]); + plc_addr_in.sin_addr.s_addr = inet_addr(ip_string); + memset(&(plc_addr_in.sin_zero), 0, sizeof(plc_addr_in.sin_zero)); + + int plc_socket = socket(AF_INET, SOCK_STREAM, 0); + int flag = 1; + + struct timeval timeout; + timeout.tv_sec = 10; + timeout.tv_usec = 0; + if (setsockopt(plc_socket, IPPROTO_TCP, TCP_NODELAY, (void*)&flag, sizeof(flag)) < 0) { + printf("Error setting TCP_NODELAY function!\n"); + return -1; + } + if (setsockopt(plc_socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, (socklen_t)sizeof(struct timeval)) < 0) { + printf("Error setting SO_SNDTIMEO function!\n"); + return -2; + } + if (setsockopt(plc_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, (socklen_t)sizeof(struct timeval)) < 0) { + printf("Error setting SO_RCVTIMEO function!\n"); + return -3; + } + + if (plc_socket < 0) { + printf("Get socket error!\n"); + return -4; + } + + if (connect(plc_socket, (struct sockaddr*)&plc_addr_in, sizeof(struct sockaddr)) == -1) { + printf("Connect plc socket failed!\n"); + closesocket(plc_socket); + return -5; + } else { + p_plc->socket = plc_socket; + printf("Connect plc socket success!\n"); + return 0; + } +} + +int ControlDisconnectSocket(BasicSocketPlc *p_plc) +{ + if (p_plc->socket < 0) + return -1; + + int error = closesocket(p_plc->socket); + if (0 == error) + p_plc->socket = -1; + + return error; +} + +int ControlProtocolOpenDef(struct ControlProtocol *control_protocol) +{ + g_circular_area = CircularAreaAppInit(PLC_DATA_LENGTH); + if (NULL == g_circular_area) { + printf("%s CircularAreaInit error\n", __func__); + return -1; + } + + control_protocol->args = (void *)g_circular_area; + + pthread_attr_t attr; + attr.schedparam.sched_priority = 19; + attr.stacksize = 2048; + + PrivTaskCreate(&recv_plc_data_task, &attr, &ReceivePlcDataTask, control_protocol); + PrivTaskStartup(&recv_plc_data_task); +} + +int ControlProtocolCloseDef(void) +{ + CircularAreaAppRelease(g_circular_area); + + PrivTaskDelete(recv_plc_data_task, 0); + + return 0; +} + +uint8_t GetValueTypeMemorySize(UniformValueType uniform_value_type) +{ + switch (uniform_value_type) + { + case UNIFORM_BOOL: + case UNIFORM_INT8: + case UNIFORM_UINT8: + return 1; + break; + case UNIFORM_INT16: + case UNIFORM_UINT16: + return 2; + break; + case UNIFORM_INT32: + case UNIFORM_UINT32: + case UNIFORM_FLOAT: + return 4; + break; + case UNIFORM_DOUBLE: + return 8; + break; + default: + break; + } + + return 0; +} + +int ControlPeripheralInit(struct ControlRecipe *p_recipe) +{ + switch (p_recipe->communication_type) + { + case 0://Socket Init + lwip_config_tcp(0, p_recipe->socket_config.local_ip, p_recipe->socket_config.netmask, p_recipe->socket_config.gateway); + break; + case 1://Serial Init + // Uart485Init(p_recipe->serial_config.baud_rate, p_recipe->serial_config.data_bits, + // p_recipe->serial_config.stop_bits, p_recipe->serial_config.check_mode); + break; + default: + break; + } + + return 0; +} + +int RecipeBasicInformation(struct ControlRecipe *p_recipe, int protocol_type, cJSON *p_recipe_file_json) +{ + if (protocol_type != (ProtocolType)(cJSON_GetObjectItem(p_recipe_file_json, "protocol_type")->valueint)) { + printf("protocol type not match!\n"); + return -1; + } + p_recipe->protocol_type = protocol_type; + + p_recipe->device_id = cJSON_GetObjectItem(p_recipe_file_json, "device_id")->valueint; + strncpy(p_recipe->device_name, cJSON_GetObjectItem(p_recipe_file_json, "device_name")->valuestring, 20); + p_recipe->read_period = cJSON_GetObjectItem(p_recipe_file_json, "read_period")->valueint; + p_recipe->communication_type = cJSON_GetObjectItem(p_recipe_file_json, "communication_type")->valueint; + + printf("\n**************** RECIPE BASIC INFORMATION ******************\n"); + printf("\nprotocol_type: %d, communication_type: %d, device_id: %d, device_name: %s, read_period is %d\n", + p_recipe->protocol_type, p_recipe->communication_type, p_recipe->device_id, p_recipe->device_name, p_recipe->read_period); + + switch (p_recipe->communication_type) + { + case 0://Socket Config + ControlBasicSocketConfig(p_recipe, p_recipe_file_json); + break; + case 1://Serial Config + ControlBasicSerialConfig(p_recipe, p_recipe_file_json); + break; + default: + break; + } + + printf("\n************************************************************\n"); +} + +void RecipeReadVariableItem(struct ControlRecipe *p_recipe, int protocol_type, cJSON *p_recipe_file_json) +{ + int ret = 0; + + ProtocolFormatInfo protocol_format_info; + memset(&protocol_format_info, 0, sizeof(ProtocolFormatInfo)); + + cJSON *read_item_list_json = cJSON_GetObjectItem(p_recipe_file_json, "read_item_list"); + if (cJSON_IsArray(read_item_list_json)) { + /*Get Recipe Variable Item Count and total length*/ + p_recipe->read_item_count = cJSON_GetArraySize(read_item_list_json); + p_recipe->total_data_length = GetRecipeTotalDataLength(read_item_list_json); + + /*Malloc Read Data Pointer, Reference "CONTROL FRAMEWORK READ DATA FORMAT"*/ + p_recipe->protocol_data = PrivMalloc(sizeof(struct ProtocolData)); + p_recipe->protocol_data->data = PrivMalloc(CONTROL_DATA_HEAD_LENGTH + p_recipe->total_data_length); + p_recipe->protocol_data->data_length = CONTROL_DATA_HEAD_LENGTH + p_recipe->total_data_length; + memset(p_recipe->protocol_data->data, 0, p_recipe->protocol_data->data_length); + + /*Init The Control Protocol*/ + ControlProtocolInitDesc(p_recipe, protocol_init); + + /*Format Data Header, Reference "CONTROL FRAMEWORK READ DATA FORMAT"*/ + FormatDataHeader(p_recipe); + + for (uint16_t read_item_index = 0; read_item_index < p_recipe->read_item_count; read_item_index ++) { + cJSON *read_single_item_json = cJSON_GetArrayItem(read_item_list_json, read_item_index); + + protocol_format_info.read_single_item_json = read_single_item_json; + protocol_format_info.read_item_index = read_item_index; + + /*Format Protocol Cmd By Analyze Variable Item One By One*/ + ret = p_recipe->ControlProtocolFormatCmd(p_recipe, &protocol_format_info); + if (ret < 0) { + printf("%s read %d item failed!\n", __func__, read_item_index); + continue; + } + } + } +} + diff --git a/APP_Framework/Framework/control/shared/control_def.h b/APP_Framework/Framework/control/shared/control_def.h new file mode 100644 index 000000000..fafb7d6f2 --- /dev/null +++ b/APP_Framework/Framework/control/shared/control_def.h @@ -0,0 +1,161 @@ +/* +* Copyright (c) 2022 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** + * @file control_def.h + * @brief DEFINE code for control framework + * @version 3.0 + * @author AIIT XUOS Lab + * @date 2022-10-08 + */ + +#ifndef CONTROL_DEF_H +#define CONTROL_DEF_H + +#include +#include +#include +#include + +#ifdef LIB_USING_CJSON +#include +#endif + +#ifdef BSP_USING_LWIP +#include "lwip/sys.h" +#include "lwip/sockets.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define CONTROL_PARAM_CHECK(param) \ + do \ + { \ + if(NULL == param) { \ + KPrintf("CONTROL CHECK FAILED ...%s %d %s is NULL.\n", __FUNCTION__, __LINE__, #param); \ + return -1; \ + } \ + }while (0) + +#ifdef BSP_USING_LWIP +#define socket_write lwip_write +#define socket_read lwip_read +#endif + +typedef enum +{ + UNIFORM_BOOL = 1, + UNIFORM_INT8, + UNIFORM_INT16, + UNIFORM_INT32, + UNIFORM_UINT8, + UNIFORM_UINT16, + UNIFORM_UINT32, + UNIFORM_DOUBLE, + UNIFORM_FLOAT +}UniformValueType; + +typedef struct +{ + uint8_t ip[4]; + uint16_t port; + int32_t socket; + int8_t secondary_connect_flag;//0: enble, no connected; 1: enable, connected; -1: disable +}BasicSocketPlc; + +typedef struct +{ + uint16_t command_length; + uint16_t data_size; + uint8_t *p_command; + uint8_t *p_data; +}BasicPlcDataInfo; + +typedef struct +{ + cJSON *read_single_item_json; + uint16_t read_item_index;//Variable item index(1 ++) +}ProtocolFormatInfo; + +struct ProtocolData +{ + uint8_t *data; + uint16_t data_length; +}; + +struct SerialConfig +{ + uint32_t baud_rate; + uint8_t data_bits; + uint8_t stop_bits; + uint8_t check_mode; +}; + +struct SocketConfig +{ + uint16_t port; + uint8_t plc_ip[4]; + uint8_t local_ip[4]; + uint8_t gateway[4]; + uint8_t netmask[4]; +}; + +struct ControlRecipe +{ + char device_name[20]; + uint16_t device_id; + uint16_t read_period; + uint16_t read_item_count; + uint16_t total_data_length; + uint8_t communication_type; + + ProtocolType protocol_type; + + void *read_item; + + struct SerialConfig serial_config; + struct SocketConfig socket_config; + + struct ProtocolData *protocol_data; + + int (*ControlProtocolFormatCmd)(struct ControlRecipe *p_recipe, ProtocolFormatInfo *protocol_format_info); +}; + +/*Get Value Type Memory Size*/ +uint8_t GetValueTypeMemorySize(UniformValueType uniform_value_type); + +/*Get basic information from recipe file*/ +int RecipeBasicInformation(struct ControlRecipe *p_recipe, int protocol_type, cJSON *p_recipe_file_json); + +/*Get the variable need to read from recipe file*/ +void RecipeReadVariableItem(struct ControlRecipe *p_recipe, int protocol_type, cJSON *p_recipe_file_json); + +int ControlPeripheralInit(struct ControlRecipe *p_recipe); + +void ControlPrintList(char name[5], uint8_t *number_list, uint16_t length); + +int ControlConnectSocket(BasicSocketPlc *p_plc); + +int ControlDisconnectSocket(BasicSocketPlc *p_plc); + +int ControlProtocolOpenDef(struct ControlProtocol *control_protocol); + +int ControlProtocolCloseDef(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/APP_Framework/Applications/framework_init.c b/APP_Framework/Framework/framework_init.c similarity index 96% rename from APP_Framework/Applications/framework_init.c rename to APP_Framework/Framework/framework_init.c index 9612fd635..20d56ab29 100644 --- a/APP_Framework/Applications/framework_init.c +++ b/APP_Framework/Framework/framework_init.c @@ -15,6 +15,7 @@ extern int SensorFrameworkInit(void); extern int AdapterFrameworkInit(void); +extern int ControlFrameworkInit(void); extern int Adapter4GInit(void); extern int AdapterNbiotInit(void); @@ -73,6 +74,10 @@ static struct InitDesc framework[] = { "connection_framework", AdapterFrameworkInit }, #endif +#ifdef SUPPORT_CONTROL_FRAMEWORK + { "control_framework", ControlFrameworkInit }, +#endif + { "NULL", NULL }, }; @@ -229,6 +234,10 @@ int FrameworkInit(void) ConnectionDeviceFrameworkInit(framework); #endif +#ifdef SUPPORT_CONTROL_FRAMEWORK + ControlFrameworkInit(); +#endif + #ifdef LIB_LV lv_port_init(); #endif diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/Kconfig b/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/Kconfig index 223f5e966..72eef20d3 100644 --- a/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/Kconfig @@ -49,6 +49,7 @@ menuconfig BSP_USING_SDIO if BSP_USING_SDIO source "$BSP_DIR/third_party_driver/sdio/Kconfig" endif + menuconfig BSP_USING_LCD bool "Using LCD device" default n @@ -56,6 +57,7 @@ menuconfig BSP_USING_LCD if BSP_USING_LCD source "$BSP_DIR/third_party_driver/lcd/Kconfig" endif + menuconfig BSP_USING_TOUCH bool "Using TOUCH device" default n diff --git a/Ubiquitous/XiZi_IIoT/path_kernel.mk b/Ubiquitous/XiZi_IIoT/path_kernel.mk index 3731ae559..917d6076c 100755 --- a/Ubiquitous/XiZi_IIoT/path_kernel.mk +++ b/Ubiquitous/XiZi_IIoT/path_kernel.mk @@ -440,6 +440,7 @@ endif endif +KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Applications/general_functions/circular_area # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Applications/general_functions/list # ifeq ($(CONFIG_SUPPORT_SENSOR_FRAMEWORK), y) @@ -472,9 +473,11 @@ ifeq ($(CONFIG_SUPPORT_CONTROL_FRAMEWORK), y) KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control/shared # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control/ipc_protocol # +KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control/ipc_protocol/include # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control/ipc_protocol/modbus_tcp # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control/ipc_protocol/modbus_uart # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control/plc_protocol # +KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control/plc_protocol/include # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control/plc_protocol/fins # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control/plc_protocol/melsec # KERNELPATHS += -I$(KERNEL_ROOT)/../../APP_Framework/Framework/control/plc_protocol/opcua #