1、feat add modbus tcp protocol for control framework; 2、fix spi6 io define error on hc32f4a0 board from Liu_Weichao

it is OK
This commit is contained in:
xuedongliang
2023-01-18 15:06:08 +08:00
60 changed files with 3955 additions and 221 deletions
+22 -1
View File
@@ -2,12 +2,33 @@ 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
config CONTROL_USING_SERIAL_485
bool
default n
config CONTROL_USING_SOCKET
bool
default n
if CONTROL_USING_SOCKET
choice
prompt "select socket lib"
default CONTROL_SOCKET_LWIP
config CONTROL_SOCKET_LWIP
bool "support socket, using LwIP"
select BSP_USING_LWIP
config CONTROL_SOCKET_W5500
bool "support socket, using W5500"
select BSP_USING_W5500
endchoice
endif
config CONTROL_RECIPE_FILE
string "control framework recipe file name"
default "test_recipe.json"
@@ -1,8 +1,15 @@
config CONTROL_PROTOCOL_MODBUS_TCP
bool "Using modbus_tcp control protocol"
default n
select CONTROL_USING_SOCKET
if CONTROL_PROTOCOL_MODBUS_TCP
source "$APP_DIR/Framework/control/ipc_protocol/modbus_tcp/Kconfig"
endif
config CONTROL_PROTOCOL_MODBUS_UART
bool "Using modbus_uart control protocol"
default n
select CONTROL_USING_SERIAL_485
if CONTROL_PROTOCOL_MODBUS_UART
source "$APP_DIR/Framework/control/ipc_protocol/modbus_uart/Kconfig"
endif
@@ -0,0 +1,69 @@
/*
* 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 modbus_tcp.h
* @brief support modbus_tcp function
* @version 3.0
* @author AIIT XUOS Lab
* @date 2022.09.27
*/
#ifndef MODBUS_TCP_H
#define MODBUS_TCP_H
#include <control_def.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MODBUS_TCP_UNIT_ID 0x01
#define MODBUS_TCP_READ_CMD_LENGTH 0x0C
#define MODBUS_TCP_WRITE_SINGLE_CMD_LENGTH 0x0C
#define MODBUS_TCP_WRITE_MULTI_HEAD 0x07
typedef enum
{
READ_COIL_STATUS = 0x01, //read coil cmd
READ_INPUT_STATUS = 0x02, //read input colr cmd
READ_HOLDING_REGISTER = 0x03, //read register info cmd
READ_INPUT_REGISTER = 0x04, //read input register cmd
WRITE_SINGLE_COIL = 0x05, //write coil cmd
WRITE_SINGLE_REGISTER = 0x06, //write single register cmd
WRITE_MULTIPLE_COIL = 0x0F, //write multi coil cmd
WRITE_MULTIPLE_REGISTER = 0x10 //write multi register cmd
}ModbusTcpFunctionCode;
typedef struct
{
BasicPlcDataInfo base_data_info;
ModbusTcpFunctionCode function_code;
}ModbusTcpDataInfo;
typedef struct
{
ModbusTcpDataInfo data_info;
UniformValueType value_type;
char value_name[20];
uint16_t start_address;
uint16_t quantity;
}ModbusTcpReadItem;
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,67 @@
/*
* 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 modbus_uart.h
* @brief support modbus_uart function
* @version 3.0
* @author AIIT XUOS Lab
* @date 2022.12.29
*/
#ifndef MODBUS_UART_H
#define MODBUS_UART_H
#include <control_def.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MODBUS_UART_READ_CMD_LENGTH 0x08
#define MODBUS_UART_WRITE_CMD_LENGTH 0x08
typedef enum
{
READ_COIL_STATUS = 0x01, //read coil cmd
READ_INPUT_STATUS = 0x02, //read input colr cmd
READ_HOLDING_REGISTER = 0x03, //read register info cmd
READ_INPUT_REGISTER = 0x04, //read input register cmd
WRITE_SINGLE_COIL = 0x05, //write coil cmd
WRITE_SINGLE_REGISTER = 0x06, //write single register cmd
WRITE_MULTIPLE_COIL = 0x0F, //write multi coil cmd
WRITE_MULTIPLE_REGISTER = 0x10 //write multi register cmd
}ModbusUartFunctionCode;
typedef struct
{
BasicPlcDataInfo base_data_info;
ModbusUartFunctionCode function_code;
}ModbusUartDataInfo;
typedef struct
{
ModbusUartDataInfo data_info;
UniformValueType value_type;
char value_name[20];
uint8_t station;
uint16_t start_address;
uint16_t quantity;
}ModbusUartReadItem;
#ifdef __cplusplus
}
#endif
#endif
@@ -15,6 +15,465 @@
* @brief support modbus_tcp function
* @version 3.0
* @author AIIT XUOS Lab
* @date 2022.09.27
* @date 2022.12.09
*/
#include <modbus_tcp.h>
/*using cirtular area to receive write-data*/
#define CA_DATA_LENGTH 512
struct CircularAreaApp *g_write_data;
static BasicSocketPlc plc_socket = {0};
static uint8_t recv_buff[1024] = {0};
/**
* @description: Modbus Tcp Data Transform from Receive Buffer To Control-Data
* @param p_read_item - read item pointer
* @param recv_buff - receive buff
* @return success : 0 error : -1
*/
static void ModbusTcpTransformRecvBuffToData(ModbusTcpReadItem *p_read_item, uint8_t *recv_buff)
{
uint8_t head_length = 9;
uint8_t *data_buffer;
ModbusTcpDataInfo *p_modbus_tcp_data_info = &(p_read_item->data_info);
uint16_t quantity = p_read_item->quantity;
ModbusTcpFunctionCode function_code = p_modbus_tcp_data_info->function_code;
uint8_t *p_data = p_modbus_tcp_data_info->base_data_info.p_data;
uint8_t bytes_count = recv_buff[8];
if ((WRITE_SINGLE_COIL == function_code) || (WRITE_SINGLE_REGISTER == function_code) ||
(WRITE_MULTIPLE_COIL == function_code) || (WRITE_MULTIPLE_REGISTER == function_code)) {
head_length = 10;
if (p_modbus_tcp_data_info->base_data_info.command_ready) {
p_modbus_tcp_data_info->base_data_info.command_ready = 0;
}
}
data_buffer = recv_buff + head_length;//remove head data
if (READ_COIL_STATUS == function_code || READ_INPUT_STATUS == function_code) {
printf("Receive data is ");
for (int i = 0;i < bytes_count;i ++) {
for (int j = 0;j < 8;j ++) {
if ((i * 8 + j) < p_read_item->quantity) {
*(uint8_t *)(p_data + i * 8 + j) = ((data_buffer[i] >> j) & 0x01) ? 1 : 0;
printf("0x%x", *(uint8_t *)(p_data + i * 8 + j));
}
}
}
} else if (READ_HOLDING_REGISTER == function_code || READ_INPUT_REGISTER == function_code) {
printf("Receive data is ");
for (uint16_t i = 0; i < quantity; i ++) {
((int16_t *)p_data)[i] = ((int16_t *)data_buffer)[quantity - i - 1];
printf("0x%x 0x%x ", p_data[2 * i], p_data[2 * i + 1]);
}
}
printf("\n");
}
#ifdef CONTROL_USING_SOCKET
/**
* @description: Modbus Tcp Get Data From Socket
* @param socket - socket
* @param p_read_item - read item pointer
* @return success : 0 error : -1 -2
*/
static int ModbusTcpGetData(int32_t socket, ModbusTcpReadItem *p_read_item)
{
uint8_t try_count = 0;
int32_t write_error = 0;
ModbusTcpDataInfo *p_modbus_tcp_data_info = &(p_read_item->data_info);
BasicPlcDataInfo *p_base_data_info = &(p_modbus_tcp_data_info->base_data_info);
if (!p_base_data_info->command_ready) {
//command not ready, just return
return 1;
}
memset(recv_buff, 0, sizeof(recv_buff));
while (try_count < 10) {
ControlPrintfList("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!\n", 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! read again\n", errno);
memset(recv_buff, 0, sizeof(recv_buff));
recv_length = socket_read(socket, recv_buff, sizeof(recv_buff));
if (recv_length > 0) {
ControlPrintfList("RECV", recv_buff, recv_length);
ModbusTcpTransformRecvBuffToData(p_read_item, recv_buff);
return 0;
}
} else {
ControlPrintfList("RECV", recv_buff, recv_length);
ModbusTcpTransformRecvBuffToData(p_read_item, recv_buff);
return 0;
}
}
if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK)) {
printf("Send command failed, errno is %d!\n", errno);
continue;
} else {
return -1;
}
}
return -2;
}
#endif
/**
* @description: Modbus Tcp Data Info Init
* @param p_read_item - read item pointer
* @param index - read item index
* @param p_data - control-data pointer
* @return success : 0 error : -1
*/
static int ModbusTcpInitialDataInfo(ModbusTcpReadItem *p_read_item, uint16_t index, uint8_t *p_data)
{
uint16_t command_index = 0;
uint8_t function_code = p_read_item->data_info.function_code;
uint16_t start_address = p_read_item->start_address;
uint16_t quantity = p_read_item->quantity;
BasicPlcDataInfo *p_base_data_info = &(p_read_item->data_info.base_data_info);
switch (function_code)
{
case READ_COIL_STATUS:
case READ_INPUT_STATUS:
case READ_HOLDING_REGISTER:
case READ_INPUT_REGISTER:
p_base_data_info->command_length = MODBUS_TCP_READ_CMD_LENGTH;
p_base_data_info->p_command = PrivMalloc(p_base_data_info->command_length);
p_base_data_info->p_data = p_data;
p_base_data_info->command_ready = 1;
break;
case WRITE_SINGLE_COIL:
case WRITE_SINGLE_REGISTER:
if (p_data == NULL) {
return -1;
} else {
p_base_data_info->command_length = MODBUS_TCP_WRITE_SINGLE_CMD_LENGTH;
p_base_data_info->p_command = PrivMalloc(p_base_data_info->command_length);
p_base_data_info->p_data = p_data;
p_base_data_info->data_size = 2;
p_base_data_info->command_ready = 0;
}
break;
case WRITE_MULTIPLE_COIL:
if (p_data == NULL) {
return -1;
} else {
//"quantity" define how many coil need to be written,"n_byte" define the bytes of write-data(counted by bit)
uint16_t n_byte = (quantity - 1) / 8 + 1;
p_base_data_info->command_length = n_byte + MODBUS_TCP_WRITE_MULTI_HEAD + 6;
p_base_data_info->p_command = PrivMalloc(p_base_data_info->command_length);
//13th command define the bytes of write-data
p_base_data_info->p_command[12] = ((quantity - 1) / 8 + 1);
p_base_data_info->p_data = p_data;
p_base_data_info->data_size = n_byte;
p_base_data_info->command_ready = 0;
}
break;
case WRITE_MULTIPLE_REGISTER:
if (p_data == NULL) {
return -1;
} else {
//"quantity" define how many register need to be written
p_base_data_info->command_length = quantity * 2 + MODBUS_TCP_WRITE_MULTI_HEAD + 6;
p_base_data_info->p_command = PrivMalloc(p_base_data_info->command_length);
//13th command define the bytes of write-data
p_base_data_info->p_command[12] = 2 * quantity;
p_base_data_info->p_data = p_data;
p_base_data_info->data_size = quantity * 2;
p_base_data_info->command_ready = 0;
}
break;
default:
return -2;
break;
}
memset(p_base_data_info->p_command, 0, p_base_data_info->command_length);
p_base_data_info->p_command[0] = index >> 8;
p_base_data_info->p_command[1] = index;
p_base_data_info->p_command[2] = 0x00;
p_base_data_info->p_command[3] = 0x00;
p_base_data_info->p_command[4] = 0x00;
if (function_code < WRITE_MULTIPLE_COIL) {
p_base_data_info->p_command[5] = 0x06;
} else {
p_base_data_info->p_command[5] = 0x09;
}
p_base_data_info->p_command[6] = MODBUS_TCP_UNIT_ID;
p_base_data_info->p_command[7] = function_code;
p_base_data_info->p_command[8] = start_address >> 8;
p_base_data_info->p_command[9] = start_address;
if ((function_code != WRITE_SINGLE_COIL) && (function_code != WRITE_SINGLE_REGISTER)) {
p_base_data_info->p_command[10] = quantity >> 8;
p_base_data_info->p_command[11] = quantity;
}
return 0;
}
/**
* @description: Modbus Tcp Format write data from "g_write_data"
* @param p_read_item - read item pointer
* @return success : 0 error : -1
*/
static int ModbusTcpForamatWriteData(ModbusTcpReadItem *p_read_item)
{
int i = 0;
uint16_t command_index = 0;
int write_data_length = 0;
uint8_t write_data_buffer[32] = {0};
BasicPlcDataInfo *p_base_data_info = &(p_read_item->data_info.base_data_info);
uint8_t *p_command = p_base_data_info->p_command;
uint8_t function_code = p_read_item->data_info.function_code;
if (function_code < WRITE_SINGLE_COIL) {
return 0;
}
write_data_length = CircularAreaAppRead(g_write_data, write_data_buffer, p_base_data_info->data_size);
if (p_base_data_info->data_size != write_data_length) {
//printf("%s get write data %d [should be %d]failed!\n", __func__, write_data_length, p_base_data_info->data_size);
return 0;
}
switch (function_code)
{
case WRITE_SINGLE_COIL:
case WRITE_SINGLE_REGISTER:
command_index = 10;
break;
case WRITE_MULTIPLE_COIL:
case WRITE_MULTIPLE_REGISTER:
command_index = 13;
break;
default:
return -2;
break;
}
for (i = 0; i < write_data_length; i ++) {
p_base_data_info->p_command[command_index + i] = write_data_buffer[i];
}
p_base_data_info->command_ready = 1;
return write_data_length;
}
/**
* @description: Modbus Tcp Receive Plc Data Task
* @param parameter - parameter pointer
* @return
*/
void *ReceivePlcDataTask(void *parameter)
{
int i = 0;
uint8_t try_count = 0;
uint16_t data_length = 0;
uint8_t *modbus_tcp_data;
uint16_t read_item_size = sizeof(ModbusTcpReadItem);
struct ControlProtocol *control_protocol = (struct ControlProtocol *)parameter;
struct CircularAreaApp *circular_area = (struct CircularAreaApp *)control_protocol->args;
ModbusTcpReadItem *modbus_tcp_read_item = (ModbusTcpReadItem *)control_protocol->recipe->read_item;
modbus_tcp_data = control_protocol->recipe->protocol_data.data;
data_length = control_protocol->recipe->protocol_data.data_length;
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 ++) {
#ifdef CONTROL_USING_SOCKET
/*only connect socket when close socket or init*/
while (ControlConnectSocket(&plc_socket) < 0) {
PrivTaskDelay(1000);
}
ModbusTcpForamatWriteData((ModbusTcpReadItem *)modbus_tcp_read_item + i);
ModbusTcpGetData(plc_socket.socket, (ModbusTcpReadItem *)modbus_tcp_read_item + i);
#endif
}
/*read all variable item data, put them into circular_area*/
if (i == control_protocol->recipe->read_item_count) {
printf("%s get %d item %d length modbus_tcp_data %p\n", __func__, i, data_length, modbus_tcp_data);
CircularAreaAppWrite(circular_area, modbus_tcp_data, data_length, 0);
}
/*read data every single 'read_period' ms*/
PrivTaskDelay(control_protocol->recipe->read_period);
}
}
/**
* @description: Modbus Tcp Protocol Open
* @param control_protocol - control protocol pointer
* @return success : 0 error
*/
int ModbusTcpOpen(struct ControlProtocol *control_protocol)
{
ControlProtocolOpenDef(control_protocol);
g_write_data = CircularAreaAppInit(CA_DATA_LENGTH);
if (NULL == g_write_data) {
printf("%s CircularAreaInit error\n", __func__);
return -1;
}
return 0;
}
/**
* @description: Modbus Tcp Protocol Close
* @param control_protocol - control protocol pointer
* @return success : 0 error
*/
int ModbusTcpClose(struct ControlProtocol *control_protocol)
{
CircularAreaAppRelease(g_write_data);
#ifdef CONTROL_USING_SOCKET
ControlDisconnectSocket(&plc_socket);
#endif
ControlProtocolCloseDef();
return 0;
}
/**
* @description: Modbus Tcp Protocol Read Data
* @param control_protocol - control protocol pointer
* @param buf - read data buffer
* @param len - read data length
* @return success : data length error : 0
*/
int ModbusTcpRead(struct ControlProtocol *control_protocol, void *buf, size_t len)
{
struct CircularAreaApp *circular_area = (struct CircularAreaApp *)control_protocol->args;
return CircularAreaAppRead(circular_area, buf, len);
}
/**
* @description: Modbus Tcp Protocol Write Data
* @param control_protocol - control protocol pointer
* @param buf - write data buffer
* @param len - write data length
* @return success : data length error : 0
*/
int ModbusTcpWrite(struct ControlProtocol *control_protocol, const void *buf, size_t len)
{
CircularAreaAppWrite(g_write_data, (uint8_t *)buf, len, 0);
return 0;
}
/**
* @description: Modbus Tcp Protocol Ioctl
* @param control_protocol - control protocol pointer
* @param cmd - ioctl cmd
* @param args - ioctl args
* @return success : data length error : 0
*/
int ModbusTcpIoctl(struct ControlProtocol *control_protocol, int cmd, void *args)
{
//to do
return 0;
}
static struct ControlDone modbustcp_protocol_done =
{
._open = ModbusTcpOpen,
._close = ModbusTcpClose,
._read = ModbusTcpRead,
._write = ModbusTcpWrite,
._ioctl = ModbusTcpIoctl,
};
/**
* @description: Modbus TCP Protocol Cmd Generate
* @param p_recipe - recipe pointer
* @param protocol_format_info - protocol format info pointer
* @return success : 0 error : -1
*/
int ModbusTcpProtocolFormatCmd(struct ControlRecipe *p_recipe, ProtocolFormatInfo *protocol_format_info)
{
int ret = 0;
static uint8_t last_item_size = 0;
uint8_t *p_read_item_data = protocol_format_info->p_read_item_data + last_item_size;
ModbusTcpReadItem *modbustcp_read_item = (ModbusTcpReadItem *)(p_recipe->read_item) + protocol_format_info->read_item_index;
modbustcp_read_item->value_type = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "value_type")->valueint;
strncpy(modbustcp_read_item->value_name, cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "value_name")->valuestring, 20);
modbustcp_read_item->data_info.function_code = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "function_code")->valueint;
modbustcp_read_item->start_address = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "start_address")->valueint;
modbustcp_read_item->quantity = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "quantity")->valueint;
ret = ModbusTcpInitialDataInfo(modbustcp_read_item,
protocol_format_info->read_item_index,
p_read_item_data);
ControlPrintfList("CMD", modbustcp_read_item->data_info.base_data_info.p_command, modbustcp_read_item->data_info.base_data_info.command_length);
protocol_format_info->last_item_size = GetValueTypeMemorySize(modbustcp_read_item->value_type);
last_item_size += protocol_format_info->last_item_size;
return ret;
}
/**
* @description: Modbus TCP Protocol Init
* @param p_recipe - recipe pointer
* @return success : 0 error : -1
*/
int ModbusTcpProtocolInit(struct ControlRecipe *p_recipe)
{
p_recipe->read_item = PrivMalloc(sizeof(ModbusTcpReadItem) * p_recipe->read_item_count);
if (NULL == p_recipe->read_item) {
PrivFree(p_recipe->read_item);
return -1;
}
memset(p_recipe->read_item, 0, sizeof(ModbusTcpReadItem));
p_recipe->ControlProtocolFormatCmd = ModbusTcpProtocolFormatCmd;
p_recipe->done = &modbustcp_protocol_done;
return 0;
}
@@ -1,26 +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 modbus_tcp.h
* @brief support modbus_tcp function
* @version 3.0
* @author AIIT XUOS Lab
* @date 2022.09.27
*/
#ifndef MODBUS_TCP_H
#define MODBUS_TCP_H
#endif
@@ -0,0 +1,142 @@
{
"device_id": 4,
"device_name": "GJ2",
"communication_type": 0,
"socket_config": {
"plc_ip": "192.168.250.9",
"local_ip": "192.168.250.233",
"gateway": "192.168.250.1",
"netmask": "255.255.254.0",
"port": 502
},
"protocol_type": 2,
"read_period": 100,
"read_item_list": [
{
"value_name": "M0",
"value_type": 1,
"function_code": 1,
"start_address": 8192,
"quantity": 1
},
{
"value_name": "M1",
"value_type": 1,
"function_code": 1,
"start_address":8193,
"quantity": 1
},
{
"value_name": "M102",
"value_type": 1,
"function_code": 1,
"start_address": 8294,
"quantity": 1
},
{
"value_name": "M200",
"value_type": 1,
"function_code": 1,
"start_address": 8392,
"quantity": 1
},
{
"value_name": "M201",
"value_type": 1,
"function_code": 1,
"start_address":8393,
"quantity": 1
},
{
"value_name": "M202",
"value_type": 1,
"function_code": 1,
"start_address": 8394,
"quantity": 1
},
{
"value_name": "M203",
"value_type": 1,
"function_code": 1,
"start_address": 8395,
"quantity": 1
},
{
"value_name": "M204",
"value_type": 1,
"function_code": 1,
"start_address": 8396,
"quantity": 1
},
{
"value_name": "M205",
"value_type": 1,
"function_code": 1,
"start_address": 8397,
"quantity": 1
},
{
"value_name": "M206",
"value_type": 1,
"function_code": 1,
"start_address": 8398,
"quantity": 1
},
{
"value_name": "D20",
"value_type": 3,
"function_code": 3,
"start_address": 20,
"quantity": 1
},
{
"value_name": "D21",
"value_type": 3,
"function_code": 3,
"start_address": 21,
"quantity": 1
},
{
"value_name": "D22",
"value_type": 3,
"function_code": 3,
"start_address": 22,
"quantity": 1
},
{
"value_name": "D23",
"value_type": 3,
"function_code": 3,
"start_address": 23,
"quantity": 1
},
{
"value_name": "D202",
"value_type": 9,
"function_code": 3,
"start_address": 202,
"quantity": 2
},
{
"value_name": "D204",
"value_type": 9,
"function_code": 3,
"start_address": 204,
"quantity": 2
},
{
"value_name": "D206",
"value_type": 9,
"function_code": 3,
"start_address": 206,
"quantity": 2
},
{
"value_name": "D208",
"value_type": 9,
"function_code": 3,
"start_address": 208,
"quantity": 2
}
]
}
@@ -1,2 +1,37 @@
if ADD_XIZI_FETURES
config CONTROL_FRAMEWORK_UART_485_DIR
int "control framework 485 direction pin number"
default "2"
config CONTROL_FRAMEWORK_PIN_DEV
string "control framework device pin dev path"
default "/dev/pin_dev"
config CONTROL_FRAMEWORK_DRIVER_EXTUART
bool "Using extra uart to control framework"
default n
config CONTROL_FRAMEWORK_UART_DEV
string "control framework device uart dev path"
default "/dev/uart3_dev3"
depends on !CONTROL_FRAMEWORK_DRIVER_EXTUART
if CONTROL_FRAMEWORK_DRIVER_EXTUART
config CONTROL_FRAMEWORK_UART_DEV
string "control framework device extra uart dev path"
default "/dev/extuart_dev0"
config CONTROL_FRAMEWORK_DEV_EXT_PORT
int "if control framework device using extuart, choose port"
default "0"
endif
endif
if ADD_NUTTX_FETURES
endif
if ADD_RTTHREAD_FETURES
endif
@@ -1,4 +1,4 @@
SRC_FILES :=
SRC_FILES := modbus_uart.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,424 @@
/*
* 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 modbus_uart.c
* @brief support modbus_uart function
* @version 3.0
* @author AIIT XUOS Lab
* @date 2022.12.29
*/
#include <modbus_uart.h>
/*using cirtular area to receive write-data*/
#define CA_DATA_LENGTH 512
struct CircularAreaApp *g_write_data;
static BasicSocketPlc plc_socket = {0};
static uint8_t recv_buff[1024] = {0};
/**
* @description: CRC16 check
* @param data data buffer
* @param length data length
* @return check code
*/
static uint16_t ModbusUartCrc16(uint8_t *data, uint32_t length)
{
int j;
uint16_t reg_crc = 0xFFFF;
while (length--) {
reg_crc ^= *data++;
for (j = 0;j < 8;j ++) {
if(reg_crc & 0x01)
reg_crc = reg_crc >> 1 ^ 0xA001;
else
reg_crc = reg_crc >> 1;
}
}
printf(" crc = [0x%x]\n", reg_crc);
return reg_crc;
}
/**
* @description: Modbus Uart Data Transform from Receive Buffer To Control-Data
* @param p_read_item - read item pointer
* @param recv_buff - receive buff
* @return success : 0 error : -1
*/
static int ModbusUartTransformRecvBuffToData(ModbusUartReadItem *p_read_item, uint8_t *recv_buff)
{
uint8_t head_length = 3;
uint8_t *data_buffer;
ModbusUartDataInfo *p_modbus_uart_data_info = &(p_read_item->data_info);
uint16_t quantity = p_read_item->quantity;
ModbusUartFunctionCode function_code = p_modbus_uart_data_info->function_code;
uint8_t *p_data = p_modbus_uart_data_info->base_data_info.p_data;
uint8_t bytes_count = recv_buff[2];
if ((WRITE_SINGLE_COIL == function_code) || (WRITE_SINGLE_REGISTER == function_code)) {
head_length = 4;
if (p_modbus_uart_data_info->base_data_info.command_ready) {
p_modbus_uart_data_info->base_data_info.command_ready = 0;
}
}
data_buffer = recv_buff + head_length;//remove head data
if (READ_COIL_STATUS == function_code || READ_INPUT_STATUS == function_code) {
printf("Receive data is ");
for (int i = 0;i < bytes_count;i ++) {
for (int j = 0;j < 8;j ++) {
if ((i * 8 + j) < p_read_item->quantity) {
*(uint8_t *)(p_data + i * 8 + j) = ((data_buffer[i] >> j) & 0x01) ? 1 : 0;
printf("0x%x", *(uint8_t *)(p_data + i * 8 + j));
}
}
}
} else if (READ_HOLDING_REGISTER == function_code || READ_INPUT_REGISTER == function_code) {
printf("Receive data is ");
for (uint16_t i = 0; i < quantity; i ++) {
((int16_t *)p_data)[i] = ((int16_t *)data_buffer)[quantity - i - 1];
printf("0x%x 0x%x ", p_data[2 * i], p_data[2 * i + 1]);
}
}
printf("\n");
return 0;
}
/**
* @description: Modbus Uart Get Data From Serial
* @param p_read_item - read item pointer
* @return success : 0 error : -1 -2
*/
static int ModbusUartGetDataBySerial(ModbusUartReadItem *p_read_item)
{
uint32_t cmd_length, read_length = 0;
memset(recv_buff, 0, sizeof(recv_buff));
ModbusUartDataInfo *p_modbus_uart_data_info = &(p_read_item->data_info);
BasicPlcDataInfo *p_base_data_info = &(p_modbus_uart_data_info->base_data_info);
ModbusUartFunctionCode function_code = p_modbus_uart_data_info->function_code;
ControlPrintfList("SEND", p_base_data_info->p_command, p_base_data_info->command_length);
SerialWrite(p_base_data_info->p_command, p_base_data_info->command_length);
if (READ_COIL_STATUS == function_code || READ_INPUT_STATUS == function_code) {
cmd_length = 6;
} else if (READ_HOLDING_REGISTER == function_code || READ_INPUT_REGISTER == function_code) {
cmd_length = 7;
} else if (WRITE_SINGLE_COIL == function_code || WRITE_SINGLE_REGISTER == function_code) {
cmd_length = 8;
} else {
//MULTIPLE_COIL and MULTIPLE_REGISTER to do
cmd_length = 0;
}
read_length = SerialRead(recv_buff, cmd_length);
if (read_length) {
ControlPrintfList("RECV", recv_buff, read_length);
return ModbusUartTransformRecvBuffToData(p_read_item, recv_buff);
}
}
/**
* @description: Modbus Uart Data Info Init
* @param p_read_item - read item pointer
* @param station - uart station number
* @param p_data - control-data pointer
* @return success : 0 error : -1 -2
*/
static int ModbusUartInitialDataInfo(ModbusUartReadItem *p_read_item, uint8_t station, uint8_t *p_data)
{
uint16_t command_crc = 0;
uint8_t function_code = p_read_item->data_info.function_code;
uint16_t start_address = p_read_item->start_address;
uint16_t quantity = p_read_item->quantity;
BasicPlcDataInfo *p_base_data_info = &(p_read_item->data_info.base_data_info);
switch (function_code)
{
case READ_COIL_STATUS:
case READ_INPUT_STATUS:
case READ_HOLDING_REGISTER:
case READ_INPUT_REGISTER:
p_base_data_info->command_length = MODBUS_UART_READ_CMD_LENGTH;
p_base_data_info->p_command = PrivMalloc(p_base_data_info->command_length);
p_base_data_info->p_data = p_data;
p_base_data_info->command_ready = 1;
break;
case WRITE_SINGLE_COIL:
case WRITE_SINGLE_REGISTER:
if (p_data == NULL) {
return -1;
} else {
p_base_data_info->command_length = MODBUS_UART_WRITE_CMD_LENGTH;
p_base_data_info->p_command = PrivMalloc(p_base_data_info->command_length);
p_base_data_info->p_data = p_data;
p_base_data_info->data_size = 2;
p_base_data_info->command_ready = 0;
}
break;
case WRITE_MULTIPLE_COIL:
case WRITE_MULTIPLE_REGISTER:
//to do
printf("%s unsupported function code %d\n", __func__, function_code);
return -1;
default:
return -2;
}
memset(p_base_data_info->p_command, 0, p_base_data_info->command_length);
p_base_data_info->p_command[0] = station;
p_base_data_info->p_command[1] = function_code;
p_base_data_info->p_command[2] = start_address >> 8;
p_base_data_info->p_command[3] = start_address;
if ((function_code != WRITE_SINGLE_COIL) && (function_code != WRITE_SINGLE_REGISTER)) {
p_base_data_info->p_command[4] = quantity >> 8;
p_base_data_info->p_command[5] = quantity;
command_crc = ModbusUartCrc16(p_base_data_info->p_command, 6);
p_base_data_info->p_command[6] = command_crc & 0xFF;
p_base_data_info->p_command[7] = (command_crc >> 8) & 0xFF;
}
return 0;
}
/**
* @description: Modbus Uart Format write data from "g_write_data"
* @param p_read_item - read item pointer
* @return success : 0 error : -1 -2
*/
static int ModbusUartForamatWriteData(ModbusUartReadItem *p_read_item)
{
int i = 0;
uint16_t command_index = 0;
int write_data_length = 0;
uint8_t write_data_buffer[32] = {0};
BasicPlcDataInfo *p_base_data_info = &(p_read_item->data_info.base_data_info);
uint8_t *p_command = p_base_data_info->p_command;
uint8_t function_code = p_read_item->data_info.function_code;
if (function_code < WRITE_SINGLE_COIL) {
return 0;
}
write_data_length = CircularAreaAppRead(g_write_data, write_data_buffer, p_base_data_info->data_size);
if (p_base_data_info->data_size != write_data_length) {
//printf("%s get write data %d [should be %d]failed!\n", __func__, write_data_length, p_base_data_info->data_size);
return 0;
}
switch (function_code)
{
case WRITE_SINGLE_COIL:
case WRITE_SINGLE_REGISTER:
command_index = 4;
break;
case WRITE_MULTIPLE_COIL:
case WRITE_MULTIPLE_REGISTER:
printf("%s unsupported function code %d\n", __func__, function_code);
return -1;
default:
return -2;
}
for (i = 0; i < write_data_length; i ++) {
p_base_data_info->p_command[command_index + i] = write_data_buffer[i];
}
p_base_data_info->command_ready = 1;
return write_data_length;
}
/**
* @description: Modbus Uart Receive Plc Data Task
* @param parameter - parameter pointer
* @return
*/
void *ReceivePlcDataTask(void *parameter)
{
int i = 0;
uint8_t try_count = 0;
uint16_t data_length = 0;
uint8_t *modbus_uart_data;
uint16_t read_item_size = sizeof(ModbusUartReadItem);
struct ControlProtocol *control_protocol = (struct ControlProtocol *)parameter;
struct CircularAreaApp *circular_area = (struct CircularAreaApp *)control_protocol->args;
ModbusUartReadItem *modbus_uart_read_item = (ModbusUartReadItem *)control_protocol->recipe->read_item;
modbus_uart_data = control_protocol->recipe->protocol_data.data;
data_length = control_protocol->recipe->protocol_data.data_length;
while (1) {
for (i = 0; i < control_protocol->recipe->read_item_count; i ++) {
ModbusUartForamatWriteData((ModbusUartReadItem *)modbus_uart_read_item + i);
ModbusUartGetDataBySerial((ModbusUartReadItem *)modbus_uart_read_item + i);
}
/*read all variable item data, put them into circular_area*/
if (i == control_protocol->recipe->read_item_count) {
printf("%s get %d item %d length modbus_uart_data %p\n", __func__, i, data_length, modbus_uart_data);
CircularAreaAppWrite(circular_area, modbus_uart_data, data_length, 0);
}
/*read data every single 'read_period' ms*/
PrivTaskDelay(control_protocol->recipe->read_period);
}
}
/**
* @description: Modbus Uart Protocol Open
* @param control_protocol - control protocol pointer
* @return success : 0 error
*/
int ModbusUartOpen(struct ControlProtocol *control_protocol)
{
ControlProtocolOpenDef(control_protocol);
g_write_data = CircularAreaAppInit(CA_DATA_LENGTH);
if (NULL == g_write_data) {
printf("%s CircularAreaInit error\n", __func__);
return -1;
}
return 0;
}
/**
* @description: Modbus Uart Protocol Close
* @param control_protocol - control protocol pointer
* @return success : 0 error
*/
int ModbusUartClose(struct ControlProtocol *control_protocol)
{
CircularAreaAppRelease(g_write_data);
ControlProtocolCloseDef();
return 0;
}
/**
* @description: Modbus Uart Protocol Read Data
* @param control_protocol - control protocol pointer
* @param buf - read data buffer
* @param len - read data length
* @return success : data length error : 0
*/
int ModbusUartRead(struct ControlProtocol *control_protocol, void *buf, size_t len)
{
struct CircularAreaApp *circular_area = (struct CircularAreaApp *)control_protocol->args;
return CircularAreaAppRead(circular_area, buf, len);
}
/**
* @description: Modbus Uart Protocol Write Data
* @param control_protocol - control protocol pointer
* @param buf - write data buffer
* @param len - write data length
* @return success : data length error : 0
*/
int ModbusUartWrite(struct ControlProtocol *control_protocol, const void *buf, size_t len)
{
CircularAreaAppWrite(g_write_data, (uint8_t *)buf, len, 0);
return 0;
}
/**
* @description: Modbus Uart Protocol Ioctl
* @param control_protocol - control protocol pointer
* @param cmd - ioctl cmd
* @param args - ioctl args
* @return success : data length error : 0
*/
int ModbusUartIoctl(struct ControlProtocol *control_protocol, int cmd, void *args)
{
//to do
return 0;
}
static struct ControlDone modbusuart_protocol_done =
{
._open = ModbusUartOpen,
._close = ModbusUartClose,
._read = ModbusUartRead,
._write = ModbusUartWrite,
._ioctl = ModbusUartIoctl,
};
/**
* @description: Modbus TCP Protocol Cmd Generate
* @param p_recipe - recipe pointer
* @param protocol_format_info - protocol format info pointer
* @return success : 0 error : -1
*/
int ModbusUartProtocolFormatCmd(struct ControlRecipe *p_recipe, ProtocolFormatInfo *protocol_format_info)
{
int ret = 0;
static uint8_t last_item_size = 0;
uint8_t *p_read_item_data = protocol_format_info->p_read_item_data + last_item_size;
ModbusUartReadItem *modbusuart_read_item = (ModbusUartReadItem *)(p_recipe->read_item) + protocol_format_info->read_item_index;
modbusuart_read_item->value_type = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "value_type")->valueint;
strncpy(modbusuart_read_item->value_name, cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "value_name")->valuestring, 20);
modbusuart_read_item->data_info.function_code = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "function_code")->valueint;
modbusuart_read_item->start_address = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "start_address")->valueint;
modbusuart_read_item->quantity = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "quantity")->valueint;
ret = ModbusUartInitialDataInfo(modbusuart_read_item,
p_recipe->serial_config.station,
p_read_item_data);
ControlPrintfList("CMD", modbusuart_read_item->data_info.base_data_info.p_command, modbusuart_read_item->data_info.base_data_info.command_length);
protocol_format_info->last_item_size = GetValueTypeMemorySize(modbusuart_read_item->value_type);
last_item_size += protocol_format_info->last_item_size;
return ret;
}
/**
* @description: Modbus TCP Protocol Init
* @param p_recipe - recipe pointer
* @return success : 0 error : -1
*/
int ModbusUartProtocolInit(struct ControlRecipe *p_recipe)
{
p_recipe->read_item = PrivMalloc(sizeof(ModbusUartReadItem) * p_recipe->read_item_count);
if (NULL == p_recipe->read_item) {
PrivFree(p_recipe->read_item);
return -1;
}
memset(p_recipe->read_item, 0, sizeof(ModbusUartReadItem));
p_recipe->ControlProtocolFormatCmd = ModbusUartProtocolFormatCmd;
p_recipe->done = &modbusuart_protocol_done;
return 0;
}
@@ -0,0 +1,30 @@
{
"device_id": 1,
"device_name": "GJ2",
"communication_type": 1,
"serial_config": {
"station": 1,
"baud_rate": 9600,
"data_bits": 8,
"stop_bits": 1,
"check_mode": 0
},
"protocol_type": 3,
"read_period": 100,
"read_item_list": [
{
"value_name": "M0",
"value_type": 1,
"function_code": 1,
"start_address": 8192,
"quantity": 1
},
{
"value_name": "D208",
"value_type": 9,
"function_code": 3,
"start_address": 208,
"quantity": 1
}
]
}
@@ -1,15 +1,28 @@
config CONTROL_PROTOCOL_FINS
bool "Using fins control protocol"
default n
select CONTROL_USING_SOCKET
if CONTROL_PROTOCOL_FINS
source "$APP_DIR/Framework/control/plc_protocol/fins/Kconfig"
endif
config CONTROL_PROTOCOL_MELSEC
bool "Using melsec control protocol"
default n
if CONTROL_PROTOCOL_MELSEC
source "$APP_DIR/Framework/control/plc_protocol/melsec/Kconfig"
endif
config CONTROL_PROTOCOL_OPCUA
bool "Using opcua control protocol"
default n
if CONTROL_PROTOCOL_OPCUA
source "$APP_DIR/Framework/control/plc_protocol/opcua/Kconfig"
endif
config CONTROL_PROTOCOL_S7
bool "Using s7 control protocol"
default n
if CONTROL_PROTOCOL_S7
source "$APP_DIR/Framework/control/plc_protocol/s7/Kconfig"
endif
@@ -1,2 +1 @@
@@ -154,6 +154,7 @@ static int FinsTransformRecvBuffToData(FinsReadItem *p_read_item, uint8_t *recv_
return 0;
}
#ifdef CONTROL_USING_SOCKET
/**
* @description: Fins Protocol Handshake
* @param socket - socket
@@ -242,6 +243,7 @@ static int FinsGetData(int32_t socket, FinsReadItem *p_read_item)
}
return -2;
}
#endif
/**
* @description: Fins Data Info Init
@@ -303,6 +305,7 @@ void *ReceivePlcDataTask(void *parameter)
while (1) {
for (i = 0; i < control_protocol->recipe->read_item_count; i ++) {
#ifdef CONTROL_USING_SOCKET
/*only connect socket when close socket or init*/
while (ControlConnectSocket(&plc_socket) < 0) {
PrivTaskDelay(1000);
@@ -320,6 +323,7 @@ void *ReceivePlcDataTask(void *parameter)
plc_socket.secondary_connect_flag = 1;
FinsGetData(plc_socket.socket, (FinsReadItem *)fins_read_item + i);
#endif
}
/*read all variable item data, put them into circular_area*/
@@ -328,7 +332,7 @@ void *ReceivePlcDataTask(void *parameter)
CircularAreaAppWrite(circular_area, fins_data, data_length, 0);
}
/*read data every single 200ms*/
/*read data every single 'read_period' ms*/
PrivTaskDelay(control_protocol->recipe->read_period);
}
}
@@ -352,7 +356,9 @@ int FinsOpen(struct ControlProtocol *control_protocol)
*/
int FinsClose(struct ControlProtocol *control_protocol)
{
#ifdef CONTROL_USING_SOCKET
ControlDisconnectSocket(&plc_socket);
#endif
ControlProtocolCloseDef();
@@ -390,6 +396,8 @@ static struct ControlDone fins_protocol_done =
int FinsProtocolFormatCmd(struct ControlRecipe *p_recipe, ProtocolFormatInfo *protocol_format_info)
{
int ret = 0;
static uint8_t last_item_size = 0;
uint8_t *p_read_item_data = protocol_format_info->p_read_item_data + last_item_size;
FinsReadItem *fins_read_item = (FinsReadItem *)(p_recipe->read_item) + protocol_format_info->read_item_index;
@@ -405,11 +413,13 @@ int FinsProtocolFormatCmd(struct ControlRecipe *p_recipe, ProtocolFormatInfo *pr
ret = FinsInitialDataInfo(fins_read_item,
p_recipe->socket_config.plc_ip[3],
p_recipe->socket_config.local_ip[3],
protocol_format_info->p_read_item_data + protocol_format_info->last_item_size);
p_read_item_data);
ControlPrintfList("CMD", fins_read_item->data_info.base_data_info.p_command, fins_read_item->data_info.base_data_info.command_length);
protocol_format_info->last_item_size = GetValueTypeMemorySize(fins_read_item->value_type);
last_item_size += protocol_format_info->last_item_size;
return ret;
}
@@ -426,6 +436,8 @@ int FinsProtocolInit(struct ControlRecipe *p_recipe)
return -1;
}
memset(p_recipe->read_item, 0, sizeof(FinsReadItem));
p_recipe->ControlProtocolFormatCmd = FinsProtocolFormatCmd;
p_recipe->done = &fins_protocol_done;
@@ -15,5 +15,98 @@
* @brief plc protocol melsec
* @version 3.0
* @author AIIT XUOS Lab
* @date 2022-10-08
*/
* @date 2022-11-29
*/
#ifndef MELSEC_H
#define MELSEC_H
#include <control_def.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SUB_HEADER 0x5000
#define NETWORK_NUMBER 0x00
#define PC_NUMBER 0xFF
#define QEQUEST_DESTINSTION_MODULE_IO_NUMBER 0x03FF
#define QEQUEST_DESTINSTION_MODULE_STATION_NUMBER 0x00
#define STATION_NUMBER 0x00
#define FRAME_NUMBER 0x4639
#define SELF_STATION_NUMBER 0x00
#define MELSEC_NAK 0x15
#define MELSEC_STX 0x02
#define MELSEC_ETX 0x03
#define MELSEC_ENQ 0x05
#define MELSEC_1E_FRAME_RB 0x00
#define MELSEC_1E_FRAME_RW 0x01
#define MELSEC_1E_FRAME_WB 0x02
#define MELSEC_1E_FRAME_WW 0x03
#define MELSEC_1C_FRAME_RB 0x4252
#define MELSEC_1C_FRAME_RW 0x5752
#define MELSEC_1C_FRAME_WB 0x4257
#define MELSEC_1C_FRAME_WW 0x5757
//same as MELSEC_3E_Q_L_FRAME
#define MELSEC_3C_FRAME_RB 0x04010001
#define MELSEC_3C_FRAME_RW 0x04010000
#define MELSEC_3C_FRAME_WB 0x14010001
#define MELSEC_3C_FRAME_WW 0x14010000
//same as MELSEC_3C_FRAME
#define MELSEC_3E_Q_L_FRAME_RB 0x04010001
#define MELSEC_3E_Q_L_FRAME_RW 0x04010000
#define MELSEC_3E_Q_L_FRAME_WB 0x14010001
#define MELSEC_3E_Q_L_FRAME_WW 0x14010000
#define MELSEC_3E_IQ_R_FRAME_RB 0x04010003
#define MELSEC_3E_IQ_R_FRAME_RW 0x04010002
#define MELSEC_3E_IQ_R_FRAME_WB 0x14010003
#define MELSEC_3E_IQ_R_FRAME_WW 0x14010002
typedef enum {
READ_IN_BITS,
READ_IN_WORD,
WRITE_IN_BITS,
WRITE_IN_WORD,
TEST_IN_BIT,
TEST_IN_WORD
}MelsecCommandType;
typedef enum {
MELSEC_1E_FRAME,
MELSEC_3E_Q_L_FRAME,
MELSEC_3E_IQ_R_FRAME,
MELSEC_1C_FRAME,
MELSEC_3C_FRAME
}MelsecFrameType;
typedef struct
{
BasicPlcDataInfo base_data_info;
MelsecCommandType command_type;
MelsecFrameType frame_type;
}MelsecDataInfo;
typedef struct
{
MelsecDataInfo data_info;
UniformValueType value_type;
uint8_t value_name[20];
uint16_t monitoring_timer;
uint16_t device_code;
uint8_t head_device_number_string[6];
uint16_t device_points_count;
}MelsecReadItem;
#ifdef __cplusplus
}
#endif
#endif
@@ -1,2 +1,64 @@
choice
prompt "select melsec protocol"
default CONTROL_PROTOCOL_MELSEC_1E
config CONTROL_PROTOCOL_MELSEC_1E
bool "support melsec_1e protocol, using SOCKET"
select CONTROL_USING_SOCKET
config CONTROL_PROTOCOL_MELSEC_3E_Q_L
bool "support melsec_3e_q_l protocol, using SOCKET"
select CONTROL_USING_SOCKET
config CONTROL_PROTOCOL_MELSEC_3E_IQ_R
bool "support melsec_3e_iq_r protocol, using SOCKET"
select CONTROL_USING_SOCKET
config CONTROL_PROTOCOL_MELSEC_1C
bool "support melsec_1c protocol, using SERIAL"
select CONTROL_USING_SERIAL_485
config CONTROL_PROTOCOL_MELSEC_3C
bool "support melsec_3c protocol, using SERIAL"
select CONTROL_USING_SERIAL_485
endchoice
if CONTROL_USING_SERIAL_485
if ADD_XIZI_FETURES
config CONTROL_FRAMEWORK_UART_485_DIR
int "control framework 485 direction pin number"
default "2"
config CONTROL_FRAMEWORK_PIN_DEV
string "control framework device pin dev path"
default "/dev/pin_dev"
config CONTROL_FRAMEWORK_DRIVER_EXTUART
bool "Using extra uart to control framework"
default n
config CONTROL_FRAMEWORK_UART_DEV
string "control framework device uart dev path"
default "/dev/uart3_dev3"
depends on !CONTROL_FRAMEWORK_DRIVER_EXTUART
if CONTROL_FRAMEWORK_DRIVER_EXTUART
config CONTROL_FRAMEWORK_UART_DEV
string "control framework device extra uart dev path"
default "/dev/extuart_dev0"
config CONTROL_FRAMEWORK_DEV_EXT_PORT
int "if control framework device using extuart, choose port"
default "0"
endif
endif
if ADD_NUTTX_FETURES
endif
if ADD_RTTHREAD_FETURES
endif
endif
@@ -1,4 +1,4 @@
SRC_FILES :=
SRC_FILES := melsec.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,805 @@
/*
* 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 melsec.c
* @brief plc protocol melsec, support 1E、3E_Q_L、3E_IQ_R、1C、3C
* @version 3.0
* @author AIIT XUOS Lab
* @date 2022-11-29
*/
#include <melsec.h>
static BasicSocketPlc plc_socket = {0};
static uint8_t recv_buff[1024] = {0};
/**
* @description: Melsec Get Check Sum
* @param p_command - p_command pointer
* @param command_length - command length
* @return checksum
*/
static uint8_t GetCheckSum(uint8_t *p_command, uint16_t command_length)
{
uint8_t checksum = 0;
for (uint16_t i = 0; i < command_length; i++) {
checksum += p_command[i];
}
return checksum;
}
/**
* @description: Melsec Transform from Hex to Ascii
* @param hex - hex
* @return ascii
*/
static uint8_t TransformHexToAscii(uint8_t hex)
{
hex %= 0x10;
return hex < 0xA ? hex + '0' : hex - 10 + 'A';
}
/**
* @description: Melsec Transform from Ascii to Hex
* @param ascii - ascii
* @return hex
*/
static uint8_t TransformAsciiToHex(uint8_t ascii)
{
if (ascii > 'F' || ascii < '0' || (ascii > '9' && ascii < 'A'))
return 0;
else
return ascii < 'A' ? ascii - '0' : ascii - 'A' + 10;
}
/**
* @description: Melsec Get Device Code
* @param frame_type - melsec frame type
* @param device_string - device string
* @return device code
*/
static int MelsecGetDeviceCode(MelsecFrameType frame_type, char device_string[2])
{
switch (frame_type) {
case MELSEC_1C_FRAME:
if (strcmp(device_string, "M") == 0)
return 0x4D;
if (strcmp(device_string, "D") == 0)
return 0x44;
if (strcmp(device_string, "B") == 0)
return 0x22;
if (strcmp(device_string, "W") == 0)
return 0x57;
if (strcmp(device_string, "X") == 0)
return 0x58;
if (strcmp(device_string, "Y") == 0)
return 0x59;
case MELSEC_1E_FRAME:
if (strcmp(device_string, "M") == 0)
return 0x4D20;
if (strcmp(device_string, "D") == 0)
return 0x4420;
if (strcmp(device_string, "B") == 0)
return 0x2220;
if (strcmp(device_string, "W") == 0)
return 0x5720;
if (strcmp(device_string, "X") == 0)
return 0x5820;
if (strcmp(device_string, "Y") == 0)
return 0x5920;
case MELSEC_3C_FRAME:
if (strcmp(device_string, "M") == 0)
return 0x4D2A;
if (strcmp(device_string, "D") == 0)
return 0x442A;
if (strcmp(device_string, "B") == 0)
return 0x222A;
if (strcmp(device_string, "W") == 0)
return 0x572A;
case MELSEC_3E_IQ_R_FRAME:
if (strcmp(device_string, "M") == 0)
return 0x0090;
if (strcmp(device_string, "D") == 0)
return 0x00A8;
if (strcmp(device_string, "B") == 0)
return 0x00A0;
if (strcmp(device_string, "W") == 0)
return 0x00B4;
if (strcmp(device_string, "X") == 0)
return 0x009C;
if (strcmp(device_string, "Y") == 0)
return 0x009D;
case MELSEC_3E_Q_L_FRAME:
if (strcmp(device_string, "M") == 0)
return 0x90;
if (strcmp(device_string, "D") == 0)
return 0xA8;
if (strcmp(device_string, "B") == 0)
return 0xA0;
if (strcmp(device_string, "W") == 0)
return 0xB4;
if (strcmp(device_string, "X") == 0)
return 0x9C;
if (strcmp(device_string, "Y") == 0)
return 0x9D;
}
}
/**
* @description: Melsec Get Command Base Length
* @param frame_type - melsec frame type
* @return command length
*/
static int MelsecGetCommandBaseLength(MelsecFrameType frame_type)
{
switch (frame_type) {
case MELSEC_1C_FRAME:
return 17;
case MELSEC_1E_FRAME:
return 12;
case MELSEC_3C_FRAME:
return 33;
case MELSEC_3E_IQ_R_FRAME:
case MELSEC_3E_Q_L_FRAME:
return 21;
default:
return -1;
}
}
/**
* @description: Melsec Get Command Code
* @param frame_type - melsec frame type
* @param command_type - melsec command type
* @return command code
*/
static uint32_t MelsecGetCommandCode(MelsecFrameType frame_type, MelsecCommandType command_type)
{
switch (frame_type) {
case MELSEC_1C_FRAME:
switch (command_type) {
case READ_IN_BITS:
return MELSEC_1C_FRAME_RB;
case READ_IN_WORD:
return MELSEC_1C_FRAME_RW;
case WRITE_IN_BITS:
return MELSEC_1C_FRAME_WB;
case WRITE_IN_WORD:
return MELSEC_1C_FRAME_WW;
}
case MELSEC_1E_FRAME:
return command_type;
case MELSEC_3C_FRAME:
case MELSEC_3E_Q_L_FRAME:
switch (command_type) {
case READ_IN_BITS:
return MELSEC_3E_Q_L_FRAME_RB;
case READ_IN_WORD:
return MELSEC_3E_Q_L_FRAME_RW;
case WRITE_IN_BITS:
return MELSEC_3E_Q_L_FRAME_WB;
case WRITE_IN_WORD:
return MELSEC_3E_Q_L_FRAME_WW;
}
case MELSEC_3E_IQ_R_FRAME:
switch (command_type) {
case READ_IN_BITS:
return MELSEC_3E_IQ_R_FRAME_RB;
case READ_IN_WORD:
return MELSEC_3E_IQ_R_FRAME_RW;
case WRITE_IN_BITS:
return MELSEC_3E_IQ_R_FRAME_WB;
case WRITE_IN_WORD:
return MELSEC_3E_IQ_R_FRAME_WW;
}
}
}
/**
* @description: Melsec_1E Cmd Genetare
* @param p_command - command pointer
* @param command_code - command code
* @param p_read_item - p_read_item pointer
* @return success : index error : 0
*/
static uint16_t Melsec1eGenerateCommand(uint8_t *p_command, uint32_t command_code, MelsecReadItem *p_read_item)
{
uint16_t index = 0;
p_command[index++] = command_code;
p_command[index++] = PC_NUMBER;
p_command[index++] = p_read_item->monitoring_timer / 250;
p_command[index++] = (p_read_item->monitoring_timer / 250) >> 8;
uint16_t head_device_number = 0;
for (uint8_t i = 0; i < 6; i++) {
if (0 != p_read_item->head_device_number_string[i])
head_device_number = TransformAsciiToHex(p_read_item->head_device_number_string[i]) + head_device_number * (((0x5820 == p_read_item->device_code) || (0x5920 == p_read_item->device_code)) ? 8 : 10);
else
break;
}
p_command[index++] = head_device_number;
p_command[index++] = head_device_number >> (8 * 1);
p_command[index++] = head_device_number >> (8 * 2);
p_command[index++] = head_device_number >> (8 * 3);
p_command[index++] = p_read_item->device_code;
p_command[index++] = p_read_item->device_code >> 8;
p_command[index++] = p_read_item->device_points_count;
p_command[index++] = 0x00;
return index;
}
/**
* @description: Melsec_3E_Q_L Cmd Genetare
* @param p_command - command pointer
* @param command_code - command code
* @param p_read_item - p_read_item pointer
* @return success : index error : 0
*/
static uint16_t Melsec3eqlGenerateCommand(uint8_t *p_command, uint32_t command_code, MelsecReadItem *p_read_item)
{
p_read_item->monitoring_timer /= 250;
uint16_t index = 0;
p_command[index++] = SUB_HEADER >> 8;
p_command[index++] = (uint8_t)SUB_HEADER;
p_command[index++] = NETWORK_NUMBER;
p_command[index++] = PC_NUMBER;
p_command[index++] = (uint8_t)QEQUEST_DESTINSTION_MODULE_IO_NUMBER;
p_command[index++] = (uint8_t)(QEQUEST_DESTINSTION_MODULE_IO_NUMBER >> 8);
p_command[index++] = QEQUEST_DESTINSTION_MODULE_STATION_NUMBER;
p_command[index++] = 0x0C;
p_command[index++] = 0x00;
p_command[index++] = p_read_item->monitoring_timer;
p_command[index++] = p_read_item->monitoring_timer >> 8;
p_command[index++] = command_code >> (8 * 2);
p_command[index++] = command_code >> (8 * 3);
p_command[index++] = command_code;
p_command[index++] = command_code >> (8 * 1);
uint16_t head_device_number = 0;
for (uint8_t i = 0; i < 6; i++) {
if (0 != p_read_item->head_device_number_string[i])
head_device_number = TransformAsciiToHex(p_read_item->head_device_number_string[i]) + head_device_number * (((0x9c == (uint8_t)p_read_item->device_code) || (0x9d == (uint8_t)p_read_item->device_code)) ? 16 : 10);
else
break;
}
p_command[index++] = head_device_number;
p_command[index++] = head_device_number >> (8 * 1);
p_command[index++] = head_device_number >> (8 * 2);
p_command[index++] = p_read_item->device_code;
p_command[index++] = p_read_item->device_points_count;
p_command[index++] = p_read_item->device_points_count >> 8;
return index;
}
/**
* @description: Melsec_3E_IQ_R Cmd Genetare
* @param p_command - command pointer
* @param command_code - command code
* @param p_read_item - p_read_item pointer
* @return success : index error : 0
*/
static uint16_t Melsec3eiqrGenerateCommand(uint8_t *p_command, uint32_t command_code, MelsecReadItem *p_read_item)
{
uint16_t index = Melsec3eqlGenerateCommand(p_command, command_code, p_read_item) - 6;
uint16_t head_device_number = 0;
for (uint8_t i = 0; i < 6; i++) {
if (0 != p_read_item->head_device_number_string[i])
head_device_number = TransformAsciiToHex(p_read_item->head_device_number_string[i]) + head_device_number * (((0x9c == (uint8_t)p_read_item->device_code) || (0x9d == (uint8_t)p_read_item->device_code)) ? 16 : 10);
else
break;
}
p_command[index++] = head_device_number;
p_command[index++] = head_device_number >> (8 * 1);
p_command[index++] = head_device_number >> (8 * 2);
p_command[index++] = head_device_number >> (8 * 3);
p_command[index++] = p_read_item->device_code;
p_command[index++] = p_read_item->device_code >> 8;
p_command[index++] = p_read_item->device_points_count;
p_command[index++] = p_read_item->device_points_count >> 8;
return index;
}
/**
* @description: Melsec_1C Cmd Genetare
* @param p_command - command pointer
* @param command_code - command code
* @param p_read_item - p_read_item pointer
* @return success : index error : 0
*/
static uint16_t Melsec1cGenerateCommand(uint8_t *p_command, uint32_t command_code, MelsecReadItem *p_read_item)
{
p_read_item->monitoring_timer /= 10;
uint16_t index = 0;
uint8_t checksum = 0;
p_command[index++] = MELSEC_ENQ;
p_command[index++] = TransformHexToAscii(STATION_NUMBER >> 4);
p_command[index++] = TransformHexToAscii(STATION_NUMBER);
p_command[index++] = TransformHexToAscii(PC_NUMBER >> 4);
p_command[index++] = TransformHexToAscii(PC_NUMBER);
p_command[index++] = command_code >> 8;
p_command[index++] = command_code;
p_command[index++] = TransformHexToAscii(p_read_item->monitoring_timer);
p_command[index++] = p_read_item->device_code;
uint8_t head_device_number_string_length = 0;
for (uint8_t i = 0; i < 6; i++) {
if (0 == p_read_item->head_device_number_string[i])
break;
else
head_device_number_string_length++;
}
p_command[index++] = (head_device_number_string_length - 4 < 0) ? 0x30 : p_read_item->head_device_number_string[head_device_number_string_length - 4];
p_command[index++] = (head_device_number_string_length - 3 < 0) ? 0x30 : p_read_item->head_device_number_string[head_device_number_string_length - 3];
p_command[index++] = (head_device_number_string_length - 2 < 0) ? 0x30 : p_read_item->head_device_number_string[head_device_number_string_length - 2];
p_command[index++] = (head_device_number_string_length - 1 < 0) ? 0x30 : p_read_item->head_device_number_string[head_device_number_string_length - 1];
p_command[index++] = TransformHexToAscii(p_read_item->device_points_count >> 4);
p_command[index++] = TransformHexToAscii(p_read_item->device_points_count);
checksum = GetCheckSum(p_command + 1, index - 1);
p_command[index++] = TransformHexToAscii(checksum >> 4);
p_command[index++] = TransformHexToAscii(checksum);
return index;
}
/**
* @description: Melsec_3C Cmd Genetare
* @param p_command - command pointer
* @param command_code - command code
* @param p_read_item - p_read_item pointer
* @return success : index error : 0
*/
static uint16_t Melsec3cGenerateCommand(uint8_t* p_command, uint32_t command_code, MelsecReadItem *p_read_item)
{
uint16_t index = 0;
uint8_t checksum = 0;
p_command[index++] = MELSEC_ENQ;
p_command[index++] = FRAME_NUMBER >> 8;
p_command[index++] = (uint8_t)FRAME_NUMBER;
p_command[index++] = TransformHexToAscii(STATION_NUMBER >> 4);
p_command[index++] = TransformHexToAscii(STATION_NUMBER);
p_command[index++] = TransformHexToAscii(NETWORK_NUMBER >> 4);
p_command[index++] = TransformHexToAscii(NETWORK_NUMBER);
p_command[index++] = TransformHexToAscii(PC_NUMBER >> 4);
p_command[index++] = TransformHexToAscii(PC_NUMBER);
p_command[index++] = TransformHexToAscii(SELF_STATION_NUMBER >> 4);
p_command[index++] = TransformHexToAscii(SELF_STATION_NUMBER);
p_command[index++] = TransformHexToAscii(command_code >> (7 * 4));
p_command[index++] = TransformHexToAscii(command_code >> (6 * 4));
p_command[index++] = TransformHexToAscii(command_code >> (5 * 4));
p_command[index++] = TransformHexToAscii(command_code >> (4 * 4));
p_command[index++] = TransformHexToAscii(command_code >> (3 * 4));
p_command[index++] = TransformHexToAscii(command_code >> (2 * 4));
p_command[index++] = TransformHexToAscii(command_code >> (1 * 4));
p_command[index++] = TransformHexToAscii(command_code);
p_command[index++] = p_read_item->device_code >> 8;
p_command[index++] = p_read_item->device_code;
uint8_t head_device_number_string_length = 0;
for (uint8_t i = 0; i < 6; i++) {
if (0 == p_read_item->head_device_number_string[i])
break;
else
head_device_number_string_length++;
}
p_command[index++] = (head_device_number_string_length - 6 < 0) ? 0x30 : p_read_item->head_device_number_string[head_device_number_string_length - 6];
p_command[index++] = (head_device_number_string_length - 5 < 0) ? 0x30 : p_read_item->head_device_number_string[head_device_number_string_length - 5];
p_command[index++] = (head_device_number_string_length - 4 < 0) ? 0x30 : p_read_item->head_device_number_string[head_device_number_string_length - 4];
p_command[index++] = (head_device_number_string_length - 3 < 0) ? 0x30 : p_read_item->head_device_number_string[head_device_number_string_length - 3];
p_command[index++] = (head_device_number_string_length - 2 < 0) ? 0x30 : p_read_item->head_device_number_string[head_device_number_string_length - 2];
p_command[index++] = (head_device_number_string_length - 1 < 0) ? 0x30 : p_read_item->head_device_number_string[head_device_number_string_length - 1];
p_command[index++] = TransformHexToAscii(p_read_item->device_points_count >> (3 * 8));
p_command[index++] = TransformHexToAscii(p_read_item->device_points_count >> (2 * 8));
p_command[index++] = TransformHexToAscii(p_read_item->device_points_count >> (1 * 8));
p_command[index++] = TransformHexToAscii(p_read_item->device_points_count);
checksum = GetCheckSum(p_command + 1, index - 1);
p_command[index++] = TransformHexToAscii(checksum >> 4);
p_command[index++] = TransformHexToAscii(checksum);
return index;
}
/**
* @description: Melsec Cmd Genetare
* @param p_command - command pointer
* @param command_code - command code
* @param p_read_item - p_read_item pointer
* @return success : index error : 0
*/
static uint16_t MelsecGenerateCommand(uint8_t *p_command, uint32_t command_code, MelsecReadItem *p_read_item)
{
uint16_t (*GenerateMelsecCommandFunction)(uint8_t *p_command, uint32_t command_code, MelsecReadItem *p_read_item);
switch (p_read_item->data_info.frame_type) {
case MELSEC_1E_FRAME:
GenerateMelsecCommandFunction = Melsec1eGenerateCommand;
break;
case MELSEC_3E_IQ_R_FRAME:
GenerateMelsecCommandFunction = Melsec3eiqrGenerateCommand;
break;
case MELSEC_3E_Q_L_FRAME:
GenerateMelsecCommandFunction = Melsec3eqlGenerateCommand;
break;
case MELSEC_1C_FRAME:
GenerateMelsecCommandFunction = Melsec1cGenerateCommand;
break;
case MELSEC_3C_FRAME:
GenerateMelsecCommandFunction = Melsec3cGenerateCommand;
break;
default:
return 0;
}
return GenerateMelsecCommandFunction(p_command, command_code, p_read_item);
}
/**
* @description: Melsec Data Info Init
* @param p_read_item - read item pointer
* @param p_data - control-data pointer
* @return success : 0 error : -1
*/
int MelsecInitialDataInfo(MelsecReadItem *p_read_item, uint8_t *p_data)
{
uint8_t check_sum = 0;
BasicPlcDataInfo *p_base_data_info = &(p_read_item->data_info.base_data_info);
int command_base_length = MelsecGetCommandBaseLength(p_read_item->data_info.frame_type);
if (command_base_length < 0) {
printf("%s Not supported device code!\n", __func__);
return -1;
}
switch (p_read_item->data_info.command_type) {
case READ_IN_BITS:
p_base_data_info->command_length = command_base_length;
p_base_data_info->p_command = PrivMalloc(command_base_length);
p_base_data_info->data_size = p_read_item->device_points_count;
p_base_data_info->p_data = p_data;
break;
case READ_IN_WORD:
p_base_data_info->command_length = command_base_length;
p_base_data_info->p_command = PrivMalloc(command_base_length);
p_base_data_info->data_size = p_read_item->device_points_count * 2;
p_base_data_info->p_data = p_data;
break;
case WRITE_IN_BITS:
p_base_data_info->command_length = command_base_length + p_read_item->device_points_count;
p_base_data_info->p_command = PrivMalloc(command_base_length + p_read_item->device_points_count);
command_base_length -= (p_read_item->data_info.frame_type >= MELSEC_1C_FRAME) ? 2 : 0;
memcpy(p_base_data_info->p_command + command_base_length, p_data, p_read_item->device_points_count);
break;
case WRITE_IN_WORD:
p_base_data_info->command_length = command_base_length + p_read_item->device_points_count * 2;
p_base_data_info->p_command = PrivMalloc(command_base_length + p_read_item->device_points_count * 2);
command_base_length -= (p_read_item->data_info.frame_type >= MELSEC_1C_FRAME) ? 2 : 0;
memcpy(p_base_data_info->p_command + command_base_length, p_data, p_read_item->device_points_count * 2);
break;
default:
return -1;
}
uint32_t command_code = MelsecGetCommandCode(p_read_item->data_info.frame_type, p_read_item->data_info.command_type);
MelsecGenerateCommand(p_base_data_info->p_command, command_code, p_read_item);
return 0;
}
/**
* @description: Melsec Data Transform from Receive Buffer To Control-Data
* @param p_read_item - read item pointer
* @param recv_buff - receive buff
* @return success : 0 error : -1
*/
static int MelsecTransformRecvBuffToData(MelsecReadItem *p_read_item, uint8_t *recv_buff)
{
MelsecDataInfo *p_melsec_data_info = &(p_read_item->data_info);
MelsecFrameType frame_type = p_melsec_data_info->frame_type;
MelsecCommandType command_type = p_melsec_data_info->command_type;
uint8_t *p_data = p_melsec_data_info->base_data_info.p_data;
uint16_t device_points_count = p_read_item->device_points_count;
uint8_t is_ascii = ((MELSEC_1E_FRAME == frame_type) || (MELSEC_3E_Q_L_FRAME == frame_type) || (MELSEC_3E_IQ_R_FRAME == frame_type)) ? 0 : 1;
uint16_t abnormal_code = 0;
switch (frame_type) {
case MELSEC_3E_IQ_R_FRAME:
case MELSEC_3E_Q_L_FRAME:
if (recv_buff[9] != 0 || recv_buff[10] != 0)
abnormal_code = recv_buff[10] * 256 + recv_buff[9];
else
recv_buff += 11;
break;
case MELSEC_1E_FRAME:
if (recv_buff[1] != 0)
abnormal_code = recv_buff[2];
else
recv_buff += 2;
break;
case MELSEC_1C_FRAME:
if (MELSEC_NAK == recv_buff[0])
abnormal_code = recv_buff[5] * 256 + recv_buff[6];
else
recv_buff += 5;
break;
case MELSEC_3C_FRAME:
if (MELSEC_NAK == recv_buff[0])
abnormal_code = ((uint16_t)TransformAsciiToHex(recv_buff[11])) << 12 + ((uint16_t)TransformAsciiToHex(recv_buff[12])) << 8 +
((uint16_t)TransformAsciiToHex(recv_buff[13])) << 4 + ((uint16_t)TransformAsciiToHex(recv_buff[14]));
else
recv_buff += 11;
break;
default:
return -1;
}
if (abnormal_code != 0) {
printf("Data abnormal, abnormal code is %0x!", abnormal_code);
return -1;
}
ControlPrintfList("DATA", recv_buff, (uint16_t)(device_points_count * (READ_IN_BITS == command_type ? 0.5 : 2) * (frame_type >= MELSEC_1C_FRAME ? 2 : 1) + 0.6));
printf("Receive data is ");
for (uint16_t i = 0; i < device_points_count; i++) {
if (READ_IN_BITS == command_type) {
if (!is_ascii) {
p_data[i] = (recv_buff[i / 2] & (i % 2 == 0 ? 0x10 : 0x01)) || 0;
} else {
p_data[i] = TransformAsciiToHex(recv_buff[i]);
}
printf("0x%x", p_data[i]);
} else if (READ_IN_WORD == command_type) {
if (!is_ascii) {
uint16_t recv_buff_index = 2 * (device_points_count - 1 - i);
p_data[2 * i] = recv_buff[recv_buff_index + 1];
p_data[2 * i + 1] = recv_buff[recv_buff_index];
} else {
uint16_t recv_buff_index = 4 * (device_points_count - 1 - i);
p_data[2 * i] = TransformAsciiToHex(recv_buff[recv_buff_index]) * 16 + TransformAsciiToHex(recv_buff[recv_buff_index + 1]);
p_data[2 * i + 1] = TransformAsciiToHex(recv_buff[recv_buff_index + 2]) * 16 + TransformAsciiToHex(recv_buff[recv_buff_index + 3]);
}
printf("0x%x 0x%x", p_data[2 * i], p_data[2 * i + 1]);
}
}
printf("\n");
return 0;
}
#ifdef CONTROL_USING_SOCKET
/**
* @description: Melsec Get Data From Socket
* @param socket - socket
* @param p_read_item - read item pointer
* @return success : 0 error : -1 -2
*/
static int MelsecGetDataBySocket(int32_t socket, MelsecReadItem *p_read_item)
{
uint8_t try_count = 0;
int32_t write_error = 0;
MelsecDataInfo *p_melsec_data_info = &(p_read_item->data_info);
BasicPlcDataInfo *p_base_data_info = &(p_melsec_data_info->base_data_info);
memset(recv_buff, 0, sizeof(recv_buff));
while (try_count < 10) {
ControlPrintfList("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 {
ControlPrintfList("RECV", recv_buff, recv_length);
return MelsecTransformRecvBuffToData(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;
}
#endif
/**
* @description: Melsec Get Data From Serial
* @param p_read_item - read item pointer
* @return success : 0 error : -1 -2
*/
static int MelsecGetDataBySerial(MelsecReadItem *p_read_item)
{
uint32_t read_length = 0;
memset(recv_buff, 0, sizeof(recv_buff));
MelsecDataInfo *p_melsec_data_info = &(p_read_item->data_info);
BasicPlcDataInfo *p_base_data_info = &(p_melsec_data_info->base_data_info);
ControlPrintfList("SEND", p_base_data_info->p_command, p_base_data_info->command_length);
SerialWrite(p_base_data_info->p_command, p_base_data_info->command_length);
read_length = SerialRead(recv_buff, sizeof(recv_buff));
if (read_length) {
ControlPrintfList("RECV", recv_buff, read_length);
return MelsecTransformRecvBuffToData(p_read_item, recv_buff);
}
}
/**
* @description: Melsec Receive Plc Data Task
* @param parameter - parameter pointer
* @return
*/
void *ReceivePlcDataTask(void *parameter)
{
int i = 0;
uint8_t try_count = 0;
uint16_t data_length = 0;
uint8_t *melsec_data;
uint16_t read_item_size = sizeof(MelsecReadItem);
struct ControlProtocol *control_protocol = (struct ControlProtocol *)parameter;
struct CircularAreaApp *circular_area = (struct CircularAreaApp *)control_protocol->args;
MelsecReadItem *melsec_read_item = (MelsecReadItem *)control_protocol->recipe->read_item;
melsec_data = control_protocol->recipe->protocol_data.data;
data_length = control_protocol->recipe->protocol_data.data_length;
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;
while (1) {
for (i = 0; i < control_protocol->recipe->read_item_count; i ++) {
if ((PROTOCOL_MELSEC_1C == control_protocol->protocol_type) || (PROTOCOL_MELSEC_3C == control_protocol->protocol_type)) {
MelsecGetDataBySerial((MelsecReadItem *)melsec_read_item + i);
} else {
#ifdef CONTROL_USING_SOCKET
/*only connect socket when close socket or init*/
while (ControlConnectSocket(&plc_socket) < 0) {
PrivTaskDelay(1000);
}
MelsecGetDataBySocket(plc_socket.socket, (MelsecReadItem *)melsec_read_item + i);
#endif
}
}
/*read all variable item data, put them into circular_area*/
if (i == control_protocol->recipe->read_item_count) {
printf("%s get %d item %d length\n", __func__, i, data_length);
CircularAreaAppWrite(circular_area, melsec_data, data_length, 0);
}
/*read data every single 'read_period' ms*/
PrivTaskDelay(control_protocol->recipe->read_period);
}
}
/**
* @description: Melsec Protocol Open
* @param control_protocol - control protocol pointer
* @return success : 0 error
*/
int MelsecOpen(struct ControlProtocol *control_protocol)
{
ControlProtocolOpenDef(control_protocol);
return 0;
}
/**
* @description: Melsec Protocol Close
* @param control_protocol - control protocol pointer
* @return success : 0 error
*/
int MelsecClose(struct ControlProtocol *control_protocol)
{
if ((PROTOCOL_MELSEC_1C != control_protocol->protocol_type) && (PROTOCOL_MELSEC_3C != control_protocol->protocol_type)) {
#ifdef CONTROL_USING_SOCKET
ControlDisconnectSocket(&plc_socket);
#endif
}
ControlProtocolCloseDef();
return 0;
}
/**
* @description: Melsec Protocol Read Data
* @param control_protocol - control protocol pointer
* @param buf - read data buffer
* @param len - read data length
* @return success : data length error : 0
*/
int MelsecRead(struct ControlProtocol *control_protocol, void *buf, size_t len)
{
struct CircularAreaApp *circular_area = (struct CircularAreaApp *)control_protocol->args;
return CircularAreaAppRead(circular_area, buf, len);
}
static struct ControlDone melsec_protocol_done =
{
._open = MelsecOpen,
._close = MelsecClose,
._read = MelsecRead,
._write = NULL,
._ioctl = NULL,
};
/**
* @description: Melsec Protocol Cmd Generate
* @param p_recipe - recipe pointer
* @param protocol_format_info - protocol format info pointer
* @return success : 0 error : -1
*/
int MelsecProtocolFormatCmd(struct ControlRecipe *p_recipe, ProtocolFormatInfo *protocol_format_info)
{
int ret = 0;
static uint8_t last_item_size = 0;
uint8_t *p_read_item_data = protocol_format_info->p_read_item_data + last_item_size;
MelsecReadItem *melsec_read_item = (MelsecReadItem *)(p_recipe->read_item) + protocol_format_info->read_item_index;
melsec_read_item->value_type = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "value_type")->valueint;
strncpy(melsec_read_item->value_name, cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "value_name")->valuestring, 20);
melsec_read_item->data_info.command_type = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "command_type")->valueint;
melsec_read_item->data_info.frame_type = p_recipe->protocol_type - PROTOCOL_MELSEC_1E;
melsec_read_item->monitoring_timer = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "monitoring_timer")->valueint;
melsec_read_item->device_code = MelsecGetDeviceCode(melsec_read_item->data_info.frame_type, cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "device_code")->valuestring);
strncpy(melsec_read_item->head_device_number_string, cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "head_device_number_string")->valuestring, 6);
melsec_read_item->device_points_count = cJSON_GetObjectItem(protocol_format_info->read_single_item_json, "device_points_count")->valueint;
ret = MelsecInitialDataInfo(melsec_read_item, p_read_item_data);
ControlPrintfList("CMD", melsec_read_item->data_info.base_data_info.p_command, melsec_read_item->data_info.base_data_info.command_length);
protocol_format_info->last_item_size = GetValueTypeMemorySize(melsec_read_item->value_type);
last_item_size += protocol_format_info->last_item_size;
return ret;
}
/**
* @description: Melsec Protocol Init
* @param p_recipe - recipe pointer
* @return success : 0 error : -1
*/
int MelsecProtocolInit(struct ControlRecipe *p_recipe)
{
p_recipe->read_item = PrivMalloc(sizeof(MelsecReadItem) * p_recipe->read_item_count);
if (NULL == p_recipe->read_item) {
PrivFree(p_recipe->read_item);
return -1;
}
memset(p_recipe->read_item, 0, sizeof(MelsecReadItem));
p_recipe->ControlProtocolFormatCmd = MelsecProtocolFormatCmd;
p_recipe->done = &melsec_protocol_done;
return 0;
}
@@ -0,0 +1,34 @@
{
"device_id": 769,
"device_name": "S01",
"communication_type": 1,
"serial_config": {
"station": 1,
"baud_rate": 19200,
"data_bits": 7,
"stop_bits": 1,
"check_mode": 3
},
"protocol_type": 9,
"read_period": 100,
"read_item_list": [
{
"value_name": "启动",
"value_type": 1,
"device_code": "M",
"head_device_number_string": "0",
"device_points_count": 1,
"command_type": 0,
"monitoring_timer": 100
},
{
"value_name": "停止",
"value_type": 1,
"device_code": "M",
"head_device_number_string": "1",
"device_points_count": 1,
"command_type": 0,
"monitoring_timer": 100
}
]
}
@@ -0,0 +1,34 @@
{
"device_id": 771,
"device_name": "S03",
"communication_type": 0,
"socket_config": {
"plc_ip": "192.168.250.20",
"local_ip": "192.168.250.233",
"gateway": "192.168.250.1",
"netmask": "255.255.254.0",
"port": 2000
},
"protocol_type": 6,
"read_period": 100,
"read_item_list": [
{
"value_name": "启动",
"value_type": 1,
"device_code": "M",
"head_device_number_string": "0",
"device_points_count": 1,
"command_type": 0,
"monitoring_timer": 100
},
{
"value_name": "停止",
"value_type": 1,
"device_code": "M",
"head_device_number_string": "1",
"device_points_count": 1,
"command_type": 0,
"monitoring_timer": 100
}
]
}
@@ -0,0 +1,34 @@
{
"device_id": 770,
"device_name": "S02",
"communication_type": 1,
"serial_config": {
"station": 1,
"baud_rate": 19200,
"data_bits": 7,
"stop_bits": 1,
"check_mode": 3
},
"protocol_type": 10,
"read_period": 100,
"read_item_list": [
{
"value_name": "启动",
"value_type": 1,
"device_code": "M",
"head_device_number_string": "0",
"device_points_count": 1,
"command_type": 0,
"monitoring_timer": 100
},
{
"value_name": "停止",
"value_type": 1,
"device_code": "M",
"head_device_number_string": "1",
"device_points_count": 1,
"command_type": 0,
"monitoring_timer": 100
}
]
}
@@ -0,0 +1,34 @@
{
"device_id": 773,
"device_name": "S05",
"communication_type": 0,
"socket_config": {
"plc_ip": "192.168.250.20",
"local_ip": "192.168.250.233",
"gateway": "192.168.250.1",
"netmask": "255.255.254.0",
"port": 2000
},
"protocol_type": 8,
"read_period": 100,
"read_item_list": [
{
"value_name": "启动",
"value_type": 1,
"device_code": "M",
"head_device_number_string": "0",
"device_points_count": 1,
"command_type": 0,
"monitoring_timer": 100
},
{
"value_name": "停止",
"value_type": 1,
"device_code": "M",
"head_device_number_string": "1",
"device_points_count": 1,
"command_type": 0,
"monitoring_timer": 100
}
]
}
@@ -0,0 +1,34 @@
{
"device_id": 772,
"device_name": "S04",
"communication_type": 0,
"socket_config": {
"plc_ip": "192.168.250.20",
"local_ip": "192.168.250.233",
"gateway": "192.168.250.1",
"netmask": "255.255.254.0",
"port": 2000
},
"protocol_type": 7,
"read_period": 100,
"read_item_list": [
{
"value_name": "启动",
"value_type": 1,
"device_code": "M",
"head_device_number_string": "0",
"device_points_count": 1,
"command_type": 0,
"monitoring_timer": 100
},
{
"value_name": "停止",
"value_type": 1,
"device_code": "M",
"head_device_number_string": "1",
"device_points_count": 1,
"command_type": 0,
"monitoring_timer": 100
}
]
}
@@ -33,6 +33,18 @@ extern void *ReceivePlcDataTask(void *parameter);
extern int FinsProtocolInit(struct ControlRecipe *p_recipe);
#endif
#ifdef CONTROL_PROTOCOL_MELSEC
extern int MelsecProtocolInit(struct ControlRecipe *p_recipe);
#endif
#ifdef CONTROL_PROTOCOL_MODBUS_TCP
extern int ModbusTcpProtocolInit(struct ControlRecipe *p_recipe);
#endif
#ifdef CONTROL_PROTOCOL_MODBUS_UART
extern int ModbusUartProtocolInit(struct ControlRecipe *p_recipe);
#endif
/*
CONTROL FRAMEWORK READ DATA FORMAT:
| HEAD |device_id|read data length|read item count| data |
@@ -55,6 +67,19 @@ static struct ControlProtocolInitParam protocol_init[] =
#ifdef CONTROL_PROTOCOL_FINS
{ PROTOCOL_FINS, FinsProtocolInit },
#endif
#ifdef CONTROL_PROTOCOL_MELSEC
{ PROTOCOL_MELSEC_1E, MelsecProtocolInit },
{ PROTOCOL_MELSEC_3E_Q_L, MelsecProtocolInit },
{ PROTOCOL_MELSEC_3E_IQ_R, MelsecProtocolInit },
{ PROTOCOL_MELSEC_1C, MelsecProtocolInit },
{ PROTOCOL_MELSEC_3C, MelsecProtocolInit },
#endif
#ifdef CONTROL_PROTOCOL_MODBUS_TCP
{ PROTOCOL_MODBUS_TCP, ModbusTcpProtocolInit },
#endif
#ifdef CONTROL_PROTOCOL_MODBUS_UART
{ PROTOCOL_MODBUS_UART, ModbusUartProtocolInit },
#endif
{ PROTOCOL_END, NULL },
};
@@ -125,12 +150,13 @@ static uint16_t GetRecipeTotalDataLength(cJSON* read_item_list_json)
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.station = cJSON_GetObjectItem(p_serial_config_json, "station")->valueint;
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);
printf("Serial_config:station: %d baud_rate: %d, data_bits: %d, stop_bits: %d, check_mode is %d\n",
p_recipe->serial_config.station, p_recipe->serial_config.baud_rate, p_recipe->serial_config.data_bits, p_recipe->serial_config.stop_bits, p_recipe->serial_config.check_mode);
}
/**
@@ -184,13 +210,14 @@ static void ControlBasicSocketConfig(struct ControlRecipe *p_recipe, cJSON *p_re
*/
void ControlPrintfList(char name[5], uint8_t *number_list, uint16_t length)
{
printf("\n******************%5s****************\n", name);
printf("\n******************%s****************\n", name);
for (int32_t i = 0;i < length;i ++) {
printf("0x%x ", number_list[i]);
}
printf("\n**************************************\n");
}
#ifdef CONTROL_USING_SOCKET
/**
* @description: Control Framework Connect Socket
* @param p_plc - basic socket plc pointer
@@ -267,6 +294,7 @@ int ControlDisconnectSocket(BasicSocketPlc *p_plc)
return error;
}
#endif
/**
* @description: Control Framework Protocol Open for Sub_Protocol, Init Circular Area and Receive Data Task
@@ -69,6 +69,7 @@ typedef struct
{
uint16_t command_length;
uint16_t data_size;
uint8_t command_ready;
uint8_t *p_command;
uint8_t *p_data;
}BasicPlcDataInfo;
@@ -89,6 +90,7 @@ struct ProtocolData
struct SerialConfig
{
uint8_t station;
uint32_t baud_rate;
uint8_t data_bits;
uint8_t stop_bits;
@@ -20,6 +20,96 @@
#include <control_io.h>
#ifdef CONTROL_USING_SERIAL_485
static int pin_fd = 0;
static int uart_fd = 0;
/**
* @description: Set Uart 485 Input
* @return
*/
static void Set485Input(void)
{
struct PinStat pin_stat;
pin_stat.pin = CONTROL_FRAMEWORK_UART_485_DIR;
pin_stat.val = GPIO_LOW;
PrivWrite(pin_fd, &pin_stat, 1);
}
/**
* @description: Set Uart 485 Output
* @return
*/
static void Set485Output(void)
{
struct PinStat pin_stat;
pin_stat.pin = CONTROL_FRAMEWORK_UART_485_DIR;
pin_stat.val = GPIO_HIGH;
PrivWrite(pin_fd, &pin_stat, 1);
}
/**
* @description: Control Framework Uart 485 Init
* @param baud_rate - baud rate
* @param data_bits - data bits
* @param stop_bits - stop bits
* @param check_mode - check mode, even、odd、none
* @return
*/
void Uart485Init(uint32_t baud_rate, uint8_t data_bits, uint8_t stop_bits, uint8_t check_mode)
{
int ret = 0;
pin_fd = PrivOpen(CONTROL_FRAMEWORK_PIN_DEV, O_RDWR);
if (pin_fd < 0) {
printf("open %s error\n", CONTROL_FRAMEWORK_PIN_DEV);
return;
}
struct PinParam pin_param;
pin_param.cmd = GPIO_CONFIG_MODE;
pin_param.mode = GPIO_CFG_OUTPUT;
pin_param.pin = CONTROL_FRAMEWORK_UART_485_DIR;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = PIN_TYPE;
ioctl_cfg.args = &pin_param;
PrivIoctl(pin_fd, OPE_CFG, &ioctl_cfg);
uart_fd = open(CONTROL_FRAMEWORK_UART_DEV, O_RDWR);
if (uart_fd < 0) {
printf("open fd error %d\n", uart_fd);
return;
}
printf("Uart485Init open fd %d baud_rate %d data_bits %d stop_bits %d check_mode %d\n",
uart_fd, baud_rate, data_bits, stop_bits, check_mode);
struct SerialDataCfg cfg;
cfg.serial_baud_rate = baud_rate;
cfg.serial_data_bits = data_bits;
cfg.serial_stop_bits = stop_bits;
cfg.serial_buffer_size = 128;
cfg.serial_parity_mode = check_mode;
cfg.serial_bit_order = 0;
cfg.serial_invert_mode = 0;
#ifdef CONTROL_FRAMEWORK_DRIVER_EXTUART
cfg.ext_uart_no = 0;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.serial_timeout = 10000;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
ioctl_cfg.args = &cfg;
ret = PrivIoctl(uart_fd, OPE_INT, &ioctl_cfg);
if (0 != ret) {
printf("ioctl fd error %d\n", ret);
return;
}
printf("%s done!\n", __func__);
}
#endif
/**
* @description: Control Framework Socket Init
* @param ip - local ip pointer
@@ -33,9 +123,14 @@ void SocketInit(char *ip, char *mask, char *gw)
ip[0], ip[1], ip[2], ip[3],
mask[0], mask[1], mask[2], mask[3],
gw[0], gw[1], gw[2], gw[3]);
#ifdef CONTROL_USING_SOCKET
#ifdef BSP_USING_LWIP
lwip_config_tcp(0, ip, mask, gw);
#endif
#ifdef BSP_USING_W5500
//to do
#endif
#endif
}
/**
@@ -48,5 +143,50 @@ void SocketInit(char *ip, char *mask, char *gw)
*/
void SerialInit(uint32_t baud_rate, uint8_t data_bits, uint8_t stop_bits, uint8_t check_mode)
{
// Uart485Init(baud_rate, data_bits, stop_bits, check_mode);
#ifdef CONTROL_USING_SERIAL_485
Uart485Init(baud_rate, data_bits, stop_bits, check_mode);
#endif
}
/**
* @description: Control Framework Serial Write
* @param write_data - write data
* @param length - length
* @return
*/
void SerialWrite(uint8_t *write_data, int length)
{
#ifdef CONTROL_USING_SERIAL_485
Set485Output();
PrivTaskDelay(20);
PrivWrite(uart_fd, write_data, length);
PrivTaskDelay(15);
Set485Input();
#endif
}
/**
* @description: Control Framework Serial Read
* @param read_data - read data
* @param length - length
* @return read data size
*/
int SerialRead(uint8_t *read_data, int length)
{
#ifdef CONTROL_USING_SERIAL_485
int data_size = 0;
int data_recv_size = 0;
while (data_size < length) {
data_recv_size = PrivRead(uart_fd, read_data + data_recv_size, length);
data_size += data_recv_size;
}
//need to wait 30ms , make sure write cmd again and receive data successfully
PrivTaskDelay(30);
return data_size;
#endif
}
@@ -24,26 +24,42 @@
#include <transform.h>
#include <list.h>
#ifdef CONTROL_USING_SOCKET
#ifdef BSP_USING_LWIP
#include "lwip/sys.h"
#include "lwip/sockets.h"
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONTROL_USING_SOCKET
#ifdef BSP_USING_LWIP
#define socket_write lwip_write
#define socket_read lwip_read
#endif
#ifdef BSP_USING_W5500
//to do
#define socket_write
#define socket_read
#endif
#endif
/*Control Framework Socket Init*/
void SocketInit(char *ip, char *mask, char *gw);
/*Control Framework Serial Init*/
void SerialInit(uint32_t baud_rate, uint8_t data_bits, uint8_t stop_bits, uint8_t check_mode);
/*Control Framework Serial Write*/
void SerialWrite(uint8_t *write_data, int length);
/*Control Framework Serial Read*/
int SerialRead(uint8_t *read_data, int length);
#ifdef __cplusplus
}
#endif
@@ -104,7 +104,7 @@ int PrivTaskDelay(int32_t ms)
#ifndef SEPARATE_COMPILE
uint32_t PrivGetTickTime()
{
return CalculteTimeMsFromTick(CurrentTicksGain());
return CalculateTimeMsFromTick(CurrentTicksGain());
}
#endif
/*********************fs**************************/