当前位置:网站首页>libmodus源码解读
libmodus源码解读
2022-05-14 13:51:43【一帘忧梦】
libmodbus 源码分析:
1. uint8_t 的头文件 #include "stdint.h"
2. 两个最核心的结构体
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);
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;
struct _modbus {
/* Slave address */
int slave;
/* Socket or file descriptor */
int s;
int debug;
int error_recovery;
struct timeval response_timeout;
struct timeval byte_timeout;
struct timeval indication_timeout;
const modbus_backend_t *backend; //把各种操作封装在一个结构体中,也可以不封装。
void *backend_data;
};
typedef struct _modbus modbus_t;
这两个结构体定义在 modbus-private.h 从中可以借鉴到一点 在取名时不对外的结构体或函数命名可以在前面加 "_"
3. 应用:
----------------------------random-test-client.c-------------------------- 过程
modbus_t ctx = modbus_new_tcp("127.0.0.1", 1502); // ctx表示容器 在这里既可以表示cli 也可以表示ser
modbus_connect(ctx);
modbus_read_registers() 位于modbus.c协议核心层
->read_registers 位于modbus.c协议核心层
-> req_length = ctx->backend->build_request_basis(ctx, function, addr, nb, req); //构建requeset基础信息
rc = send_msg(ctx, req, req_length);
if (rc > 0) {
rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
rc = check_confirmation(ctx, req, rsp, rc);
offset = ctx->backend->header_length;
for (i = 0; i < rc; i++) {
/* shift reg hi_byte to temp OR with lo_byte */
dest[i] = (rsp[offset + 2 + (i << 1)] << 8) |
rsp[offset + 3 + (i << 1)];
}
return dest;
4. modbus_new_tcp 函数过程:
modbus_new_tcp-》
modbus_t *ctx;
modbus_tcp_t *ctx_tcp;
ctx = (modbus_t *)malloc(sizeof(modbus_t));}
_modbus_init_common(ctx); //给ctx 赋初始值 不管是modbus_tcp 还是modbus_rtu都是调用这个函数。
ctx->slave = MODBUS_TCP_SLAVE; //tcp
ctx->backend = &_modbus_tcp_backend; //tcp _modbus_tcp_backend 这个是一个已经定义并初始化了的结构体。 位于modbus-tcp.c
ctx->backend_data = (modbus_tcp_t *)malloc(sizeof(modbus_tcp_t)); //tcp 分配内存
ctx_tcp = (modbus_tcp_t *)ctx->backend_data;
->根据modbus_new_tcp 传入的参数填充ctx_tcp 也就是ctx->backend_data
>end
5.
// 具体的modbus_backend_t
modbus-tcp.c _modbus_tcp_backend结构体变量。 全局
const modbus_backend_t _modbus_tcp_backend = {
_MODBUS_BACKEND_TYPE_TCP,
_MODBUS_TCP_HEADER_LENGTH,
_MODBUS_TCP_CHECKSUM_LENGTH,
MODBUS_TCP_MAX_ADU_LENGTH,
_modbus_set_slave,
_modbus_tcp_build_request_basis,
_modbus_tcp_build_response_basis,
_modbus_tcp_prepare_response_tid,
_modbus_tcp_send_msg_pre,
_modbus_tcp_send,
_modbus_tcp_receive,
_modbus_tcp_recv,
_modbus_tcp_check_integrity,
_modbus_tcp_pre_check_confirmation,
_modbus_tcp_connect,
_modbus_tcp_close,
_modbus_tcp_flush,
_modbus_tcp_select,
_modbus_tcp_free
};
6.
//初始化modbus的公共部分
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->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;
}
7. ----------------------------random-test-server.c--------------------------
modbus_mapping_t定义了modbus的四种寄存器,并进行了内存数据映射,以方便快速访问和读取寄存器的值。
其他跟client差不多,多了一个modbus_mapping_new
modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
int nb_registers, int nb_input_registers)
{
return modbus_mapping_new_start_address(
0, nb_bits, 0, nb_input_bits, 0, nb_registers, 0, nb_input_registers);
}
modbus_mapping_new_start_address :映射内存,实际是分配了4个内存。
实现如下:
modbus_mapping_t *mb_mapping;
mb_mapping = (modbus_mapping_t *)malloc(sizeof(modbus_mapping_t)); //申请内存
/* 0X */
mb_mapping->nb_bits = nb_bits; nb:numbers 表示个数。
mb_mapping->start_bits = start_bits;
mb_mapping->tab_bits =(uint8_t *) malloc(nb_bits * sizeof(uint8_t)); 注意这里的长度
memset(mb_mapping->tab_bits, 0, nb_bits * sizeof(uint8_t));
main函数实现:
modbus_t *ctx;
modbus_mapping_t *mb_mapping;
ctx = modbus_new_tcp("127.0.0.1", 1502);
mb_mapping = modbus_mapping_new(500, 500, 500, 500);
s = modbus_tcp_listen(ctx, 1);
modbus_tcp_accept(ctx, &s);
rc = modbus_receive(ctx, query);
//free malloc
modbus_mapping_free(mb_mapping);
modbus_close(ctx);
modbus_free(ctx);
8. 超时处理 如果需要精确到ms us可以 也可以参考这里面的。
比如里面用到延时的例子:
static void _sleep_response_timeout(modbus_t *ctx)
{
/* Response timeout is always positive */
#ifdef _WIN32
/* usleep doesn't exist on Windows */
Sleep((ctx->response_timeout.tv_sec * 1000) +
(ctx->response_timeout.tv_usec / 1000));
#else
/* usleep source code */
struct timespec request, remaining;
request.tv_sec = ctx->response_timeout.tv_sec;
request.tv_nsec = ((long int)ctx->response_timeout.tv_usec) * 1000;
while (nanosleep(&request, &remaining) == -1 && errno == EINTR) {
request = remaining;
}
#endif
}
9.困惑已久的问题:使用enum 或#define 场景:
如果所有的整型值是连续的建议使用enum,如果中间可能会有非连续的建议使用#define
例如 libmodubs里面:
/* Protocol exceptions */
enum {
MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,
MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE,
MODBUS_EXCEPTION_ACKNOWLEDGE,
MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY,
MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE,
MODBUS_EXCEPTION_MEMORY_PARITY,
MODBUS_EXCEPTION_NOT_DEFINED,
MODBUS_EXCEPTION_GATEWAY_PATH,
MODBUS_EXCEPTION_GATEWAY_TARGET,
MODBUS_EXCEPTION_MAX
};
/* Modbus function codes */
#define MODBUS_FC_READ_COILS 0x01
#define MODBUS_FC_READ_DISCRETE_INPUTS 0x02
#define MODBUS_FC_READ_HOLDING_REGISTERS 0x03
#define MODBUS_FC_READ_INPUT_REGISTERS 0x04
#define MODBUS_FC_WRITE_SINGLE_COIL 0x05
#define MODBUS_FC_WRITE_SINGLE_REGISTER 0x06
#define MODBUS_FC_READ_EXCEPTION_STATUS 0x07
#define MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F
#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
#define MODBUS_FC_REPORT_SLAVE_ID 0x11
#define MODBUS_FC_MASK_WRITE_REGISTER 0x16
#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
#define MODBUS_BROADCAST_ADDRESS 0
10 #define 宏定义
#define a b ,后接两个参数,表示用a代替b。
例如 :#define PI 3.14
#define uint8_t unsigned char
#define 后只有一个参数
定义宏替换为空字符串,可以理解为后一个参数为空字符串
11. 宏函数与函数:
一般来说,应该用宏去替换小的、可重复的代码段,这样可以使程序运行速度更快;当任务比较复杂,需要多行代码才能实现时,或者要求程序越小越好时,就应该使用函数。
11.总结:libmodubs 构建了两个结构体 modbus_t 和 modbus_backend_t ,其中modbus_t用来表示modbus client或者server 通称为ctx(容器),modbus_backend_t 封装了各种modbus操作,作为指针放置在modbus_t 里面。
modbus_backend_t * 指向不同的具体类型设备 tcp/rtu。重点在于理解面向对象的设计方法
边栏推荐
猜你喜欢
随机推荐
- 大学英语六级考试(CET6)历年阅读试题译文
- CET-6 六级考试必备范文10篇
- 大学英语六级作文模板大全(完整版)
- 超实用25个英语演讲口语金句
- cet4-6高频词汇
- 新iPhone到手后要开启这8个设置,让手机更安全更好用
- 是能力更是文化,谈谈IT系统的安全发布
- tensorflow学习6 -- 跑通UNet图像分割
- postman循环调用同一个接口
- (Transfer Learning and fine tuning)迁移学习与微调
- ICDAR 2021竞赛 科学文献分析——表格识别综述部分(剩余部分是文档布局分析)
- Webpach打包器的如何使用
- 2021-IEEE论文-深度神经网络在文档图像表格识别中的应用现状及性能分析
- Why can 128 KB soul duel achieve such a long plot?
- The price rise twice a year highlights the greed of the introduction of Jidian, and the global chip hopes to find another way out
- Second week project training report
- Third week project training report
- Fourth week project training report
- Arm is still brilliant, but it is already under siege
- Performance hit everyone, Foxconn and apple are still close, and Lixun precision seems to have failed to take advantage of the opportunity
- 5g fell from the altar. Compared with 4G, the available technology is limited, and the only advantage is that it is faster
- A new force in the field of HPC -- Fu force supercomputing
- Data center white paper (2022): the data center industry continues to upgrade and fully enables the digital economy
- Error reading registry by C WPF application
- Teach you how to do prototype design
- P4 learning - Basic forwarding
- The contents of the input box are displayed on the right
- Clickhouse 22.3 lts release
- Programmer flirting special ~ ~ ~ nice H5 cube creative photo album, resources free!!! A gift from a programmer to a girl is very suitable for a young lady!
- [missing scan tool] awvs, appscan download and installation (with network disk link)
- 5.3 binary tree_ Code implementation of optimized heap and Top-k problem
- 5.4 binary tree_ Code implementation of various traversal and calculation
- Record: com mysql. cj. jdbc. exceptions. CommunicationsException: Communications link failure... [effective through personal test]
- Record: 1221 - incorrect usage of Union and order by [effective through personal test]
- [force deduction] backtracking 1 - Foundation + combination
- What role does cloud computing play in building intelligence?
- Abstract - the shortest novel of 2016
- Fiddler packet capture guide 05: breaking points
- EDA technology and market analysis
- 是能力更是文化,談談IT系統的安全發布