222 lines
6.1 KiB
C++
222 lines
6.1 KiB
C++
#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, ®isterValue);
|
||
|
||
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");
|
||
}
|