diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e78f25..be4b47f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,14 +94,14 @@ target_link_libraries(edge_proxy PRIVATE # =================#================================================ # 测试目标 # ================================================================= -# add_executable(test -# src/test.cc -# src/SQL/data_storage.cc +add_executable(test + src/test.cc + src/piper_tts_interface.cc -# ) +) -# target_link_libraries(test PRIVATE -# edge_proxy_lib -# ) +target_link_libraries(test PRIVATE + edge_proxy_lib +) diff --git a/src/modbus/modbus_master_poller.h b/src/modbus/modbus_master_poller.h index 870b4dc..6869aa0 100644 --- a/src/modbus/modbus_master_poller.h +++ b/src/modbus/modbus_master_poller.h @@ -12,7 +12,6 @@ class ModbusMasterPoller : public std::enable_shared_from_this { public: - // <<< MODIFIED: 构造函数接收新的配置结构体 ModbusMasterPoller(boost::asio::io_context& io_context, ModbusTcpDeviceConfig config, ReportDataCallback report_cb); @@ -35,14 +34,13 @@ private: void do_poll(); void do_write(); void do_read_header(); - void do_read_pdu(std::size_t pdu_length, uint16_t poll_start_addr); // <<< MODIFIED: 需要知道轮询的起始地址 + void do_read_pdu(std::size_t pdu_length, uint16_t poll_start_addr); void on_error(const std::string& stage); boost::asio::io_context& m_io_context; boost::asio::ip::tcp::socket m_socket; boost::asio::steady_timer m_timer; - // <<< MODIFIED: 成员变量使用新的配置结构体 ModbusTcpDeviceConfig m_config; ReportDataCallback m_report_callback; diff --git a/src/test.cc b/src/test.cc index 4dadc3c..6a9b3ae 100644 --- a/src/test.cc +++ b/src/test.cc @@ -1,91 +1,16 @@ +#include "piper_tts_interface.h" +#include #include -#include -// #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; -// } - -// // 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::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 -// 这是你的主程序或某个初始化函数中的代码 int main() { - // 1. 创建具体的数据点配置列表 - std::vector 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; // 将我们刚刚配置的数据点列表放进去 - // ... 接下来进入管理层 ... -} \ No newline at end of file + PiperTTSInterface tts_processor; + // 示例 1: 只提供文本和输出文件名 + std::string text1 = "你好,世界。温度传感器出现故障。只需输入文本即可。"; + std::string file1 = "hello_world.wav"; + if (tts_processor.text_to_speech(text1, file1)) { + std::cout << "Audio for '" << text1 << "' generated successfully!" << std::endl; + } else { + std::cerr << "Failed to generate audio for '" << text1 << "'." << std::endl; + } + return 0; +} diff --git a/src/tts/piper_tts_interface.cc b/src/tts/piper_tts_interface.cc new file mode 100644 index 0000000..7821658 --- /dev/null +++ b/src/tts/piper_tts_interface.cc @@ -0,0 +1,46 @@ +#include "piper_tts_interface.h" +#include // For system() + +// 构造函数实现 +PiperTTSInterface::PiperTTSInterface(const std::string& piper_exec_path, + const std::string& model_path_fixed) + : piper_executable(piper_exec_path), fixed_model_path(model_path_fixed) { + // 构造时直接初始化模型路径 + if (fixed_model_path.empty()) { + std::cerr << "Warning: PiperTTSInterface created without a default model path. text_to_speech calls may fail." << std::endl; + } +} + +// 注意:这里不再有 set_default_model_path 方法 + +// 辅助函数,封装 system() 调用,以便更好地控制和调试 +int PiperTTSInterface::execute_command(const std::string& command) { + std::cout << "Executing command: " << command << std::endl; + return std::system(command.c_str()); +} + +bool PiperTTSInterface::text_to_speech(const std::string& text, + const std::string& output_filename) { + + // 直接使用构造函数中设置的固定模型路径 + if (fixed_model_path.empty()) { + std::cerr << "Error: No fixed model path specified for text_to_speech." << std::endl; + return false; + } + + std::string escaped_text = text; + + std::string command = "echo \"" + escaped_text + "\" | " + + piper_executable + " --model " + fixed_model_path + + " --output_file " + output_filename; + + int result = execute_command(command); + + if (result == 0) { // system() 返回 0 表明命令执行成功 + std::cout << "Successfully generated audio: " << output_filename << std::endl; + return true; + } else { + std::cerr << "Failed to generate audio for '" << text << "'. Command exited with code: " << result << std::endl; + return false; + } +} diff --git a/src/tts/piper_tts_interface.h b/src/tts/piper_tts_interface.h new file mode 100644 index 0000000..95debf5 --- /dev/null +++ b/src/tts/piper_tts_interface.h @@ -0,0 +1,33 @@ +#ifndef PIPER_TTS_INTERFACE_H +#define PIPER_TTS_INTERFACE_H + +#include +#include + +class PiperTTSInterface { +public: + // 构造函数:指定 piper 可执行文件路径 和 默认模型文件路径 + PiperTTSInterface(const std::string& piper_executable_path = "piper", + const std::string& default_model_path = "/app/piper_models/zh_CN-huayan-medium.onnx"); // 默认模型路径直接在这里设置 + + // 我们将移除或不使用 set_default_model_path,因为模型在构造时已指定 + + /** + * @brief 将文本转换为语音并保存为WAV文件。 + * @param text 要转换的文本。 + * @param output_filename 生成的WAV文件名,例如 "output.wav"。 + * 如果model_path参数为空,则使用构造函数中指定的默认模型。 + * @return true 表示成功生成音频,false 表示失败。 + */ + bool text_to_speech(const std::string& text, + const std::string& output_filename); // 移除了 model_path 参数 + +private: + std::string piper_executable; // Piper 可执行文件的路径 + std::string fixed_model_path; // 固定模型路径 + + // 辅助函数,封装 system() 调用,以便更好地控制和调试 + int execute_command(const std::string& command); +}; + +#endif // PIPER_TTS_INTERFACE_H