forked from xuos/xiuos
feat add melsec protocol for control framework
This commit is contained in:
parent
e5bf0cee41
commit
0b49dd1a3c
|
@ -1,15 +1,27 @@
|
|||
config CONTROL_PROTOCOL_FINS
|
||||
bool "Using fins control protocol"
|
||||
default n
|
||||
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
|
||||
|
|
|
@ -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,20 @@
|
|||
choice
|
||||
prompt "select melsec protocol"
|
||||
default CONTROL_PROTOCOL_MELSEC_1E
|
||||
|
||||
config CONTROL_PROTOCOL_MELSEC_1E
|
||||
bool "support melsec_1e protocol, using TCP"
|
||||
|
||||
config CONTROL_PROTOCOL_MELSEC_3E_Q_L
|
||||
bool "support melsec_3e_q_l protocol, using TCP"
|
||||
|
||||
config CONTROL_PROTOCOL_MELSEC_3E_IQ_R
|
||||
bool "support melsec_3e_iq_r protocol, using TCP"
|
||||
|
||||
config CONTROL_PROTOCOL_MELSEC_1C
|
||||
bool "support melsec_1c protocol, using SERIAL"
|
||||
|
||||
config CONTROL_PROTOCOL_MELSEC_3C
|
||||
bool "support melsec_3c protocol, using SERIAL"
|
||||
endchoice
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
SRC_FILES :=
|
||||
SRC_FILES := melsec.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
|
|
|
@ -0,0 +1,669 @@
|
|||
/*
|
||||
* 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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 ++) {
|
||||
/*only connect socket when close socket or init*/
|
||||
while (ControlConnectSocket(&plc_socket) < 0) {
|
||||
PrivTaskDelay(1000);
|
||||
}
|
||||
|
||||
MelsecGetDataBySocket(plc_socket.socket, (MelsecReadItem *)melsec_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\n", __func__, i, data_length);
|
||||
CircularAreaAppWrite(circular_area, melsec_data, data_length, 0);
|
||||
}
|
||||
|
||||
/*read data every single read_period*/
|
||||
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)
|
||||
{
|
||||
ControlDisconnectSocket(&plc_socket);
|
||||
|
||||
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;
|
||||
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 = 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,
|
||||
protocol_format_info->p_read_item_data + protocol_format_info->last_item_size);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
p_recipe->ControlProtocolFormatCmd = MelsecProtocolFormatCmd;
|
||||
|
||||
p_recipe->done = &melsec_protocol_done;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -33,6 +33,10 @@ 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
|
||||
|
||||
/*
|
||||
CONTROL FRAMEWORK READ DATA FORMAT:
|
||||
| HEAD |device_id|read data length|read item count| data |
|
||||
|
@ -55,6 +59,13 @@ 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
|
||||
|
||||
{ PROTOCOL_END, NULL },
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue