2025-10-24 23:19:44 +08:00

218 lines
6.0 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 "VrLog.h"
#include <cstring>
#include <QDateTime>
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 0; // 已初始化,直接返回成功
}
// 保存配置参数
m_device = device;
m_baud = baud;
m_parity = parity;
m_dataBit = dataBit;
m_stopBit = stopBit;
// 创建Modbus RTU上下文
m_pModbusCtx = modbus_new_rtu(device.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 -1;
}
// 设置从机地址通常为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 -2;
}
// 创建读取定时器
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 0;
}
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(1000);
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 registers[2] = {0}; // float需要2个寄存器
int rc = modbus_read_registers(m_pModbusCtx, TEMPERATURE_ADDR, TEMPERATURE_QUANTITY, registers);
if (rc == -1) {
LOG_ERROR("Failed to read registers 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;
}
// 将寄存器数据转换为float温度值
// Modbus使用大端序存储float需要转换
uint32_t tempValue = ((uint32_t)registers[0] << 16) | registers[1];
memcpy(&temperature, &tempValue, sizeof(float));
return 0;
}
void ModbusRTUMaster::ConvertTemperatureToRegisters(float temperature, uint16_t registers[2])
{
// 将float温度值转换为Modbus寄存器格式大端序
uint32_t tempValue = 0;
memcpy(&tempValue, &temperature, sizeof(float));
// 高16位寄存器
registers[0] = (tempValue >> 16) & 0xFFFF;
// 低16位寄存器
registers[1] = tempValue & 0xFFFF;
}
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");
}