modbus_class.h
#ifndef __MODBUS_CLASS_H__
#define __MODBUS_CLASS_H__
#include "apis/Net.h"
#include "Foundation/Guard.h"
#ifndef uint8_t
typedef unsigned char uint8_t;
#endif
#ifndef uint16_t
typedef unsigned short uint16_t;
#endif
#ifndef uint32_t
typedef unsigned int uint32_t;
#endif
class CModBus
{
public:
typedef enum
{
MODBUS_ERROR_RECOVERY_NONE = 0,
MODBUS_ERROR_RECOVERY_LINK = (1<<1),
MODBUS_ERROR_RECOVERY_PROTOCOL = (1<<2)
} ERROR_RECOVERY_MODE;
typedef struct _ST_SLAVE_INFO
{
/* 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;
void *backend;
void *backend_data;
}ST_SLAVE_INFO;
typedef struct _ST_MAPPING_INFO{
int nb_bits;
int start_bits;
int nb_input_bits;
int start_input_bits;
int nb_input_registers;
int start_input_registers;
int nb_registers;
int start_registers;
uint8_t *tab_bits;
uint8_t *tab_input_bits;
uint16_t *tab_input_registers;
uint16_t *tab_registers;
} ST_MAPPING_INFO;
public:
/**
* @brief TCP-IP构造
* @return 返回丛机描述结构指针
*/
CModBus(const char *ip_address, int port);
/**
* @brief TCP IPv4或Ipv6服务器进行通信。node参数指定要连接的主机的主机名或IP地址,例如。 192.168.0.5,:: 1或server.com。
* @brief 服务参数是要连接的服务名称/端口号。 要使用默认的Modbus端口,请使用字符串“502”。 在许多Unix系统上,使用大于或等于1024的端口号是很方便的,因为没有必要拥有管理员权限。
* @return 返回丛机描述结构指针
*/
CModBus(const char *node, const char *service);
/**
* @brief RTU构造方式
* @return 返回丛机描述结构指针
*/
CModBus(const char *device, int baud, char parity,int data_bit, int stop_bit);
/**
* @brief TCP-IP构造
* @return 返回丛机描述结构指针
*/
~CModBus();
/**
* @brief TCP-IP配置丛机
* @return 返回丛机描述结构指针
*/
ST_SLAVE_INFO* NewTcp(const char *ip_address, int port);
/**
* @brief 配置TCP监听最大路数
*/
int TcpListen(int nb_connection);
/**
* @brief TCP接收数据
*/
int TcpAccept(int *s);
ST_SLAVE_INFO* NewTcpPi(const char *node, const char *service);
int TcpPiListen(int nb_connection);
int TcpPiAccept(int *s);
/**
* @brief RTU配置丛机,参数为串口配置
* @return 返回丛机描述结构指针
*/
ST_SLAVE_INFO* NewRtu(const char *device, int baud, char parity,int data_bit, int stop_bit);
/**
* @brief 串口模式选择MODBUS_RTU_RS232/MODBUS_RTU_RS485
*/
int RtuSetSerialMode(int mode);
/**
* @brief 获取串口模式
*/
int RtuGetSerialMode();
/**
* @brief 设置RTS,默认MODBUS_RTU_RTS_NONE非实时,可选择MODBUS_RTU_RTS_NONE/MODBUS_RTU_RTS_UP/MODBUS_RTU_RTS_DOWN
* @当使用MODBUS_RTU_RTS_UP时,在RTS标志启用的情况下进行ioctl调用,然后在延迟1ms之后将数据写入总线,\
* @在禁用RTS标志的情况下进行另个ioctl调用,并且再次发生1ms的延迟--伪实时-重新同步
* @MODBUS_RTU_RTS_DOWN模式应用相同的过程,但具有反转的RTS标志。
*/
int RtuSetRts(int mode);
/**
* @brief 获取RTS模式
*/
int RtuGetRts();
/**
* @brief 当配置实时模式RTU时,默认有个内部函数处理在设置RTS发送数据前后被设置,也可以自定义 set_rts
*/
int RtuSetCustomRts(void (*set_rts) (void* ctx, int on));
/**
* @brief 当配置为RTU且在实时模式RTS时,配置发送和接收延时时间
*/
int RtuSetRtsDelay(int us);
int RtuGetRtsDelay();
/**
* @brief 配置丛机
*/
int SetSlave(int slave);
int GetSlave(void);
/**
* @brief 当连接失败或者收到的字节不是预期的时候,设置错误恢复模式
*/
int SetErrorRecovery(ERROR_RECOVERY_MODE error_recovery);
/**
* @brief 设置套接字或文件描述符,可进行多个客户端连接
*/
int SetSocket(int s);
int GetSocket(void);
/**
* @brief 存储用于在超时参数中等待响应的超时间隔
*/
int GetResponseTimeout( uint32_t *to_sec, uint32_t *to_usec);
int SetResponseTimeout(uint32_t to_sec, uint32_t to_usec);
/**
* @brief 在超时参数中存储同一消息的两个连续字节之间的超时间隔
*/
int GetByteTimeout(uint32_t *to_sec, uint32_t *to_usec);
int SetByteTimeout(uint32_t to_sec, uint32_t to_usec);
/**
* @brief 设置响应超时时间
*/
int GetIndicationTimeout(uint32_t *to_sec, uint32_t *to_usec);
int SetIndicationTimeout(uint32_t to_sec, uint32_t to_usec);
/**
* @brief 检索当前的头部长度
*/
int GetHeaderLength();
/**
* @brief 使用参数中给出的信息建立到Modbus服务器,网络或总线的连接。
*/
int Connect();
/**
* @brief 关闭连接
*/
void Close();
/**
* @brief 释放描述结构中的内部资源,在析构之前调用
*/
void Free();
/**
* @brief 丢弃收到的数据
*/
int Flush();
/**
* @brief 调试标志,等同boolean类型,TRUE打开,FALSE关闭
*/
int SetDebug(int flag);
/**
* @brief 根据错误编号在标准输出或标准错误上打印错误信息
*/
const char *Strerror(int errnum);
/**
* @brief 读线圈 0x01
*/
int ReadBits(int addr, int nb, uint8_t *dest);
/**
* @brief 读输入离散量 0x02
*/
int ReadInputBits(int addr, int nb, uint8_t *dest);
/**
* @brief 读多个寄存器 0x03
*/
int ReadRegisters(int addr, int nb, uint16_t *dest);
/**
* @brief 读输入寄存器 0x04
*/
int ReadInputRegisters(int addr, int nb, uint16_t *dest);
/**
* @brief 写单个线圈 0x05
*/
int WriteBit(int coil_addr, int status);
/**
* @brief 写单个寄存器 0x06
*/
int WriteRegister(int reg_addr, int value);
/**
* @brief 写多个线圈 0x0F
*/
int WriteBits(int addr, int nb, const uint8_t *data);
/**
* @brief 写多个寄存器 0X10
*/
int WriteRegisters(int addr, int nb, const uint16_t *data);
/**
* @brief 屏蔽写寄存器 0x16
*/
int MaskWriteRegister(int addr, uint16_t and_mask, uint16_t or_mask);
/**
* @brief 读写多个寄存器 0x17
*/
int WriteAndReadRegisters(int write_addr, int write_nb, const uint16_t *src, int read_addr, int read_nb, uint16_t *dest);
/**
* @brief 获取丛机ID
*/
int ReportSlaveId(int max_dest, uint8_t *dest);
/**
* @brief 分配4个数组来存储位,输入位,寄存器和输入 寄存器。 指针存储在modbus_mapping结构中。
*/
ST_MAPPING_INFO* MappingNewStartAddress(
unsigned int start_bits, unsigned int nb_bits,
unsigned int start_input_bits, unsigned int nb_input_bits,
unsigned int start_registers, unsigned int nb_registers,
unsigned int start_input_registers, unsigned int nb_input_registers);
/**
* @brief 分配4个数组空间
*/
ST_MAPPING_INFO* MappingNew(int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers);
/**
* @brief 释放4个数组空间
*/
void MappingFree(ST_MAPPING_INFO *mb_mapping);
/**
* @brief 发送一个请求。 此功能必须用于调试目的。
*/
int SendRawRequest(uint8_t *raw_req, int raw_req_length);
/**
* @brief Receive the request from a modbus master
*/
int Receive(uint8_t *req);
/**
* @brief 用于调试目的。
*/
int ReceiveConfirmation(uint8_t *rsp);
/**
* @brief Send a response to the received request. Analyses the request and constructs a response.
*/
int Reply(const uint8_t *req, int req_length, ST_MAPPING_INFO *mb_mapping);
/**
* @brief send an exception response based on the exception_code
*/
int ReplyException(const uint8_t *req, unsigned int exception_code);
/**
* @brief Sets many bits from a single byte value (all 8 bits of the byte value are set。
*/
void SetBitsFromByte(uint8_t *dest, int idx, const uint8_t value);
/**
* @brief Sets many bits from a table of bytes (only the bits between idx and idx + nb_bits are set)
*/
void SetBitsFromBytes(uint8_t *dest, int idx, unsigned int nb_bits, const uint8_t *tab_byte);
/**
* @brief Gets the byte value from many bits. To obtain a full byte, set nb_bits to 8.
*/
uint8_t GetByteFromBits(const uint8_t *src, int idx, unsigned int nb_bits);
/**
* @brief DEPRECATED - Get a float from 4 bytes in sort of Modbus format
*/
float GetFloat(const uint16_t *src);
/**
* @brief Get a float from 4 bytes (Modbus) without any conversion (ABCD)
*/
float GetFloatAbcd(const uint16_t *src);
/**
* @brief Get a float from 4 bytes (Modbus) in inversed format (DCBA)
*/
float GetFloatDcba(const uint16_t *src);
/**
* @brief Get a float from 4 bytes (Modbus) with swapped bytes (BADC)
*/
float GetFloatBadc(const uint16_t *src);
/**
* @brief Get a float from 4 bytes (Modbus) with swapped words (CDAB)
*/
float GetFloatCdab(const uint16_t *src);
/**
* @brief DEPRECATED - Set a float to 4 bytes in a sort of Modbus format!
*/
void SetFloat(float f, uint16_t *dest);
/**
* @brief Set a float to 4 bytes for Modbus w/o any conversion (ABCD)
*/
void SetFloatAbcd(float f, uint16_t *dest);
/**
* @brief Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA)
*/
void SetFloatDcba(float f, uint16_t *dest);
/**
* @brief Set a float to 4 bytes for Modbus with byte swap conversion (BADC)
*/
void SetFloatBadc(float f, uint16_t *dest);
/**
* @brief Set a float to 4 bytes for Modbus with word swap conversion (CDAB)
*/
void modbSetFloatCdab(float f, uint16_t *dest);
private:
ST_SLAVE_INFO* m_ctx;
CMutex m_mtxCtx;
};
#endif //__MODBUS_CLASS_H__
modbus_class.cpp
#include "modbus.h"
#include "modbus-rtu.h"
#include "modbus-tcp.h"
#include "modbus-version.h"
#include "Modbus/Modbus_class.h"
CModBus::CModBus(const char *ip_address, int port)
{
CGuard guard(m_mtxCtx);
m_ctx = (ST_SLAVE_INFO*)NewTcp(ip_address, port);
Flush();
}
CModBus::CModBus(const char *node, const char *service)
{
CGuard guard(m_mtxCtx);
m_ctx = (ST_SLAVE_INFO*)NewTcpPi(node, service);
}
CModBus::CModBus(const char *device, int baud, char parity,int data_bit, int stop_bit)
{
CGuard guard(m_mtxCtx);
m_ctx = (ST_SLAVE_INFO*)NewRtu(device, baud, parity, data_bit, stop_bit);
}
CModBus::~CModBus()
{
CGuard guard(m_mtxCtx);
Close();
Free();
m_ctx = NULL;
}
CModBus::ST_SLAVE_INFO* CModBus::NewTcp(const char *ip_address, int port)
{
return (ST_SLAVE_INFO*)modbus_new_tcp(ip_address, port);
}
int CModBus::TcpListen(int nb_connection)
{
CGuard guard(m_mtxCtx);
return modbus_tcp_listen((modbus_t *)m_ctx, nb_connection);
}
int CModBus::TcpAccept(int *s)
{
CGuard guard(m_mtxCtx);
return modbus_tcp_accept((modbus_t *)m_ctx, s);
}
CModBus::ST_SLAVE_INFO* CModBus::NewTcpPi(const char *node, const char *service)
{
return (ST_SLAVE_INFO*)modbus_new_tcp_pi(node, service);
}
int CModBus::TcpPiListen(int nb_connection)
{
CGuard guard(m_mtxCtx);
return modbus_tcp_pi_listen((modbus_t *)m_ctx, nb_connection);
}
int CModBus::TcpPiAccept(int *s)
{
CGuard guard(m_mtxCtx);
return modbus_tcp_pi_accept((modbus_t *)m_ctx, s);
}
CModBus::ST_SLAVE_INFO* CModBus::NewRtu(const char *device, int baud, char parity,int data_bit, int stop_bit)
{
return (ST_SLAVE_INFO*)modbus_new_rtu(device, baud, parity, data_bit, stop_bit);
}
int CModBus::RtuSetSerialMode(int mode)
{
CGuard guard(m_mtxCtx);
return modbus_rtu_set_serial_mode((modbus_t *)m_ctx, mode);
}
int CModBus::RtuGetSerialMode()
{
CGuard guard(m_mtxCtx);
return modbus_rtu_get_serial_mode((modbus_t *)m_ctx);
}
int CModBus::RtuSetRts(int mode)
{
CGuard guard(m_mtxCtx);
return modbus_rtu_set_rts((modbus_t *)m_ctx, mode);
}
int CModBus::RtuGetRts()
{
CGuard guard(m_mtxCtx);
return modbus_rtu_get_rts((modbus_t *)m_ctx);
}
int CModBus::RtuSetCustomRts(void (*set_rts) (void* ctxx, int on))
{
CGuard guard(m_mtxCtx);
return modbus_rtu_set_custom_rts((modbus_t *)m_ctx, set_rts);
}
int CModBus::RtuSetRtsDelay(int us)
{
CGuard guard(m_mtxCtx);
return modbus_rtu_set_rts_delay((modbus_t *)m_ctx, us);
}
int CModBus::RtuGetRtsDelay()
{
CGuard guard(m_mtxCtx);
return modbus_rtu_get_rts_delay((modbus_t *)m_ctx);
}
int CModBus::SetSlave(int slave)
{
CGuard guard(m_mtxCtx);
return modbus_set_slave((modbus_t *)m_ctx, slave);
}
int CModBus::GetSlave(void)
{
CGuard guard(m_mtxCtx);
return modbus_get_slave((modbus_t *)m_ctx);
}
int CModBus::SetErrorRecovery(ERROR_RECOVERY_MODE error_recovery)
{
CGuard guard(m_mtxCtx);
return modbus_set_error_recovery((modbus_t *)m_ctx, (modbus_error_recovery_mode)error_recovery);
}
int CModBus::SetSocket(int s)
{
CGuard guard(m_mtxCtx);
return modbus_set_socket((modbus_t *)m_ctx, s);
}
int CModBus::GetSocket(void)
{
CGuard guard(m_mtxCtx);
return modbus_get_socket((modbus_t *)m_ctx);
}
int CModBus::GetResponseTimeout( uint32_t *to_sec, uint32_t *to_usec)
{
CGuard guard(m_mtxCtx);
return modbus_get_response_timeout((modbus_t *)m_ctx, to_sec,to_usec);
}
int CModBus::SetResponseTimeout(uint32_t to_sec, uint32_t to_usec)
{
CGuard guard(m_mtxCtx);
return modbus_set_response_timeout((modbus_t *)m_ctx, to_sec, to_usec);
}
int CModBus::GetByteTimeout(uint32_t *to_sec, uint32_t *to_usec)
{
CGuard guard(m_mtxCtx);
return modbus_get_byte_timeout((modbus_t *)m_ctx, to_sec, to_usec);
}
int CModBus::SetByteTimeout(uint32_t to_sec, uint32_t to_usec)
{
CGuard guard(m_mtxCtx);
return modbus_set_byte_timeout((modbus_t *)m_ctx, to_sec, to_usec);
}
int CModBus::GetIndicationTimeout(uint32_t *to_sec, uint32_t *to_usec)
{
CGuard guard(m_mtxCtx);
return modbus_get_indication_timeout((modbus_t *)m_ctx, to_sec, to_usec);
}
int CModBus::SetIndicationTimeout(uint32_t to_sec, uint32_t to_usec)
{
CGuard guard(m_mtxCtx);
return modbus_set_indication_timeout((modbus_t *)m_ctx, to_sec, to_usec);
}
int CModBus::GetHeaderLength()
{
CGuard guard(m_mtxCtx);
return modbus_get_header_length((modbus_t *)m_ctx);
}
int CModBus::Connect()
{
CGuard guard(m_mtxCtx);
return modbus_connect((modbus_t *)m_ctx);
}
void CModBus::Close()
{
CGuard guard(m_mtxCtx);
return modbus_close((modbus_t *)m_ctx);
}
void CModBus::Free()
{
CGuard guard(m_mtxCtx);
return modbus_free((modbus_t *)m_ctx);
}
int CModBus::Flush()
{
CGuard guard(m_mtxCtx);
return modbus_flush((modbus_t *)m_ctx);
}
int CModBus::SetDebug(int flag)
{
CGuard guard(m_mtxCtx);
return modbus_set_debug((modbus_t *)m_ctx, flag);
}
const char* CModBus::Strerror(int errnum)
{
return modbus_strerror(errnum);
}
int CModBus::ReadBits(int addr, int nb, uint8_t *dest)
{
CGuard guard(m_mtxCtx);
return modbus_read_bits((modbus_t *)m_ctx, addr, nb, dest);
}
int CModBus::ReadInputBits(int addr, int nb, uint8_t *dest)
{
CGuard guard(m_mtxCtx);
return modbus_read_input_bits((modbus_t *)m_ctx, addr, nb, dest);
}
int CModBus::ReadRegisters(int addr, int nb, uint16_t *dest)
{
CGuard guard(m_mtxCtx);
return modbus_read_registers((modbus_t *)m_ctx, addr, nb, dest);
}
int CModBus::ReadInputRegisters(int addr, int nb, uint16_t *dest)
{
CGuard guard(m_mtxCtx);
return modbus_read_input_registers((modbus_t *)m_ctx, addr, nb, dest);
}
int CModBus::WriteBit(int coil_addr, int status)
{
CGuard guard(m_mtxCtx);
return modbus_write_bit((modbus_t *)m_ctx, coil_addr, status);
}
int CModBus::WriteRegister(int reg_addr, int value)
{
CGuard guard(m_mtxCtx);
return modbus_write_register((modbus_t *)m_ctx, reg_addr, value);
}
int CModBus::WriteBits(int addr, int nb, const uint8_t *data)
{
CGuard guard(m_mtxCtx);
return modbus_write_bits((modbus_t *)m_ctx, addr, nb, data);
}
int CModBus::WriteRegisters(int addr, int nb, const uint16_t *data)
{
CGuard guard(m_mtxCtx);
return modbus_write_registers((modbus_t *)m_ctx, addr, nb, data);
}
int CModBus::MaskWriteRegister(int addr, uint16_t and_mask, uint16_t or_mask)
{
CGuard guard(m_mtxCtx);
return modbus_mask_write_register((modbus_t *)m_ctx, addr, and_mask, or_mask);
}
int CModBus::WriteAndReadRegisters(int write_addr, int write_nb,const uint16_t *src, int read_addr, int read_nb, uint16_t *dest)
{
CGuard guard(m_mtxCtx);
return modbus_write_and_read_registers((modbus_t *)m_ctx, write_addr, write_nb, src, read_addr, read_nb, dest);
}
int CModBus::ReportSlaveId(int max_dest, uint8_t *dest)
{
CGuard guard(m_mtxCtx);
return modbus_report_slave_id((modbus_t *)m_ctx, max_dest, dest);
}
CModBus::ST_MAPPING_INFO* CModBus::MappingNewStartAddress(unsigned int start_bits, unsigned int nb_bits,\
unsigned int start_input_bits, unsigned int nb_input_bits,\
unsigned int start_registers, unsigned int nb_registers,\
unsigned int start_input_registers, unsigned int nb_input_registers)
{
return (ST_MAPPING_INFO*)modbus_mapping_new_start_address(start_bits, nb_bits, start_input_bits, nb_input_bits,\
start_registers, nb_registers, start_input_registers, nb_input_registers);
}
CModBus::ST_MAPPING_INFO* CModBus::MappingNew(int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers)
{
return (ST_MAPPING_INFO*)modbus_mapping_new(nb_bits, nb_input_bits, nb_registers, nb_input_registers);
}
void CModBus::MappingFree(ST_MAPPING_INFO *mb_mapping)
{
return modbus_mapping_free((modbus_mapping_t*)mb_mapping);
}
int CModBus::SendRawRequest(uint8_t *raw_req, int raw_req_length)
{
CGuard guard(m_mtxCtx);
return modbus_send_raw_request((modbus_t *)m_ctx, raw_req, raw_req_length);
}
int CModBus::Receive(uint8_t *req)
{
CGuard guard(m_mtxCtx);
return modbus_receive((modbus_t *)m_ctx, req);
}
int CModBus::ReceiveConfirmation(uint8_t *rsp)
{
CGuard guard(m_mtxCtx);
return modbus_receive_confirmation((modbus_t *)m_ctx, rsp);
}
int CModBus::Reply(const uint8_t *req, int req_length, ST_MAPPING_INFO *mb_mapping)
{
CGuard guard(m_mtxCtx);
return modbus_reply((modbus_t *)m_ctx, req, req_length, (modbus_mapping_t*)mb_mapping);
}
int CModBus::ReplyException(const uint8_t *req, unsigned int exception_code)
{
CGuard guard(m_mtxCtx);
return modbus_reply_exception((modbus_t *)m_ctx, req, exception_code);
}
void CModBus::SetBitsFromByte(uint8_t *dest, int idx, const uint8_t value)
{
return modbus_set_bits_from_byte(dest, idx, value);
}
void CModBus::SetBitsFromBytes(uint8_t *dest, int idx, unsigned int nb_bits, const uint8_t *tab_byte)
{
return modbus_set_bits_from_bytes(dest, idx, nb_bits, tab_byte);
}
uint8_t CModBus::GetByteFromBits(const uint8_t *src, int idx, unsigned int nb_bits)
{
return modbus_get_byte_from_bits(src, idx, nb_bits);
}
float CModBus::GetFloat(const uint16_t *src)
{
return modbus_get_float(src);
}
float CModBus::GetFloatAbcd(const uint16_t *src)
{
return modbus_get_float_abcd(src);
}
float CModBus::GetFloatDcba(const uint16_t *src)
{
return modbus_get_float_dcba(src);
}
float CModBus::GetFloatBadc(const uint16_t *src)
{
return modbus_get_float_badc(src);
}
float CModBus::GetFloatCdab(const uint16_t *src)
{
return modbus_get_float_cdab(src);
}
void CModBus::SetFloat(float f, uint16_t *dest)
{
return modbus_set_float(f, dest);
}
void CModBus::SetFloatAbcd(float f, uint16_t *dest)
{
return modbus_set_float_abcd(f, dest);
}
void CModBus::SetFloatDcba(float f, uint16_t *dest)
{
return modbus_set_float_dcba(f, dest);
}
void CModBus::SetFloatBadc(float f, uint16_t *dest)
{
return modbus_set_float_badc(f, dest);
}
void CModBus::modbSetFloatCdab(float f, uint16_t *dest)
{
return modbus_set_float_cdab(f, dest);
}