222 lines
6.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ModbusRTUMaster.h"
#include <cstring>
#include <QDateTime>
#include "VrLog.h"
#include "VrError.h"
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);
// 检查是否已初始化
if (m_bInitialized) {
LOG_WARNING("ModbusRTUMaster is already initialized\n");
return SUCCESS; // 已初始化,直接返回成功
}
// 保存配置参数
m_device = device;
m_baud = baud;
m_parity = parity;
m_dataBit = dataBit;
m_stopBit = stopBit;
// 处理 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
// 创建Modbus RTU上下文
m_pModbusCtx = modbus_new_rtu(devicePath.toStdString().c_str(), baud, parity, dataBit, stopBit);
if (m_pModbusCtx == nullptr) {
LOG_ERROR("Failed to create modbus RTU context for device: %s\n", device.toStdString().c_str());
return ERR_CODE(DEV_NO_OPEN);
}
// 设置从机地址通常为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;
return ERR_CODE(DEV_OPEN_ERR);
}
// 创建读取定时器
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());
return SUCCESS;
}
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) {
m_pReadTimer->start(5000);
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;
}
// 读取保持寄存器(单个寄存器)
uint16_t registerValue = 0;
int rc = modbus_read_registers(m_pModbusCtx, TEMPERATURE_ADDR, TEMPERATURE_QUANTITY, &registerValue);
if (rc == -1) {
LOG_ERROR("Failed to read register from address 0x%02X, error: %s\n",
TEMPERATURE_ADDR, modbus_strerror(errno));
return -2;
}
// 检查读取的寄存器数量是否正确
if (rc != TEMPERATURE_QUANTITY) {
LOG_ERROR("Incorrect number of registers read. Expected: %d, Actual: %d\n", TEMPERATURE_QUANTITY, rc);
return -3;
}
// 将寄存器值除以10得到实际温度值
temperature = registerValue / 10.0f;
return 0;
}
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");
}