Files
kunlun/app/grapp/iot_proto_modbus.c
2024-09-28 14:24:04 +08:00

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 */