413 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			413 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /****************************************************************************
 | ||
|  | 
 | ||
|  | 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 */
 |