forked from xuos/xiuos
feat add control_framework, support fins protocol, compile OK
This commit is contained in:
parent
72e09d82e7
commit
5560fc5318
|
@ -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
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
SRC_DIR := list
|
||||
SRC_DIR := list circular_area
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -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
|
|
@ -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")
|
|
@ -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;
|
||||
}
|
|
@ -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 <string.h>
|
||||
#include <transform.h>
|
||||
|
||||
#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
|
|
@ -1,3 +1,4 @@
|
|||
SRC_FILES := framework_init.c
|
||||
SRC_DIR := transform_layer
|
||||
|
||||
ifeq ($(CONFIG_SUPPORT_SENSOR_FRAMEWORK),y)
|
||||
|
|
|
@ -21,11 +21,8 @@
|
|||
#include <adapter.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
SRC_FILES :=
|
||||
SRC_FILES := fins.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
|
|
|
@ -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 <fins.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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 <control_def.h>
|
||||
|
||||
#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
|
10
APP_Framework/Framework/control/shared/control_file.c → APP_Framework/Framework/control/plc_protocol/include/melsec.h
Executable file → Normal file
10
APP_Framework/Framework/control/shared/control_file.c → APP_Framework/Framework/control/plc_protocol/include/melsec.h
Executable file → Normal file
|
@ -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
|
||||
*/
|
15
APP_Framework/Framework/control/shared/control_file.h → APP_Framework/Framework/control/plc_protocol/include/opcua.h
Executable file → Normal file
15
APP_Framework/Framework/control/shared/control_file.h → APP_Framework/Framework/control/plc_protocol/include/opcua.h
Executable file → Normal file
|
@ -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
|
||||
*/
|
|
@ -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
|
||||
*/
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 <control.h>
|
||||
#include <control_def.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 <control_file.h>
|
||||
#include <cJSON.h>
|
||||
#ifndef CONTROL_H
|
||||
#define CONTROL_H
|
||||
|
||||
#include <transform.h>
|
||||
#include <list.h>
|
||||
|
||||
#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
|
||||
|
||||
|
|
|
@ -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 <control_def.h>
|
||||
|
||||
/*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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <transform.h>
|
||||
#include <list.h>
|
||||
#include <circular_area_app.h>
|
||||
#include <control.h>
|
||||
|
||||
#ifdef LIB_USING_CJSON
|
||||
#include <cJSON.h>
|
||||
#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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 #
|
||||
|
|
Loading…
Reference in New Issue