修复modbus主机 总线竞争问题

This commit is contained in:
GuanYuankai 2025-10-16 09:42:59 +00:00
parent 5ea24af1a0
commit 444ad2fd53
10 changed files with 358 additions and 255 deletions

View File

@ -73,6 +73,8 @@
"variant": "cpp",
"forward_list": "cpp",
"ranges": "cpp",
"valarray": "cpp"
"valarray": "cpp",
"charconv": "cpp",
"unordered_set": "cpp"
}
}

View File

@ -49,7 +49,7 @@ add_library(edge_proxy_lib STATIC
#modbus
src/modbus/modbus_rtu_client.cc
src/modbus/modbus_rtu_poller_service.cc
src/modbus/modbus_rtu_bus_service.cc
src/modbus/generic_modbus_parser.cc
# --- Modbus Master ---
src/protocol/modbus/modbus_protocol.cc

View File

@ -50,5 +50,10 @@
{"name": "valve_status","address": 104, "type": "UINT16", "scale": 1.0}
]
}
]
],
"modbus_rtu_bus_configs": {
"/dev/ttyS7": {
"inter_device_delay_ms": 150
}
}
}

View File

@ -8,7 +8,7 @@
using json = nlohmann::json;
// 辅助函数将JSON中的字符串类型映射到C++枚举
static ModbusDataType string_to_modbus_data_type(const std::string& type_str) {
static const std::map<std::string, ModbusDataType> type_map = {
{"UINT16", ModbusDataType::UINT16},
@ -44,8 +44,10 @@ void DeviceManager::load_and_start(const std::string& config_path) {
try {
json config_json = json::parse(config_file);
// --- 加载 Modbus RTU 设备 ---
// --- MODIFIED: 加载 Modbus RTU 设备的逻辑 ---
if (config_json.contains("modbus_rtu_devices")) {
// 1. 先将所有启用的设备按 port_path (总线) 分组
std::map<std::string, std::vector<ModbusRtuDeviceConfig>> rtu_device_groups;
for (const auto& dev_json : config_json["modbus_rtu_devices"]) {
if (!dev_json.value("enabled", false)) continue;
@ -61,18 +63,27 @@ void DeviceManager::load_and_start(const std::string& config_path) {
dp_json.at("name").get<std::string>(),
(uint16_t)dp_json.at("address").get<int>(),
string_to_modbus_data_type(dp_json.at("type").get<std::string>()),
dp_json.value("scale", 1.0) // .value for optional fields
dp_json.value("scale", 1.0)
});
}
auto service = std::make_unique<ModbusRtuPollerService>(config, m_report_callback);
// 将解析后的配置加入对应的分组
rtu_device_groups[config.port_path].push_back(config);
}
// 2. 为每个分组 (即每个物理串口) 创建一个 BusService
for (const auto& pair : rtu_device_groups) {
const std::string& port_path = pair.first;
const std::vector<ModbusRtuDeviceConfig>& devices_on_bus = pair.second;
auto service = std::make_unique<ModbusRtuBusService>(port_path, devices_on_bus, m_report_callback);
service->start();
m_rtu_services.push_back(std::move(service));
spdlog::info("Started Modbus RTU service for device '{}'.", config.device_id);
m_rtu_bus_services.push_back(std::move(service));
spdlog::info("Started Modbus RTU Bus service for port '{}' with {} device(s).", port_path, devices_on_bus.size());
}
}
// --- 加载 Modbus TCP 设备 ---
// --- 加载 Modbus TCP 设备 (逻辑保持不变) ---
if (config_json.contains("modbus_tcp_devices")) {
for (const auto& dev_json : config_json["modbus_tcp_devices"]) {
if (!dev_json.value("enabled", false)) continue;
@ -84,7 +95,6 @@ void DeviceManager::load_and_start(const std::string& config_path) {
config.slave_id = dev_json.at("slave_id").get<uint8_t>();
config.poll_interval_ms = dev_json.at("poll_interval_ms").get<int>();
// 解析 data_points
for (const auto& dp_json : dev_json.at("data_points")) {
config.data_points.push_back({
dp_json.at("name").get<std::string>(),
@ -111,11 +121,13 @@ void DeviceManager::stop_all() {
std::lock_guard<std::mutex> lock(m_mutex);
spdlog::info("Stopping all device services...");
for (auto& service : m_rtu_services) {
// 停止所有 RTU 总线服务
for (auto& service : m_rtu_bus_services) {
service->stop();
}
m_rtu_services.clear();
m_rtu_bus_services.clear();
// 停止所有 TCP 轮询服务
for (auto& poller : m_tcp_pollers) {
poller->stop();
}
@ -124,43 +136,38 @@ void DeviceManager::stop_all() {
spdlog::info("All device services stopped.");
}
std::vector<DeviceInfo> DeviceManager::get_all_device_info() const {
// 使用 lock_guard 确保在函数返回前互斥锁能被自动释放
std::lock_guard<std::mutex> lock(m_mutex);
std::vector<DeviceInfo> all_devices;
all_devices.reserve(m_rtu_services.size() + m_tcp_pollers.size());
all_devices.reserve(m_tcp_pollers.size()); // 初始容量可以先按TCP设备数算
// 遍历 RTU 设备
for (const auto& service : m_rtu_services) {
// !! 前提: ModbusRtuPollerService 必须有 get_config() 方法
const auto& config = service->get_config();
DeviceInfo info;
info.id = config.device_id;
info.type = "ModbusRTU";
info.is_running = service->is_running(); // 假设 service 有 is_running() 方法
info.connection_details["Port Path"] = config.port_path;
info.connection_details["Baud Rate"] = std::to_string(config.baud_rate);
info.connection_details["Slave ID"] = std::to_string(config.slave_id);
all_devices.push_back(info);
// 遍历所有 RTU 总线服务
for (const auto& service : m_rtu_bus_services) {
const auto& configs_on_bus = service->get_all_device_configs();
for (const auto& config : configs_on_bus) {
DeviceInfo info;
info.id = config.device_id;
info.type = "ModbusRTU";
info.is_running = service->is_running();
info.connection_details["Port Path"] = config.port_path;
info.connection_details["Baud Rate"] = std::to_string(config.baud_rate);
info.connection_details["Slave ID"] = std::to_string(config.slave_id);
all_devices.push_back(info);
}
}
// 遍历 TCP 设备
// 遍历 TCP 设备 (逻辑不变)
for (const auto& poller : m_tcp_pollers) {
// !! 前提: ModbusMasterPoller 必须有 get_config() 方法
const auto& config = poller->get_config();
DeviceInfo info;
info.id = config.device_id;
info.type = "ModbusTCP";
info.is_running = poller->is_running(); // 假设 poller 有 is_running() 方法
info.is_running = poller->is_running();
info.connection_details["IP Address"] = config.ip_address;
info.connection_details["Port"] = std::to_string(config.port);
info.connection_details["Slave ID"] = std::to_string(config.slave_id);
all_devices.push_back(info);
}
@ -179,15 +186,15 @@ bool DeviceManager::send_control_command(const std::string& device_id, uint16_t
}
}
// 然后,在 RTU service 列表中查找
for (const auto& service : m_rtu_services) {
if (service->get_config().device_id == device_id) {
spdlog::info("Found RTU device '{}'. Dispatching write command to address {}.", device_id, address);
service->write_single_register(address, value);
// 然后,在 RTU bus service 列表中查找哪个服务管理着该设备
for (const auto& service : m_rtu_bus_services) {
if (service->manages_device(device_id)) {
spdlog::info("Found RTU device '{}' on a bus. Dispatching write command.", device_id);
service->write_single_register(device_id, address, value);
return true;
}
}
spdlog::warn("send_control_command failed: Device with ID '{}' not found.", device_id);
spdlog::warn("send_control_command failed: Device with ID '{}' not found in any service.", device_id);
return false;
}

View File

@ -3,7 +3,7 @@
#define DEVICE_MANAGER_H
#include "protocol/iprotocol_adapter.h"
#include "modbus/modbus_rtu_poller_service.h"
#include "modbus/modbus_rtu_bus_service.h"
#include "modbus/modbus_master_poller.h"
#include <boost/asio.hpp>
#include <vector>
@ -69,11 +69,9 @@ private:
ReportDataCallback m_report_callback;
// 用于存储正在运行的服务实例,以管理其生命周期
std::vector<std::unique_ptr<ModbusRtuPollerService>> m_rtu_services;
std::vector<std::unique_ptr<ModbusRtuBusService>> m_rtu_bus_services;
std::vector<std::shared_ptr<ModbusMasterPoller>> m_tcp_pollers;
// --- <<< 新增成员 >>> ---
// mutable 关键字允许在 const 成员函数中修改它 (例如在 get_all_device_info 中加锁)
mutable std::mutex m_mutex;
};

View File

@ -0,0 +1,150 @@
// 文件名: src/modbus/modbus_rtu_bus_service.cc (注意文件名已更改)
#include "modbus_rtu_bus_service.h"
#include "generic_modbus_parser.h"
#include "spdlog/spdlog.h"
#include <chrono>
#include <algorithm>
// --- MODIFIED: 构造函数接收一个设备列表 ---
ModbusRtuBusService::ModbusRtuBusService(std::string port_path,
std::vector<ModbusRtuDeviceConfig> devices,
ReportDataCallback report_cb)
: m_port_path(std::move(port_path)),
m_devices(std::move(devices)),
m_report_callback(std::move(report_cb)) {}
ModbusRtuBusService::~ModbusRtuBusService() {
stop();
}
// --- start, stop, is_running 逻辑基本不变 ---
void ModbusRtuBusService::start() {
if (m_thread.joinable()) { return; }
m_stop_flag = false;
m_thread = std::thread(&ModbusRtuBusService::run, this);
spdlog::info("[Modbus RTU Bus] Service for port '{}' started.", m_port_path);
}
void ModbusRtuBusService::stop() {
if (m_stop_flag.exchange(true)) { return; }
if (m_thread.joinable()) {
m_thread.join();
spdlog::info("[Modbus RTU Bus] Service for port '{}' has been stopped.", m_port_path);
}
}
bool ModbusRtuBusService::is_running() const {
return !m_stop_flag && m_thread.joinable();
}
// --- NEW: 新增辅助方法 ---
bool ModbusRtuBusService::manages_device(const std::string& device_id) const {
for (const auto& device_config : m_devices) {
if (device_config.device_id == device_id) {
return true;
}
}
return false;
}
// ---写方法现在需要 device_id 来查找 slave_id ---
void ModbusRtuBusService::write_single_register(const std::string& device_id, uint16_t address, uint16_t value) {
uint8_t slave_id = 0;
bool device_found = false;
// 首先根据 device_id 找到对应的 slave_id
for (const auto& config : m_devices) {
if (config.device_id == device_id) {
slave_id = config.slave_id;
device_found = true;
break;
}
}
if (!device_found) {
spdlog::warn("[Modbus RTU Bus] Write failed: Device '{}' not managed by service on port '{}'.", device_id, m_port_path);
return;
}
// 锁定串口资源,执行写操作
std::lock_guard<std::mutex> lock(m_client_mutex);
try {
spdlog::debug("[Modbus RTU Bus] Port '{}': Writing to device '{}' (Slave ID {})...", m_port_path, device_id, slave_id);
m_client.writeSingleRegister(slave_id, address, value);
spdlog::info("[Modbus RTU Bus] Port '{}': Successfully wrote to device '{}'.", m_port_path, device_id);
} catch (const std::exception& e) {
spdlog::error("[Modbus RTU Bus] Port '{}': Failed to write to device '{}': {}", m_port_path, device_id, e.what());
}
}
const std::vector<ModbusRtuDeviceConfig>& ModbusRtuBusService::get_all_device_configs() const {
return m_devices;
}
// --- 以串行轮询多个设备 ---
void ModbusRtuBusService::run() {
if (m_devices.empty()) {
spdlog::warn("[Modbus RTU Bus] No devices configured for port '{}'. Thread will not run.", m_port_path);
return;
}
// 只需要设置一次串口参数
// 我们假设同一总线上的设备波特率等参数一致,这是 Modbus RTU 的基本要求
if (!m_client.setPortSettings(m_port_path, m_devices[0].baud_rate)) {
spdlog::error("[Modbus RTU Bus] Failed to set up serial port '{}'. Thread exiting.", m_port_path);
return;
}
// 主循环
while (!m_stop_flag) {
// 依次轮询此总线上的每一个设备
for (const auto& config : m_devices) {
if (m_stop_flag) break; // 每次轮询前都检查停止标志
{ // 创建作用域以控制锁
std::lock_guard<std::mutex> lock(m_client_mutex);
try {
// --- 针对当前设备计算轮询范围 ---
if (config.data_points.empty()) continue;
auto [min_it, max_it] = std::minmax_element(config.data_points.begin(), config.data_points.end(),
[](const DataPointConfig& a, const DataPointConfig& b) { return a.address < b.address; });
uint16_t start_address = min_it->address;
uint16_t last_address = max_it->address;
if (max_it->type >= ModbusDataType::UINT32) { last_address += 1; }
uint16_t quantity = last_address - start_address + 1;
std::vector<uint16_t> raw_registers = m_client.readHoldingRegisters(config.slave_id, start_address, quantity);
std::map<uint16_t, uint16_t> registers_map;
for (uint16_t i = 0; i < raw_registers.size(); ++i) {
registers_map[start_address + i] = raw_registers[i];
}
nlohmann::json data_j = GenericModbusParser::parse(registers_map, config.data_points);
UnifiedData report_data;
report_data.device_id = config.device_id;
report_data.timestamp_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
report_data.data_json = data_j.dump();
if (m_report_callback) {
m_report_callback(report_data);
}
} catch (const std::exception& e) {
spdlog::error("[Modbus RTU Bus] Port '{}', Device '{}': Communication error: {}", m_port_path, config.device_id, e.what());
}
} // 锁释放
// 在轮询下一个设备前,短暂延时,给总线和设备响应时间
std::this_thread::sleep_for(std::chrono::milliseconds(150));
}
// 完成一轮所有设备的轮询后,等待一个大的周期
if (!m_stop_flag) {
// 这里的等待时间可以根据需求调整,例如使用第一个设备的 poll_interval_ms
auto wake_up_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(m_devices[0].poll_interval_ms);
while (std::chrono::steady_clock::now() < wake_up_time && !m_stop_flag) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
}
m_client.closePort();
spdlog::info("[RTU Bus Service {}] Run loop finished. Thread exiting.", m_port_path);
}

View File

@ -0,0 +1,65 @@
// 文件名: src/modbus/modbus_rtu_bus_service.h (注意文件名已更改)
#ifndef MODBUS_RTU_BUS_SERVICE_H
#define MODBUS_RTU_BUS_SERVICE_H
#include "protocol/iprotocol_adapter.h"
#include "modbus_rtu_client.h"
#include "modbus_common.h"
#include <thread>
#include <atomic>
#include <string>
#include <vector> // <--- 新增
#include <mutex>
/**
* @brief Modbus RTU 线
* * 线
*/
class ModbusRtuBusService {
public:
/**
* @brief
* @param port_path 线使, e.g., "/dev/ttyS0"
* @param devices 线
* @param report_cb
*/
ModbusRtuBusService(std::string port_path,
std::vector<ModbusRtuDeviceConfig> devices,
ReportDataCallback report_cb);
~ModbusRtuBusService();
ModbusRtuBusService(const ModbusRtuBusService&) = delete;
ModbusRtuBusService& operator=(const ModbusRtuBusService&) = delete;
void start();
void stop();
bool is_running() const;
/**
* @brief 线ID
*/
bool manages_device(const std::string& device_id) const;
const std::vector<ModbusRtuDeviceConfig>& get_all_device_configs() const;
/**
* @brief (线) 线
* @param device_id ID
* @param address
* @param value
*/
void write_single_register(const std::string& device_id, uint16_t address, uint16_t value);
private:
void run();
std::string m_port_path;
std::vector<ModbusRtuDeviceConfig> m_devices;
ReportDataCallback m_report_callback;
ModbusRTUClient m_client;
std::thread m_thread;
std::atomic<bool> m_stop_flag{false};
std::mutex m_client_mutex; // 保护 m_client 的互斥锁
};
#endif // MODBUS_RTU_BUS_SERVICE_H

View File

@ -1,118 +0,0 @@
// 文件名: src/modbus/modbus_rtu_poller_service.cc
#include "modbus_rtu_poller_service.h"
#include "generic_modbus_parser.h" // 使用通用解析器
#include "spdlog/spdlog.h"
#include <chrono>
#include <algorithm> // for std::minmax_element
ModbusRtuPollerService::ModbusRtuPollerService(ModbusRtuDeviceConfig config, ReportDataCallback report_cb)
: m_config(std::move(config)),
m_report_callback(std::move(report_cb)) {}
ModbusRtuPollerService::~ModbusRtuPollerService() {
stop();
}
void ModbusRtuPollerService::start() {
if (m_thread.joinable()) {
spdlog::warn("[Modbus RTU Service] Poller for device '{}' is already running.", m_config.device_id);
return;
}
m_stop_flag = false;
// 启动一个新线程,并将 run() 方法作为入口点
// 'this' 指针被传递,以便新线程可以调用类的成员函数
m_thread = std::thread(&ModbusRtuPollerService::run, this);
spdlog::info("[Modbus RTU Service] Poller for device '{}' started in a background thread.", m_config.device_id);
}
void ModbusRtuPollerService::stop() {
m_stop_flag = true;
if (m_thread.joinable()) {
m_thread.join(); // 等待线程安全退出
spdlog::info("[Modbus RTU Service] Poller for device '{}' has been stopped.", m_config.device_id);
}
}
const ModbusRtuDeviceConfig& ModbusRtuPollerService::get_config() const {
return m_config;
}
bool ModbusRtuPollerService::is_running() const {
return !m_stop_flag && m_thread.joinable();
}
void ModbusRtuPollerService::write_single_register(uint16_t address, uint16_t value) {
std::lock_guard<std::mutex> lock(m_client_mutex);
try {
spdlog::debug("[Modbus RTU] Device '{}': Writing value {} to address {}.", m_config.device_id, value, address);
m_client.writeSingleRegister(m_config.slave_id, address, value);
spdlog::info("[Modbus RTU] Device '{}': Successfully wrote value {} to address {}.", m_config.device_id, value, address);
} catch (const std::exception& e) {
spdlog::error("[Modbus RTU] Device '{}': Failed to write to address {}: {}", m_config.device_id, address, e.what());
}
}
void ModbusRtuPollerService::run() {
if (m_config.data_points.empty()) {
spdlog::warn("[Modbus RTU] Device '{}' has no data points configured. Thread will not run.", m_config.device_id);
return;
}
if (!m_client.setPortSettings(m_config.port_path, m_config.baud_rate)) {
spdlog::error("[Modbus RTU] Failed to set up serial port '{}' for device '{}'. Thread exiting.", m_config.port_path, m_config.device_id);
return;
}
auto [min_it, max_it] = std::minmax_element(m_config.data_points.begin(), m_config.data_points.end(),
[](const DataPointConfig& a, const DataPointConfig& b) {
return a.address < b.address;
});
uint16_t start_address = min_it->address;
uint16_t last_address = max_it->address;
if (max_it->type == ModbusDataType::UINT32 || max_it->type == ModbusDataType::INT32 || max_it->type == ModbusDataType::FLOAT32) {
last_address += 1;
}
uint16_t quantity = last_address - start_address + 1;
spdlog::info("[Modbus RTU] Device '{}' will poll {} registers starting from address {}.", m_config.device_id, quantity, start_address);
while (!m_stop_flag) {
{ // <--- 创建一个新的作用域来控制锁的生命周期
std::lock_guard<std::mutex> lock(m_client_mutex);
try {
std::vector<uint16_t> raw_registers = m_client.readHoldingRegisters(m_config.slave_id, start_address, quantity);
std::map<uint16_t, uint16_t> registers_map;
for (uint16_t i = 0; i < raw_registers.size(); ++i) {
registers_map[start_address + i] = raw_registers[i];
}
nlohmann::json data_j = GenericModbusParser::parse(registers_map, m_config.data_points);
UnifiedData report_data;
report_data.device_id = m_config.device_id;
report_data.timestamp_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
report_data.data_json = data_j.dump();
if (m_report_callback) {
m_report_callback(report_data);
}
} catch (const std::exception& e) {
spdlog::error("[Modbus RTU] Error during communication with device '{}': {}", m_config.device_id, e.what());
}
} // <--- 锁在这里被释放
auto wake_up_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(m_config.poll_interval_ms);
while (std::chrono::steady_clock::now() < wake_up_time) {
if (m_stop_flag) {
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
m_client.closePort();
spdlog::info("[RTU Poller {}] Run loop finished. Thread exiting.", m_config.device_id);
}

View File

@ -1,84 +0,0 @@
// 文件名: src/modbus/modbus_rtu_poller_service.h
#ifndef MODBUS_RTU_POLLER_SERVICE_H
#define MODBUS_RTU_POLLER_SERVICE_H
#include "protocol/iprotocol_adapter.h"
#include "modbus_rtu_client.h"
#include "modbus_common.h" // 包含 ModbusRtuDeviceConfig 和 DataPointConfig 定义
#include <thread>
#include <atomic>
#include <string>
#include <mutex>
/**
* @brief Modbus RTU
* * 线Modbus RTU设备
* IO操作与主程序的异步事件循环隔离开来
* 线
*/
class ModbusRtuPollerService {
public:
/**
* @brief
* @param config
* @param report_cb
*/
ModbusRtuPollerService(ModbusRtuDeviceConfig config, ReportDataCallback report_cb);
/**
* @brief
* * 线
*/
~ModbusRtuPollerService();
// 禁止拷贝和赋值,因为该类管理着一个线程资源
ModbusRtuPollerService(const ModbusRtuPollerService&) = delete;
ModbusRtuPollerService& operator=(const ModbusRtuPollerService&) = delete;
/**
* @brief
* * 线 run()
*/
void start();
/**
* @brief
* * 线退
*/
void stop();
/**
* @brief (const-ref to avoid copy)
*/
const ModbusRtuDeviceConfig& get_config() const;
/**
* @brief
*/
bool is_running() const;
/**
* @brief
* @param address
* @param value
*/
void write_single_register(uint16_t address, uint16_t value);
private:
/**
* @brief 线
* * 线
*
*/
void run();
ModbusRtuDeviceConfig m_config;
ReportDataCallback m_report_callback;
ModbusRTUClient m_client;
std::thread m_thread;
std::atomic<bool> m_stop_flag{false};
std::mutex m_client_mutex;
};
#endif // MODBUS_RTU_POLLER_SERVICE_H

View File

@ -1,13 +1,91 @@
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
#include <vector>
#include <stdexcept>
#include <iomanip>
// #include "dataStorage/data_storage.h" // 包含你的头文件
// 假设这些头文件已经包含在你的主程序中
#include "modbus/modbus_common.h" // 包含 ModbusRtuDeviceConfig, DataPointConfig, ModbusDataType
#include "modbus/modbus_rtu_poller_service.h" // 包含 ModbusRtuPollerService 类
// 模拟一个从设备接收到的原始数据
// void mockDataReceiving() {
// DataStorage& storage = DataStorage::getInstance();
// // 1. 初始化数据库(只需要做一次)
// if (!storage.initialize("/app/db/my_app_data.db")) {
// std::cerr << "Failed to initialize database. Exiting." << std::endl;
// return;
// }
int main(int argc, char* argv[]) {
printf("HELLO");
return 0;
}
// // 2. 模拟收到一批原始数据
// for (int i = 0; i < 10; ++i) {
// std::string raw_payload = "RAW_SENSOR_DATA_" + std::to_string(i) + "_VALUE=123";
// std::string device_id = "sensor-alpha-001";
// std::string protocol = "custom_protocol_v1";
// // 2.1 存储原始数据
// if (!storage.storeRawData(device_id, raw_payload, protocol)) {
// std::cerr << "Failed to store raw data for " << device_id << std::endl;
// }
// }
// // 3. 模拟协议解析器工作,并将数据转换为 UnifiedData 格式
// for (int i = 0; i < 5; ++i) {
// UnifiedData data;
// data.device_id = "sensor-beta-002";
// data.timestamp_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
// // 构造一个复杂的 JSON 字符串
// data.data_json = "{"
// "\"temperature\": " + std::to_string(25.5 + i * 0.1) + ","
// "\"humidity\": " + std::to_string(60.2 - i * 0.5) + ","
// "\"status\": \"active\","
// "\"error_code\": 0"
// "}";
// // 3.2 存储处理后的数据
// if (!storage.storeProcessedData(data)) {
// std::cerr << "Failed to store processed data for " << data.device_id << std::endl;
// }
// }
// std::cout << "Data storage simulation finished." << std::endl;
// }
// int main() {
// mockDataReceiving();
// return 0;
// }
// 假设这些头文件已经包含在你的主程序中
// #include "modbus/modbus_common.h" // 包含 ModbusRtuDeviceConfig, DataPointConfig, ModbusDataType
// #include "modbus_rtu_poller_service.h" // 包含 ModbusRtuPollerService 类
// #include "data_storage.h" // 上一个问题中的数据存储类,用来接收最终数据
// #include <iostream>
// 这是你的主程序或某个初始化函数中的代码
int main() {
// 1. 创建具体的数据点配置列表
std::vector<DataPointConfig> data_points;
// 配置第一个数据点:温度
DataPointConfig temp_config;
temp_config.name = "temperature_celsius";
temp_config.address = 0x01;
temp_config.type = ModbusDataType::FLOAT32;
temp_config.scale = 1.0; // 假设原始值需要乘以0.1才能得到真实温度
data_points.push_back(temp_config);
// 配置第二个数据点:状态
DataPointConfig status_config;
status_config.name = "device_status";
status_config.address = 0x03;
status_config.type = ModbusDataType::FLOAT32;
status_config.scale = 1.0; // 不需要缩放
data_points.push_back(status_config);
// 2. 创建完整的设备配置
ModbusRtuDeviceConfig device_config;
device_config.device_id = "boiler-room-sensor-01"; // 给设备一个唯一的ID很重要
device_config.port_path = "/dev/ttyS7"; // Linux下的串口设备名
device_config.baud_rate = 9600; // 波特率
device_config.slave_id = 0x02; // Modbus从站地址
device_config.poll_interval_ms = 2000; // 每2秒轮询一次
device_config.data_points = data_points; // 将我们刚刚配置的数据点列表放进去
// ... 接下来进入管理层 ...
}