写的有些乱,别介意,希望给到你思路
后面有空再写个总结性的。
libmodbus默认是给win32写的。
修改带前下划线(_)私有函数,这是作者写demo用的,用户应该根据平台修改。
如_modbus_set_slave
RTU私有函数
modbus-rtu.c
配置/移植内容
接口结构体定义,这是官方给的,移植的时候应该自己写
//L1182
const modbus_backend_t _modbus_rtu_backend = {
_MODBUS_BACKEND_TYPE_RTU, //模式配置 RTU or tcp
_MODBUS_RTU_HEADER_LENGTH, //头长度:1
_MODBUS_RTU_CHECKSUM_LENGTH, //校验长度:1
MODBUS_RTU_MAX_ADU_LENGTH, //应用数据单元长度 ADU(Application Data Unit)
_modbus_set_slave, //设置从机地址
_modbus_rtu_build_request_basis, //
_modbus_rtu_build_response_basis, //
_modbus_rtu_prepare_response_tid, //
_modbus_rtu_send_msg_pre, //
_modbus_rtu_send, //
_modbus_rtu_receive, //
_modbus_rtu_recv, //
_modbus_rtu_check_integrity, //
_modbus_rtu_pre_check_confirmation, //
_modbus_rtu_connect, //
_modbus_rtu_is_connected, //
_modbus_rtu_close, //
_modbus_rtu_flush, //
_modbus_rtu_select, //
_modbus_rtu_free //
};
作者基于win32写的实体函数
static int _modbus_rtu_receive(modbus_t *ctx, uint8_t *req)
{
int rc;
modbus_rtu_t *ctx_rtu = ctx->backend_data;
if (ctx_rtu->confirmation_to_ignore) {
_modbus_receive_msg(ctx, req, MSG_CONFIRMATION);
/* Ignore errors and reset the flag */
ctx_rtu->confirmation_to_ignore = FALSE;
rc = 0;
if (ctx->debug) {
printf("Confirmation to ignore\n");
}
} else {
rc = _modbus_receive_msg(ctx, req, MSG_INDICATION);
if (rc == 0) {
/* The next expected message is a confirmation to ignore */
ctx_rtu->confirmation_to_ignore = TRUE;
}
}
return rc;
}
static ssize_t _modbus_rtu_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length)
{
#if defined(_WIN32)
return win32_ser_read(&((modbus_rtu_t *) ctx->backend_data)->w_ser, rsp, rsp_length);
#else
return read(ctx->s, rsp, rsp_length);
#endif
}
创建RTU时会绑定这些私有函数,如果自己创建了modbus_rtu_backend,要把这里的也改一下
modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit)
{
...
ctx->backend = &_modbus_rtu_backend;
...
}
结构体结构
//modbus-private.h L69
typedef struct _modbus_backend {
unsigned int backend_type;
unsigned int header_length;
unsigned int checksum_length;
unsigned int max_adu_length;
int (*set_slave)(modbus_t *ctx, int slave);
int (*build_request_basis)(
modbus_t *ctx, int function, int addr, int nb, uint8_t *req);
int (*build_response_basis)(sft_t *sft, uint8_t *rsp);
int (*prepare_response_tid)(const uint8_t *req, int *req_length);
int (*send_msg_pre)(uint8_t *req, int req_length);
ssize_t (*send)(modbus_t *ctx, const uint8_t *req, int req_length);
int (*receive)(modbus_t *ctx, uint8_t *req);
ssize_t (*recv)(modbus_t *ctx, uint8_t *rsp, int rsp_length);
int (*check_integrity)(modbus_t *ctx, uint8_t *msg, const int msg_length);
int (*pre_check_confirmation)(modbus_t *ctx,
const uint8_t *req,
const uint8_t *rsp,
int rsp_length);
int (*connect)(modbus_t *ctx);
unsigned int (*is_connected)(modbus_t *ctx);
void (*close)(modbus_t *ctx);
int (*flush)(modbus_t *ctx);
int (*select)(modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);
void (*free)(modbus_t *ctx);
} modbus_backend_t;
其他需要改的内容
看代码的过程又发现一个带前下划线的函数
//modbus.c L1707
void _modbus_init_common(modbus_t *ctx)
{
/* Slave and socket are initialized to -1 */
ctx->slave = -1;
ctx->s = -1;
ctx->debug = FALSE;
ctx->error_recovery = MODBUS_ERROR_RECOVERY_NONE;
ctx->quirks = MODBUS_QUIRK_NONE;
ctx->response_timeout.tv_sec = 0;
ctx->response_timeout.tv_usec = _RESPONSE_TIMEOUT;
ctx->byte_timeout.tv_sec = 0;
ctx->byte_timeout.tv_usec = _BYTE_TIMEOUT;
ctx->indication_timeout.tv_sec = 0;
ctx->indication_timeout.tv_usec = 0;
}
于是, 直接在文档里搜索_modbus_,把带下划线的都找出来改掉
libmodbus下载地址
题外话
AI不太同意我的猜想,但我就觉得前下划线是移植/配置接口文件。
串口发送、接收、关闭就是应该根据硬件平台定义的。
_modbus_rtu_send、_modbus_rtu_receive、modbus_rtu_close
另外,stm32中弱定义,前面就有“”,给我感觉就是可以用户自己定义
__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_UART_MspInit can be implemented in the user file
*/
}