413 lines
14 KiB
C
Executable File
413 lines
14 KiB
C
Executable File
/****************************************************************************
|
|
|
|
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
|
|
|
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
|
be copied by any method or incorporated into another program without
|
|
the express written consent of Aerospace C.Power. This Information or any portion
|
|
thereof remains the property of Aerospace C.Power. The Information contained herein
|
|
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
|
liability for its use in any way and conveys no license or title under
|
|
any patent or copyright and makes no representation or warranty that this
|
|
Information is free from patent or copyright infringement.
|
|
|
|
****************************************************************************/
|
|
|
|
/* os_ship header files */
|
|
#include "os_timer_api.h"
|
|
|
|
/* iot common header files */
|
|
#include "iot_app_api.h"
|
|
#include "iot_io_api.h"
|
|
#include "iot_task_api.h"
|
|
#include "iot_proto_common.h"
|
|
#include "iot_proto_dl645.h"
|
|
#include "iot_proto_modbus.h"
|
|
#include "iot_proto_ge.h"
|
|
|
|
#if PLC_SUPPORT_STA_ROLE
|
|
|
|
mcu_data_handle_t mcu_data_modbus;
|
|
extern uint8_t ge_buf[];
|
|
extern void iot_common_bin_dump(uint8_t *data, uint32_t dlen);
|
|
|
|
/**
|
|
* @brief iot_modbus_cal_crc() - To calculate crc of modbus
|
|
* @param pbyte: point to the data
|
|
* @param nlen: the number of input data
|
|
* @retval: the value of crc
|
|
*/
|
|
uint16_t iot_modbus_cal_crc(uint8_t *pbyte, uint32_t nlen)
|
|
{
|
|
uint8_t i;
|
|
uint32_t pos;
|
|
uint16_t crc = 0xFFFF;
|
|
|
|
for (pos = 0; pos < nlen; pos++) {
|
|
/* XOR byte into least sig. byte of crc */
|
|
crc ^= (uint16_t)pbyte[pos];
|
|
/* Loop over each bit */
|
|
for (i = 8; i != 0; i--) {
|
|
/* If the LSB is set */
|
|
if ((crc & 0x0001) != 0) {
|
|
/* Shift right and XOR 0xA001 */
|
|
crc >>= 1;
|
|
/* Else LSB is not set */
|
|
crc ^= 0xA001;
|
|
} else {
|
|
/* Just shift right */
|
|
crc >>= 1;
|
|
}
|
|
}
|
|
}
|
|
/* Note, this number has low and high bytes swapped,
|
|
so use it accordingly (or swap bytes) */
|
|
return crc;
|
|
}
|
|
|
|
/**
|
|
* @brief iot_match_modbus_cmd() - To check if modbus cmd or not
|
|
* @param cmd the cmd of mudbus
|
|
* @param retval: match or not match
|
|
*/
|
|
static uint8_t iot_match_modbus_cmd(uint8_t cmd)
|
|
{
|
|
uint8_t ret;
|
|
if ((cmd == MODBUS_CMD_01_READ_COIL_STATUS) ||
|
|
(cmd == MODBUS_CMD_02_READ_INPUT_STATUS) ||
|
|
(cmd == MODBUS_CMD_03_READ_HOLD_REG) ||
|
|
(cmd == MODBUS_CMD_04_READ_INPUT_REG) ||
|
|
(cmd == MODBUS_CMD_05_ENFORCE_COIL) ||
|
|
(cmd == MODBUS_CMD_06_PRESET_REG) ||
|
|
(cmd == MODBUS_CMD_0F_ENFORCE_MULTIPLE_COIL) ||
|
|
(cmd == MODBUS_CMD_10_PRESET_MULTIPLE_REG)) {
|
|
ret = MATCH;
|
|
} else {
|
|
ret = NO_MATCH;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* @brief iot_modbus_extend_dl645_pack() - To pickup modbus cmd frames and pack
|
|
it in extend dl645 frame
|
|
* @param input: point to the input data
|
|
* @param p_data: point to the modbus data length
|
|
* @param ge_buf_pos: the position of ge buf
|
|
* @param half_sign: half data figure
|
|
* @param p_loc: the distance loop will jump
|
|
* @param crc_input: the crc value whitch in the frame
|
|
* @param crc_cal: the crc value whitch is calculated
|
|
* @param ge_len: the length of the frame
|
|
* @param retval: how many frames 1 or 0
|
|
*/
|
|
static uint8_t iot_modbus_extend_dl645_pack(uint8_t *input, uint8_t *p_data,
|
|
uint16_t ge_buf_pos, uint8_t *half_sign, uint16_t* p_loc, uint16_t crc_input,
|
|
uint16_t crc_cal, uint16_t ge_len)
|
|
{
|
|
uint8_t frame_num = 0;
|
|
if (crc_input == crc_cal) {
|
|
*p_loc = ge_len;
|
|
if (iot_ge_buf_overflow_test(ge_buf_pos, ge_len +
|
|
sizeof(ge_frame_data_send_set_subfn160_t) +
|
|
sizeof(ge_frm_tail_t) + DL645_PARSE_FRM_MIN_LEN + DL645_DI_LEN)) {
|
|
iot_sta_pack_extend_dl645_to_ge(input, p_data, &ge_len,
|
|
MODBUS_TYPE);
|
|
*half_sign = HALF_NO;
|
|
frame_num = 1;
|
|
} else {
|
|
*half_sign = OVERFLOW;
|
|
iot_cus_printf("cmd %d make ge_buf overflow\n", input[1]);
|
|
}
|
|
}
|
|
|
|
return frame_num;
|
|
}
|
|
|
|
/*
|
|
* @brief iot_modbus_cmd_01_to_04_fn() - To pickup 0x01 to 0x04 cmd frames from
|
|
buff
|
|
* @param input: point to the input data
|
|
* @param p_data: point to the modbus data length
|
|
* @param ge_buf_pos: the position of ge buf
|
|
* @param half_sign: half data figure
|
|
* @param tt_left: the length of data in the buffer do not check
|
|
* @param p_loc: the distance loop will jump
|
|
* @param retval: how many frames 1 or 0
|
|
*/
|
|
static uint8_t iot_modbus_cmd_01_to_04_fn(uint8_t *input, uint8_t *p_data,
|
|
uint16_t ge_buf_pos, uint8_t *half_sign, uint8_t tt_left, uint16_t* p_loc)
|
|
{
|
|
uint8_t frame_num = 0;
|
|
/* the ask frame, it is not have the member "data[0]", the length of the
|
|
frame is constant */
|
|
uint8_t frame_len_no_data = sizeof(modbus_head_01_to_10);
|
|
uint16_t crc_cal;
|
|
uint16_t crc_input;
|
|
uint16_t ack_data_len;
|
|
modbus_head_01_to_10 *inbuf;
|
|
modbus_head_01_04_with_len *inbuf_ack;
|
|
|
|
if (tt_left < frame_len_no_data) {
|
|
*half_sign = HALF_YES;
|
|
} else {
|
|
inbuf = (modbus_head_01_to_10 *)input;
|
|
crc_input = (inbuf->crc_h * LEFT_8BIT + inbuf->crc_l);
|
|
crc_cal = iot_modbus_cal_crc(input, MODBUS_CMD_LEN_NO_DATA);
|
|
frame_num = iot_modbus_extend_dl645_pack(input, p_data, ge_buf_pos,
|
|
half_sign, p_loc, crc_input, crc_cal, frame_len_no_data);
|
|
if (frame_num == 1) {
|
|
goto out;
|
|
} else if (*half_sign == OVERFLOW) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
inbuf_ack = (modbus_head_01_04_with_len *)input;
|
|
if (tt_left < inbuf_ack->len + MODBUS_CMD_01_04_ACK_LEN) {
|
|
*half_sign = HALF_YES;
|
|
goto out;
|
|
}
|
|
|
|
/*check as ack code*/
|
|
ack_data_len = inbuf_ack->len;
|
|
crc_cal = iot_modbus_cal_crc(input, ack_data_len +
|
|
MODBUS_CMD_01_04_ACK_LEN_NO_CRC);
|
|
crc_input = inbuf_ack->data[ack_data_len + 1] * LEFT_8BIT +
|
|
inbuf_ack->data[ack_data_len];
|
|
ack_data_len += MODBUS_CMD_01_04_ACK_LEN;
|
|
frame_num = iot_modbus_extend_dl645_pack(input, p_data, ge_buf_pos,
|
|
half_sign, p_loc, crc_input, crc_cal, ack_data_len);
|
|
out:
|
|
return frame_num;
|
|
}
|
|
|
|
/*
|
|
* @brief iot_modbus_cmd_05_06_fn() - To pickup 0x05 or 0x06 cmd frames from
|
|
buffer
|
|
* @param input: point to the input data
|
|
* @param p_data: point to the modbus data length
|
|
* @param ge_buf_pos: the position of ge buf
|
|
* @param half_sign: half data figure
|
|
* @param tt_left: the length of data in the buffer do not check
|
|
* @param p_loc: the distance loop will jump
|
|
* @param retval: how many frames 1 or 0
|
|
*/
|
|
static uint8_t iot_modbus_cmd_05_06_fn(uint8_t *input, uint8_t *p_data,
|
|
uint16_t ge_buf_pos, uint8_t *half_sign, uint8_t tt_left, uint16_t* p_loc)
|
|
{
|
|
uint8_t frame_num = 0;
|
|
uint8_t frame_len_no_data = sizeof(modbus_head_01_to_10);
|
|
uint16_t crc_cal;
|
|
uint16_t crc_input;
|
|
modbus_head_01_to_10 *inbuf;
|
|
|
|
if (tt_left < frame_len_no_data) {
|
|
*half_sign = HALF_YES;
|
|
} else {
|
|
inbuf = (modbus_head_01_to_10 *)input;
|
|
crc_input = (inbuf->crc_h * LEFT_8BIT + inbuf->crc_l);
|
|
crc_cal = iot_modbus_cal_crc(input, MODBUS_CMD_LEN_NO_DATA);
|
|
frame_num = iot_modbus_extend_dl645_pack(input, p_data, ge_buf_pos,
|
|
half_sign, p_loc, crc_input, crc_cal, frame_len_no_data);
|
|
}
|
|
return frame_num;
|
|
}
|
|
|
|
/*
|
|
* @brief iot_modbus_cmd_0f_10_fn() - To pickup 0x0f or 0x10 cmd frames from
|
|
buffer
|
|
* @param input: point to the input data
|
|
* @param p_data: point to the modbus data length
|
|
* @param ge_buf_pos: the position of ge buf
|
|
* @param half_sign: half data figure
|
|
* @param tt_left: the length of data in the buffer do not check
|
|
* @param p_loc: the distance loop will jump
|
|
* @param retval: how many frames 1 or 0
|
|
*/
|
|
static uint8_t iot_modbus_cmd_0f_10_fn(uint8_t *input, uint8_t *p_data,
|
|
uint16_t ge_buf_pos, uint8_t *half_sign, uint8_t tt_left, uint16_t* p_loc)
|
|
{
|
|
uint8_t frame_num = 0;
|
|
uint8_t frame_len_no_data = sizeof(modbus_head_01_to_10);
|
|
uint16_t crc_cal;
|
|
uint16_t crc_input;
|
|
uint16_t ack_data_len;
|
|
modbus_head_01_to_10 *inbuf;
|
|
modbus_head_0f_10_with_len *inbuf_ack;
|
|
|
|
if (tt_left < frame_len_no_data) {
|
|
*half_sign = HALF_YES;
|
|
} else {
|
|
inbuf = (modbus_head_01_to_10 *)input;
|
|
crc_input = (inbuf->crc_h * LEFT_8BIT + inbuf->crc_l);
|
|
crc_cal = iot_modbus_cal_crc(input, MODBUS_CMD_LEN_NO_DATA);
|
|
frame_num = iot_modbus_extend_dl645_pack(input, p_data, ge_buf_pos,
|
|
half_sign, p_loc, crc_input, crc_cal, frame_len_no_data);
|
|
if (frame_num == 1) {
|
|
goto out;
|
|
} else if (*half_sign == OVERFLOW) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
inbuf_ack = (modbus_head_0f_10_with_len *)input;
|
|
if (tt_left < inbuf_ack->data_len + MODBUS_CMD_0F_10_ACK_LEN) {
|
|
*half_sign = HALF_YES;
|
|
goto out;
|
|
}
|
|
|
|
/*check as ack code*/
|
|
ack_data_len = inbuf_ack->data_len;
|
|
crc_cal = iot_modbus_cal_crc(input, ack_data_len +
|
|
MODBUS_CMD_0F_10_ACK_LEN_NO_CRC);
|
|
crc_input = inbuf_ack->data[ack_data_len + 1] * LEFT_8BIT +
|
|
inbuf_ack->data[ack_data_len];
|
|
ack_data_len += MODBUS_CMD_0F_10_ACK_LEN;
|
|
frame_num = iot_modbus_extend_dl645_pack(input, p_data, ge_buf_pos,
|
|
half_sign, p_loc, crc_input, crc_cal, ack_data_len);
|
|
out:
|
|
return frame_num;
|
|
}
|
|
|
|
uint8_t iot_proto_modbus_format_check(mcu_data_handle_t *recv_data,
|
|
uint8_t *pdata, uint16_t *ret_size, uint16_t *ge_len_out)
|
|
{
|
|
uint8_t half_sign = HALF_NO;
|
|
uint8_t check_result = GET_NO_FRAME;
|
|
uint8_t *buf = &recv_data->data[recv_data->data_pos];
|
|
uint16_t tt_len = recv_data->total_len - recv_data->data_pos;
|
|
uint16_t input_data_pos = 0;
|
|
|
|
if (buf == NULL) {
|
|
goto result;
|
|
}
|
|
|
|
if (tt_len == 1) {
|
|
check_result = GET_HALF_FRAME;
|
|
goto result;
|
|
}
|
|
|
|
if ((tt_len < MODBUS_MIN_LEN) && (iot_match_modbus_cmd(buf[1]))) {
|
|
check_result = GET_HALF_FRAME;
|
|
goto result;
|
|
}
|
|
|
|
switch (buf[1]) {
|
|
case MODBUS_CMD_01_READ_COIL_STATUS:
|
|
case MODBUS_CMD_02_READ_INPUT_STATUS:
|
|
case MODBUS_CMD_03_READ_HOLD_REG:
|
|
case MODBUS_CMD_04_READ_INPUT_REG:
|
|
{
|
|
check_result = iot_modbus_cmd_01_to_04_fn(&buf[0], &pdata[*ret_size],
|
|
*ret_size, &half_sign, tt_len, &input_data_pos);
|
|
break;
|
|
}
|
|
|
|
case MODBUS_CMD_05_ENFORCE_COIL:
|
|
case MODBUS_CMD_06_PRESET_REG:
|
|
{
|
|
check_result = iot_modbus_cmd_05_06_fn(&buf[0], &pdata[*ret_size],
|
|
*ret_size, &half_sign, tt_len, &input_data_pos);
|
|
break;
|
|
}
|
|
|
|
case MODBUS_CMD_0F_ENFORCE_MULTIPLE_COIL:
|
|
case MODBUS_CMD_10_PRESET_MULTIPLE_REG:
|
|
{
|
|
check_result = iot_modbus_cmd_0f_10_fn(&buf[0], &pdata[*ret_size],
|
|
*ret_size, &half_sign, tt_len, &input_data_pos);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (half_sign == HALF_YES) {
|
|
check_result = GET_HALF_FRAME;
|
|
} else if (half_sign == OVERFLOW) {
|
|
check_result = GET_OVERFLOW;
|
|
}
|
|
|
|
if (check_result == GET_ONE_FRAME) {
|
|
*ret_size += sizeof(ge_frm_tail_t) + DL645_PARSE_FRM_MIN_LEN +
|
|
input_data_pos + sizeof(ge_frame_data_send_set_subfn160_t) +
|
|
DL645_DI_LEN;
|
|
*ge_len_out += input_data_pos;
|
|
}
|
|
|
|
result:
|
|
return check_result;
|
|
}
|
|
|
|
uint8_t iot_proto_modbus_frm_format_check(uint8_t *data, uint16_t len)
|
|
{
|
|
uint8_t err_code = 0, crc_h, crc_l, min_len;
|
|
uint16_t crc_cal;
|
|
uint16_t crc_input;
|
|
modbus_head_01_to_10 *inbuf;
|
|
modbus_head_0f_10_with_len *buf;
|
|
|
|
if (len < sizeof(modbus_head_01_to_10)) {
|
|
err_code = 1;
|
|
goto out;
|
|
}
|
|
|
|
switch (data[1]) {
|
|
case MODBUS_CMD_01_READ_COIL_STATUS:
|
|
case MODBUS_CMD_02_READ_INPUT_STATUS:
|
|
case MODBUS_CMD_03_READ_HOLD_REG:
|
|
case MODBUS_CMD_04_READ_INPUT_REG:
|
|
case MODBUS_CMD_05_ENFORCE_COIL:
|
|
case MODBUS_CMD_06_PRESET_REG:
|
|
{
|
|
if (len != sizeof(modbus_head_01_to_10)) {
|
|
err_code = 2;
|
|
goto out;
|
|
}
|
|
inbuf = (modbus_head_01_to_10 *)data;
|
|
crc_input = (inbuf->crc_h * LEFT_8BIT + inbuf->crc_l);
|
|
crc_cal = iot_modbus_cal_crc(data, MODBUS_CMD_LEN_NO_DATA);
|
|
if (crc_input != crc_cal) {
|
|
err_code = 3;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MODBUS_CMD_0F_ENFORCE_MULTIPLE_COIL:
|
|
case MODBUS_CMD_10_PRESET_MULTIPLE_REG:
|
|
{
|
|
buf = (modbus_head_0f_10_with_len *)data;
|
|
min_len = sizeof(modbus_head_0f_10_with_len);
|
|
if (len != (min_len + buf->data_len + 2)) {
|
|
err_code = 4;
|
|
break;
|
|
}
|
|
crc_l = data[min_len + buf->data_len];
|
|
crc_h = data[min_len + buf->data_len + 1];
|
|
crc_input = (crc_h * LEFT_8BIT + crc_l);
|
|
crc_cal = iot_modbus_cal_crc(data, buf->data_len + min_len);
|
|
if (crc_input != crc_cal) {
|
|
err_code = 5;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
err_code = 6;
|
|
break;
|
|
}
|
|
}
|
|
|
|
out:
|
|
if (err_code > 0) {
|
|
iot_cus_printf("modbus_frm_check err_code:%x\n", err_code);
|
|
}
|
|
|
|
return err_code;
|
|
}
|
|
|
|
#endif /* PLC_SUPPORT_STA_ROLE */ |