使用libmodbus库开发modbusTcp从站(支持多个主站连接)

#include "RDSModbusSlave.h"
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      modbus initialization
 * @param      IP/PORT/debugflag
 * @version    v1
 * @return     null
 * @date       2021/10/6
 **************************************************************/
bool RDSModbusSlave::initModbus(std::string Host_Ip = "127.0.0.1", int port = 502, bool debugging = true)
{
    ctx = modbus_new_tcp(Host_Ip.c_str(), port);
    modbus_set_debug(ctx, debugging);
    if (ctx == NULL)
    {
        fprintf(stderr, "There was an error allocating the modbus\n");
        throw - 1;
    }
    m_modbusSocket = modbus_tcp_listen(ctx, 1);
    /*设置线圈, 离散输入, 输入寄存器, 保持寄存器个数(数组元素个数))*/
    mapping = modbus_mapping_new(m_numBits, m_numInputBits, m_numInputRegisters, m_numRegisters);
    if (mapping == NULL)
    {
        fprintf(stderr, "Unable to assign mapping:%s\n", modbus_strerror(errno));
        modbus_free(ctx);
        m_initialized = false;
        return false;
    }
    m_initialized = true;
    return true;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      Constructor
 * @version    v1
 * @return     null
 * @date       2021/10/6
 **************************************************************/
RDSModbusSlave::RDSModbusSlave()
{
    initModbus("127.0.0.1", 502, false);
    //TODO:
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      Destructor
 * @version    v1
 * @return     null
 * @date       2021/10/6
 **************************************************************/
RDSModbusSlave::~RDSModbusSlave()
{
    modbus_mapping_free(mapping);
    modbus_close(ctx);
    modbus_free(ctx);
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      loadFromConfigFile
 * @version    v1
 * @return     null
 * @date       2021/10/18
 **************************************************************/
void RDSModbusSlave::loadFromConfigFile()
{
    return;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      run
 * @version    v1
 * @return     null
 * @date       2021/10/18
 **************************************************************/
void RDSModbusSlave::run()
{
    std::thread loop([this]()
    {
        while (true)
        {
            if (m_initialized)
            {
                recieveMessages();
            }
            else
            {
                m_initialized = true;
            }
        }
    });
    loop.detach();
    return;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      modbus_set_slave_id
 * @param      id
 * @version    v1
 * @return     null
 * @date       2021/10/19
 **************************************************************/
bool RDSModbusSlave::modbus_set_slave_id(int id)
{
    int rc = modbus_set_slave(ctx, id);
    if (rc == -1)
    {
        fprintf(stderr, "Invalid slave id\n");
        modbus_free(ctx);
        return false;
    }
    return true;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      setRegisterValue(设置保存寄存器的值,类型为uint16_t)
 * @param      registerStartaddress(保存寄存器的起始地址)
 * @param      Value(写入到保存寄存器里的值)
 * @version    v1
 * @return     null
 * @date       2021/10/6
 **************************************************************/
bool RDSModbusSlave::setRegisterValue(int registerStartaddress, uint16_t Value)
{
    if (registerStartaddress > (m_numRegisters - 1))
    {
        return false;
    }
    slavemutex.lock();
    mapping->tab_registers[registerStartaddress] = Value;
    slavemutex.unlock();
    return true;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      getRegisterValue(获取保存寄存器的值)
 * @param      registerStartaddress(保存寄存器的起始地址)
 * @version    v1
 * @return     null
 * @date       2021/10/6
 **************************************************************/
uint16_t RDSModbusSlave::getRegisterValue(int registerStartaddress)
{
    if (!m_initialized)
    {
        return -1;
    }
    return mapping->tab_registers[registerStartaddress];
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      setTab_Input_Bits(设置输入寄存器某一位的值)
 * @param      NumBit(输入寄存器的起始地址)
 * @param      Value(输入寄存器的值)
 * @version    v1
 * @return     null
 * @date       2021/10/8
 **************************************************************/
bool RDSModbusSlave::setTab_Input_Bits(int NumBit, uint8_t Value)
{
    if (NumBit > (m_numInputBits - 1))
    {
        return false;
    }
    slavemutex.lock();
    mapping->tab_input_bits[NumBit] = Value;
    slavemutex.unlock();
    return true;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      getTab_Input_Bits(获取输入寄存器某一位的值)
 * @param      NumBit(输入寄存器相应的bit位)
 * @version    v1
 * @return     null
 * @date       2021/10/8
 **************************************************************/
uint8_t RDSModbusSlave::getTab_Input_Bits(int NumBit)
{
    if (!m_initialized)
    {
        return -1;
    }
    return mapping->tab_input_bits[NumBit];
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      setRegisterFloatValue(设置浮点值)
 * @param      (Value:浮点值,registerStartaddress寄存器起始地址)
 * @version    v1
 * @return     null
 * @date       2021/10/8
 **************************************************************/
bool RDSModbusSlave::setRegisterFloatValue(float Value, int registerStartaddress)
{
    if (registerStartaddress > (m_numRegisters - 2))
    {
        return false;
    }
    /*小端模式*/
    slavemutex.lock();
    modbus_set_float_badc(Value, &mapping->tab_registers[registerStartaddress]);
    slavemutex.unlock();
    return true;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      获取寄存器里的浮点数 
 * @param      registerStartaddress寄存器起始地址
 * @version    v1
 * @return     两个uint16_t拼接而成的浮点值
 * @date       2021/10/6
 **************************************************************/
float RDSModbusSlave::getRegisterFloatValue(int registerStartaddress)
{
    if (!m_initialized)
    {
        return -1.0f;
    }
    return modbus_get_float_badc(&mapping->tab_registers[registerStartaddress]);
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      支持多个master同时连接
 * @version    v1
 * @return     null
 * @date       2021/10/6
 **************************************************************/
void RDSModbusSlave::recieveMessages()
{
    uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
    int fd_num = 0, fd_max = 0, ret = 0, i = 0, clnt_sock = -1;
    fd_set reads, cpy_reads;
    FD_ZERO(&reads);
    FD_SET(m_modbusSocket, &reads);
    fd_max = m_modbusSocket;
    while (true)
    {
        cpy_reads = reads;
        if ((fd_num = select(fd_max + 1, &cpy_reads, 0, 0, 0)) == -1)
            break;
        if (fd_num == 0)
            continue;
        for (i = 0; i < fd_max + 1; i++)
        {
            if (FD_ISSET(i, &cpy_reads))
            {
                if (i == m_modbusSocket)
                {
                    clnt_sock = modbus_tcp_accept(ctx, &m_modbusSocket);
                    if ((m_modbusSocket == -1) || (clnt_sock == -1))
                    {
                        std::cerr << modbus_strerror(errno) << std::endl;
                        continue;
                    }
                    FD_SET(clnt_sock, &reads);
                    if (fd_max < clnt_sock)
                        fd_max = clnt_sock;
                }
                else
                {
                    ret = modbus_receive(ctx, query);
                    if (ret == 0)
                    {
                        m_errCount = 0;
                        continue;
                    }
                    else if (ret > 0)
                    {
                        m_errCount = 0;
                        modbus_reply(ctx, query, sizeof(query), mapping);
                    }
                    else
                    {
                        modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_NONE);
                        modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_LINK);
                        modbus_close(ctx);
                        FD_CLR(i, &reads);
#ifdef _WIN32
                        closesocket(i);
#else
                        close(i);
#endif // _WIN32

                        m_errCount++;
                    }
                    if(m_errCount > 5)
                    {
                        m_initialized = false;
                        break;
                    }
                }
            }
        }
    }
    m_initialized = false;
}
#ifndef RDSMODBUSSLAVE_H
#define RDSMODBUSSLAVE_H
#include <iostream>
#include <thread>
#include <stdlib.h>
#include <iostream>
#include <mutex>
#include <string>
using namespace std;
/*如果是windows平台则要加载相应的静态库和头文件*/
#ifdef _WIN32
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <windows.h>
#include <modbus.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "modbus.lib")
/*linux平台*/
#else
#include <modbus/modbus.h>
#include <unistd.h>
#include <error.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#endif
class RDSModbusSlave
{
public:
    RDSModbusSlave();
    ~RDSModbusSlave();

public:
    void recieveMessages();
    bool modbus_set_slave_id(int id);
    bool initModbus(std::string Host_Ip, int port, bool debugging);
    uint8_t getTab_Input_Bits(int NumBit);
    bool setTab_Input_Bits(int NumBit, uint8_t Value);
    uint16_t getRegisterValue(int registerNumber);
    bool setRegisterValue(int registerNumber, uint16_t Value);
    bool setRegisterFloatValue(float Value, int registerStartaddress);
    float getRegisterFloatValue(int registerStartaddress);

private:
    std::mutex slavemutex;
    int m_errCount{ 0 };
    int m_modbusSocket{ -1 };
    bool m_initialized{ false };
    modbus_t* ctx{ nullptr };
    modbus_mapping_t* mapping{ nullptr };
    /*Mapping*/
    int m_numBits{ 500 };
    int m_numInputBits{ 500 };
    int m_numRegisters{ 500 };
    int m_numInputRegisters{ 500 };

public:
    void loadFromConfigFile();
    void run();
};
/*annotation:
(1)https://www.jianshu.com/p/0ed380fa39eb
(2)typedef struct _modbus_mapping_t
{
    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;
}modbus_mapping_t;*/
#endif // RDSMODBUSSLAVE_H

#include <iostream>
#include "RDSModbusSlave.h"
using namespace std;
void modbusRunner(RDSModbusSlave* server)
{
    server->recieveMessages();
}
RDSModbusSlave modSer;
int main()
{
    std::thread modSerThread(modbusRunner, &modSer);
    modSerThread.join();
    std::cout << "Running ModbusTcpSlave" << std::endl;
    return 0;
}
  • 9
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值