diff --git a/APP_Framework/Framework/control/plc_protocol/Kconfig b/APP_Framework/Framework/control/plc_protocol/Kconfig index 9839fe26e..11d498f81 100755 --- a/APP_Framework/Framework/control/plc_protocol/Kconfig +++ b/APP_Framework/Framework/control/plc_protocol/Kconfig @@ -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 diff --git a/APP_Framework/Framework/control/plc_protocol/include/melsec.h b/APP_Framework/Framework/control/plc_protocol/include/melsec.h index 2586fdd4e..bdefbc33f 100644 --- a/APP_Framework/Framework/control/plc_protocol/include/melsec.h +++ b/APP_Framework/Framework/control/plc_protocol/include/melsec.h @@ -15,5 +15,98 @@ * @brief plc protocol melsec * @version 3.0 * @author AIIT XUOS Lab - * @date 2022-10-08 - */ \ No newline at end of file + * @date 2022-11-29 + */ + +#ifndef MELSEC_H +#define MELSEC_H + +#include + +#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 diff --git a/APP_Framework/Framework/control/plc_protocol/melsec/Kconfig b/APP_Framework/Framework/control/plc_protocol/melsec/Kconfig index 139597f9c..93392b091 100755 --- a/APP_Framework/Framework/control/plc_protocol/melsec/Kconfig +++ b/APP_Framework/Framework/control/plc_protocol/melsec/Kconfig @@ -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 diff --git a/APP_Framework/Framework/control/plc_protocol/melsec/Makefile b/APP_Framework/Framework/control/plc_protocol/melsec/Makefile index 608656f03..9f60e0cf7 100755 --- a/APP_Framework/Framework/control/plc_protocol/melsec/Makefile +++ b/APP_Framework/Framework/control/plc_protocol/melsec/Makefile @@ -1,4 +1,4 @@ -SRC_FILES := +SRC_FILES := melsec.c include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/control/plc_protocol/melsec/melsec.c b/APP_Framework/Framework/control/plc_protocol/melsec/melsec.c new file mode 100644 index 000000000..9d95485eb --- /dev/null +++ b/APP_Framework/Framework/control/plc_protocol/melsec/melsec.c @@ -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 + +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; +} diff --git a/APP_Framework/Framework/control/shared/control_def.c b/APP_Framework/Framework/control/shared/control_def.c index 27ab2d761..fbc33225c 100644 --- a/APP_Framework/Framework/control/shared/control_def.c +++ b/APP_Framework/Framework/control/shared/control_def.c @@ -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 }, };