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