pikapython/package/modbus/agile_modbus_rtu.c
pikastech fc9562ccd6 add modbus module
add aglie_mmodbus

add agile_modbus and LICENSE

fix warning

add serialize deserialize API
2022-09-18 23:42:10 +08:00

292 lines
9.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file agile_modbus_rtu.c
* @brief Agile Modbus 软件包 RTU 源文件
* @author 马龙伟 (2544047213@qq.com)
* @date 2021-12-02
*
* @attention
*
* <h2><center>&copy; Copyright (c) 2021 Ma Longwei.
* All rights reserved.</center></h2>
*
*/
#include "agile_modbus.h"
#include "agile_modbus_rtu.h"
/** @defgroup RTU RTU
* @{
*/
/** @defgroup RTU_Private_Constants RTU Private Constants
* @{
*/
/** Table of CRC values for high-order byte */
static const uint8_t _table_crc_hi[] =
{
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40};
/** Table of CRC values for low-order byte */
static const uint8_t _table_crc_lo[] =
{
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40};
/**
* @}
*/
/** @defgroup RTU_Private_Functions RTU Private Functions
* @{
*/
/**
* @brief RTU CRC16 计算
* @param buffer 数据指针
* @param buffer_length 数据长度
* @return CRC16 值
*/
static uint16_t agile_modbus_rtu_crc16(uint8_t *buffer, uint16_t buffer_length)
{
uint8_t crc_hi = 0xFF; /* high CRC byte initialized */
uint8_t crc_lo = 0xFF; /* low CRC byte initialized */
unsigned int i; /* will index into CRC lookup */
/* pass through message buffer */
while (buffer_length--) {
i = crc_hi ^ *buffer++; /* calculate the CRC */
crc_hi = crc_lo ^ _table_crc_hi[i];
crc_lo = _table_crc_lo[i];
}
return (crc_hi << 8 | crc_lo);
}
/**
* @brief RTU 设置地址接口
* @param ctx modbus 句柄
* @param slave 从机地址
* @return 0:成功
*/
static int agile_modbus_rtu_set_slave(agile_modbus_t *ctx, int slave)
{
ctx->slave = slave;
return 0;
}
/**
* @brief RTU 构建基础请求报文接口(头部报文)
* @param ctx modbus 句柄
* @param function 功能码
* @param addr 寄存器地址
* @param nb 寄存器数目
* @param req 数据存放指针
* @return 数据长度
*/
static int agile_modbus_rtu_build_request_basis(agile_modbus_t *ctx, int function,
int addr, int nb,
uint8_t *req)
{
req[0] = ctx->slave;
req[1] = function;
req[2] = addr >> 8;
req[3] = addr & 0x00ff;
req[4] = nb >> 8;
req[5] = nb & 0x00ff;
return AGILE_MODBUS_RTU_PRESET_REQ_LENGTH;
}
/**
* @brief RTU 构建基础响应报文接口(头部报文)
* @param sft modbus 头部参数结构体指针
* @param rsp 数据存放指针
* @return 数据长度
*/
static int agile_modbus_rtu_build_response_basis(agile_modbus_sft_t *sft, uint8_t *rsp)
{
rsp[0] = sft->slave;
rsp[1] = sft->function;
return AGILE_MODBUS_RTU_PRESET_RSP_LENGTH;
}
/**
* @brief RTU 准备响应接口
* @note 该 API 会将 req_length 自动减去 AGILE_MODBUS_RTU_CHECKSUM_LENGTH 长度
* @param req 请求数据指针
* @param req_length 请求数据长度
* @return 0 (RTU 没有事务标识符)
*/
static int agile_modbus_rtu_prepare_response_tid(const uint8_t *req, int *req_length)
{
(*req_length) -= AGILE_MODBUS_RTU_CHECKSUM_LENGTH;
/* No TID */
return 0;
}
/**
* @brief RTU 预发送数据接口
* @note 该 API 会计算 CRC16 并自动填入尾部
* @param req 数据存放指针
* @param req_length 已有数据长度
* @return 数据长度
*/
static int agile_modbus_rtu_send_msg_pre(uint8_t *req, int req_length)
{
uint16_t crc = agile_modbus_rtu_crc16(req, req_length);
req[req_length++] = crc >> 8;
req[req_length++] = crc & 0x00FF;
return req_length;
}
/**
* @brief RTU 检查接收数据完整性接口(CRC16 对比)
* @param ctx modbus 句柄
* @param msg 接收数据指针
* @param msg_length 有效数据长度
* @return >0:有效数据长度; 其他:异常
*/
static int agile_modbus_rtu_check_integrity(agile_modbus_t *ctx, uint8_t *msg, const int msg_length)
{
uint16_t crc_calculated;
uint16_t crc_received;
crc_calculated = agile_modbus_rtu_crc16(msg, msg_length - 2);
crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];
/* Check CRC of msg */
if (crc_calculated == crc_received)
return msg_length;
return -1;
}
/**
* @brief RTU 预检查确认接口(请求响应地址对比)
* @note 如果请求地址是广播地址0返回成功
* @param ctx modbus 句柄
* @param req 请求数据指针
* @param rsp 响应数据指针
* @param rsp_length 响应数据长度
* @return 0:成功; 其他:异常
*/
static int agile_modbus_rtu_pre_check_confirmation(agile_modbus_t *ctx, const uint8_t *req,
const uint8_t *rsp, int rsp_length)
{
/* Check responding slave is the slave we requested (except for broacast
* request) */
if (req[0] != rsp[0] && req[0] != AGILE_MODBUS_BROADCAST_ADDRESS)
return -1;
return 0;
}
/**
* @}
*/
/** @addtogroup RTU_Private_Constants
* @{
*/
/**
* @brief RTU 后端接口
*/
static const agile_modbus_backend_t agile_modbus_rtu_backend =
{
AGILE_MODBUS_BACKEND_TYPE_RTU,
AGILE_MODBUS_RTU_HEADER_LENGTH,
AGILE_MODBUS_RTU_CHECKSUM_LENGTH,
AGILE_MODBUS_RTU_MAX_ADU_LENGTH,
agile_modbus_rtu_set_slave,
agile_modbus_rtu_build_request_basis,
agile_modbus_rtu_build_response_basis,
agile_modbus_rtu_prepare_response_tid,
agile_modbus_rtu_send_msg_pre,
agile_modbus_rtu_check_integrity,
agile_modbus_rtu_pre_check_confirmation};
/**
* @}
*/
/** @defgroup RTU_Exported_Functions RTU Exported Functions
* @{
*/
/**
* @brief RTU 初始化
* @param ctx RTU 句柄
* @param send_buf 发送缓冲区
* @param send_bufsz 发送缓冲区大小
* @param read_buf 接收缓冲区
* @param read_bufsz 接收缓冲区大小
* @return 0:成功
*/
int agile_modbus_rtu_init(agile_modbus_rtu_t *ctx, uint8_t *send_buf, int send_bufsz, uint8_t *read_buf, int read_bufsz)
{
agile_modbus_common_init(&(ctx->_ctx), send_buf, send_bufsz, read_buf, read_bufsz);
ctx->_ctx.backend = &agile_modbus_rtu_backend;
ctx->_ctx.backend_data = ctx;
return 0;
}
/**
* @}
*/
/**
* @}
*/