222 lines
6.1 KiB
C++
Raw Permalink Normal View History

2025-10-24 23:19:44 +08:00
#include "ModbusRTUMaster.h"
#include <cstring>
#include <QDateTime>
2025-11-26 22:44:38 +08:00
#include "VrLog.h"
#include "VrError.h"
2025-10-24 23:19:44 +08:00
ModbusRTUMaster::ModbusRTUMaster(QObject *parent)
: QObject(parent)
, m_pModbusCtx(nullptr)
, m_baud(115200)
, m_parity('N')
, m_dataBit(8)
, m_stopBit(1)
, m_bInitialized(false)
, m_bRunning(false)
, m_pReadTimer(nullptr)
, m_temperatureCallback(nullptr)
{
LOG_DEBUG("ModbusRTUMaster constructor called\n");
}
ModbusRTUMaster::~ModbusRTUMaster()
{
LOG_DEBUG("ModbusRTUMaster destructor called\n");
Deinitialize();
}
int ModbusRTUMaster::Initialize(const QString& device, int baud, char parity, int dataBit, int stopBit)
{
LOG_DEBUG("Initializing ModbusRTUMaster with device: %s, baud: %d, parity: %c, dataBit: %d, stopBit: %d\n",
device.toStdString().c_str(), baud, parity, dataBit, stopBit);
2025-11-26 22:44:38 +08:00
2025-10-24 23:19:44 +08:00
// 检查是否已初始化
if (m_bInitialized) {
LOG_WARNING("ModbusRTUMaster is already initialized\n");
2025-11-26 22:44:38 +08:00
return SUCCESS; // 已初始化,直接返回成功
2025-10-24 23:19:44 +08:00
}
2025-11-26 22:44:38 +08:00
2025-10-24 23:19:44 +08:00
// 保存配置参数
m_device = device;
m_baud = baud;
m_parity = parity;
m_dataBit = dataBit;
m_stopBit = stopBit;
2025-11-26 22:44:38 +08:00
// 处理 Windows 上 COM10 及以上端口的特殊命名
QString devicePath = device;
#ifdef _WIN32
// 检查是否是 COM 端口
if (device.startsWith("COM", Qt::CaseInsensitive)) {
// 提取端口号
bool ok;
int portNum = device.mid(3).toInt(&ok);
if (ok && portNum >= 10) {
// COM10 及以上需要使用 \\\\.\\COMX 格式
devicePath = QString("\\\\.\\COM%1").arg(portNum);
LOG_INFO("Windows COM port >= 10 detected, using device path: %s\n",
devicePath.toStdString().c_str());
}
}
#endif
2025-10-24 23:19:44 +08:00
// 创建Modbus RTU上下文
2025-11-26 22:44:38 +08:00
m_pModbusCtx = modbus_new_rtu(devicePath.toStdString().c_str(), baud, parity, dataBit, stopBit);
2025-10-24 23:19:44 +08:00
if (m_pModbusCtx == nullptr) {
LOG_ERROR("Failed to create modbus RTU context for device: %s\n", device.toStdString().c_str());
2025-11-26 22:44:38 +08:00
return ERR_CODE(DEV_NO_OPEN);
2025-10-24 23:19:44 +08:00
}
// 设置从机地址通常为1
modbus_set_slave(m_pModbusCtx, 1);
// 设置响应超时500ms
modbus_set_response_timeout(m_pModbusCtx, 0, 500000);
// 连接设备
if (modbus_connect(m_pModbusCtx) == -1) {
LOG_ERROR("Failed to connect to modbus device: %s, error: %s\n",
device.toStdString().c_str(), modbus_strerror(errno));
modbus_free(m_pModbusCtx);
m_pModbusCtx = nullptr;
2025-11-26 22:44:38 +08:00
return ERR_CODE(DEV_OPEN_ERR);
2025-10-24 23:19:44 +08:00
}
// 创建读取定时器
m_pReadTimer = new QTimer(this);
connect(m_pReadTimer, &QTimer::timeout, this, &ModbusRTUMaster::OnReadTimer);
m_bInitialized = true;
LOG_INFO("ModbusRTUMaster initialized successfully with device: %s\n", device.toStdString().c_str());
2025-11-26 22:44:38 +08:00
return SUCCESS;
2025-10-24 23:19:44 +08:00
}
void ModbusRTUMaster::Deinitialize()
{
LOG_DEBUG("Deinitializing ModbusRTUMaster\n");
// 停止读取
StopReading();
// 断开连接并释放资源
if (m_pModbusCtx) {
modbus_close(m_pModbusCtx);
modbus_free(m_pModbusCtx);
m_pModbusCtx = nullptr;
}
// 删除定时器
if (m_pReadTimer) {
delete m_pReadTimer;
m_pReadTimer = nullptr;
}
m_bInitialized = false;
LOG_INFO("ModbusRTUMaster deinitialized successfully\n");
}
int ModbusRTUMaster::StartReading()
{
LOG_DEBUG("Starting ModbusRTUMaster reading\n");
// 检查是否已初始化
if (!m_bInitialized) {
LOG_ERROR("ModbusRTUMaster not initialized\n");
return -1;
}
// 检查是否已在运行
if (m_bRunning) {
LOG_WARNING("ModbusRTUMaster is already running\n");
return 0; // 已运行,直接返回成功
}
// 启动定时器每1000ms读取一次
if (m_pReadTimer) {
2025-11-26 22:44:38 +08:00
m_pReadTimer->start(5000);
2025-10-24 23:19:44 +08:00
m_bRunning = true;
LOG_INFO("ModbusRTUMaster reading started\n");
return 0;
} else {
LOG_ERROR("Read timer not initialized\n");
return -2;
}
}
void ModbusRTUMaster::StopReading()
{
LOG_DEBUG("Stopping ModbusRTUMaster reading\n");
// 停止定时器
if (m_pReadTimer && m_pReadTimer->isActive()) {
m_pReadTimer->stop();
}
m_bRunning = false;
LOG_INFO("ModbusRTUMaster reading stopped\n");
}
bool ModbusRTUMaster::IsRunning() const
{
return m_bRunning;
}
void ModbusRTUMaster::OnReadTimer()
{
// 读取温度数据
float temperature = 0.0f;
int result = ReadTemperature(temperature);
if (result == 0) {
LOG_DEBUG("Temperature read successfully: %.2f°C\n", temperature);
// 调用温度回调函数(如果已设置)
std::lock_guard<std::mutex> lock(m_mutex);
if (m_temperatureCallback) {
m_temperatureCallback(temperature);
}
} else {
LOG_ERROR("Failed to read temperature, error code: %d\n", result);
}
}
int ModbusRTUMaster::ReadTemperature(float& temperature)
{
// 检查Modbus上下文
if (!m_pModbusCtx) {
LOG_ERROR("Modbus context not initialized\n");
return -1;
}
2025-11-26 22:44:38 +08:00
// 读取保持寄存器(单个寄存器)
uint16_t registerValue = 0;
int rc = modbus_read_registers(m_pModbusCtx, TEMPERATURE_ADDR, TEMPERATURE_QUANTITY, &registerValue);
2025-10-24 23:19:44 +08:00
if (rc == -1) {
2025-11-26 22:44:38 +08:00
LOG_ERROR("Failed to read register from address 0x%02X, error: %s\n",
2025-10-24 23:19:44 +08:00
TEMPERATURE_ADDR, modbus_strerror(errno));
return -2;
}
2025-11-26 22:44:38 +08:00
2025-10-24 23:19:44 +08:00
// 检查读取的寄存器数量是否正确
if (rc != TEMPERATURE_QUANTITY) {
2025-11-26 22:44:38 +08:00
LOG_ERROR("Incorrect number of registers read. Expected: %d, Actual: %d\n", TEMPERATURE_QUANTITY, rc);
2025-10-24 23:19:44 +08:00
return -3;
}
2025-11-26 22:44:38 +08:00
// 将寄存器值除以10得到实际温度值
temperature = registerValue / 10.0f;
return 0;
2025-10-24 23:19:44 +08:00
}
void ModbusRTUMaster::SetTemperatureCallback(const std::function<void(float)>& callback)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_temperatureCallback = callback;
LOG_DEBUG("Temperature callback set for ModbusRTUMaster\n");
2025-11-26 22:44:38 +08:00
}