电压读取

This commit is contained in:
GuanYuankai 2025-10-21 15:34:24 +08:00
parent f6312ffbce
commit a4d926713f
5 changed files with 274 additions and 20 deletions

View File

@ -68,6 +68,9 @@ add_library(edge_proxy_lib STATIC
#SQL
src/dataStorage/data_storage.cc
#tts
src/tts/piper_tts_interface.cc
)
target_include_directories(edge_proxy_lib PUBLIC
@ -82,7 +85,7 @@ target_link_libraries(edge_proxy_lib PRIVATE
SQLite::SQLite3
pthread
nlohmann_json
rknn_api
# rknn_api
rknnrt
)
@ -103,15 +106,15 @@ target_link_libraries(edge_proxy PRIVATE
# =================#================================================
#
# =================================================================
# add_executable(test
# src/test.cc
# src/piper_tts_interface.cc
add_executable(test
src/test.cc
src/systemMonitor/iio_sensor.cc
# )
)
# target_link_libraries(test PRIVATE
# edge_proxy_lib
# )
target_link_libraries(test PRIVATE
edge_proxy_lib
)
# 1. 定义新的可执行文件 (我们将把代码放在 src/streamer/ 目录下)

View File

@ -18,6 +18,8 @@ services:
- /dev/rga:/dev/rga
- /dev/dri:/dev/dri
- source: /sys/bus/iio/devices/iio:device0
target: /sys/bus/iio/devices/iio:device0
group_add:
- "20"
- "44"

View File

@ -0,0 +1,133 @@
#include "iio_sensor.h" // 必须包含自己的头文件
#include <iostream>
#include <fstream>
#include <filesystem>
#include <string>
#include <stdexcept>
#include <sstream>
// --- PIMPL 模式的具体实现 ---
// 这里我们只有一个空的实现,因为我们不再在类内部保存文件流
// 但保留这个结构可以让我们在不改变.h文件的情况下未来扩展功能
struct IioSensor::Impl {
// 当前实现为空
// std::ifstream voltageFile; // 这种方式已被抛弃
};
// --- 构造函数 ---
// 现在只负责构建路径和检查文件是否存在,不打开文件
IioSensor::IioSensor(const std::string& devicePath, const std::string& channelName)
: devicePath_(devicePath), channelName_(channelName) {
// 使用 std::filesystem 安全地拼接路径
std::filesystem::path fullFilePath = std::filesystem::path(devicePath_) / channelName_;
fullFilePath_ = fullFilePath.string();
// 检查文件是否存在,这是一个非常好的防御性编程实践
if (!std::filesystem::exists(fullFilePath_)) {
throw IioSensorError("IIO Channel Error: File not found at " + fullFilePath_ + "\n"
"Please check the path (" + devicePath_ + ") and ensure the sensor is connected and configured.");
}
// 初始化 PIMPL即使为空也需要创建
pImpl_ = std::make_unique<Impl>();
}
// --- 析构函数 ---
// std::unique_ptr 会自动为我们释放 Impl 对象的内存,无需手动删除
IioSensor::~IioSensor() = default;
// --- 公共接口实现 ---
int64_t IioSensor::readRawValue() {
// --- 1. 每次读取都创建一个新的文件流对象 ---
// 使用RAII管理这个临时文件流函数结束时它会自动关闭
std::ifstream voltageFile(fullFilePath_, std::ios::in);
// --- 2. 检查文件是否成功打开 ---
if (!voltageFile.is_open()) {
throw IioSensorError("IIO Channel Error: Failed to open file " + fullFilePath_ + "\n"
"Check permissions (the process might need to be in the 'iio' group).");
}
// --- 3. 读取文件内容 ---
std::string voltageValueStr;
// std::getline 从文件流中读取一行
if (!std::getline(voltageFile, voltageValueStr)) {
// 如果读取操作失败例如文件为空但根据IIO模型这里更可能是其他问题
throw IioSensorError("IIO Channel Error: Failed to read data from file " + fullFilePath_);
}
// --- 4. 字符串到数字的转换 ---
try {
// std::stoll 是 C++11 引入的,安全地将字符串转换为 long long
// 对于ADC值long long (int64_t) 通常更合适
int64_t rawValue = std::stoll(voltageValueStr);
return rawValue;
} catch (const std::invalid_argument& e) {
// 如果字符串不是一个有效的数字
throw IioSensorError("IIO Channel Error: Invalid data format in file " + fullFilePath_ +
". Content: '" + voltageValueStr + "'");
} catch (const std::out_of_range& e) {
// 如果数字超出 long long 的表示范围
throw IioSensorError("IIO Channel Error: Number out of range in file " + fullFilePath_);
}
}
double IioSensor::readVoltage(double referenceVoltage, int64_t adcResolution, double gain) {
// --- 1. 调用 readRawValue() 来复用错误处理和读取逻辑 ---
// 这符合DRY (Don't Repeat Yourself) 原则
int64_t rawValue = readRawValue();
// --- 2. 进行运行时参数检查 ---
// static_assert 不适用于运行时参数,我们使用 if 语句
if (adcResolution <= 0) {
throw std::invalid_argument("ADC Resolution must be a positive number.");
}
if (referenceVoltage <= 0) {
throw std::invalid_argument("Reference Voltage must be a positive number.");
}
if (gain == 0.0) {
throw std::invalid_argument("Gain cannot be zero.");
}
// --- 3. 计算电压并返回 ---
// 注意:这里的转换是基于原始值的,具体物理含义需要根据你的数据手册确定
// (rawValue / Resolution) * ReferenceVoltage * Gain
return static_cast<double>(rawValue) / static_cast<double>(adcResolution) * referenceVoltage * gain;
}
// int main() {
// // --- 配置参数 ---
// // !!! 修改这里以匹配你的设备和通道 !!!
// const std::string iio_device_path = "/sys/bus/iio/devices/iio:device0";
// const std::string iio_channel_name = "in_voltage2_raw"; // 例如,连接到 IN2 通道
// const double adc_reference_voltage = 1.8; // ADC参考电压
// const int64_t adc_resolution = 4096; // ADC分辨率 (e.g., 2^12 for 12-bit)
// const double signal_gain = 11.0; // 信号通路的增益
// std::cout << "--- Starting IIO Sensor Reader (Version 2) ---" << std::endl;
// std::cout << "Reading from device: " << iio_device_path << std::endl;
// std::cout << "Reading channel: " << iio_channel_name << std::endl;
// std::cout << "-----------------------------------------------" << std::endl;
// // 注意:传感器对象在 try 块外创建,如果构造失败(找不到文件),会立即被捕获
// IioSensor sensor(iio_device_path, iio_channel_name);
// while (true) {
// try {
// // 封装后的调用方式非常简洁!
// // 每次调用 readVoltage内部都会重新打开文件读取一次
// double actual_voltage = sensor.readVoltage(adc_reference_voltage, adc_resolution, signal_gain);
// // 输出结果
// std::cout << "Actual Voltage: " << actual_voltage << " V" << std::endl;
// } catch (const IioSensorError& e) {
// // 如果单次读取失败(例如文件内容格式错误、无权限等),打印错误但继续循环
// std::cerr << "[!] Read Error: " << e.what() << std::endl;
// }
// // 每秒钟读取一次
// std::this_thread::sleep_for(std::chrono::seconds(1));
// }
// return 0;
// }

View File

@ -0,0 +1,79 @@
#ifndef IIO_SENSOR_H
#define IIO_SENSOR_H
#include <string>
#include <memory> // For std::unique_ptr
#include <stdexcept>
#include <chrono>
#include <thread>
// 自定义异常类专门用于处理IIO相关的错误
// 继承自 std::runtime_error这样我们就可以用 catch(std::exception&) 来捕获它
class IioSensorError : public std::runtime_error {
public:
// 使用父类的构造函数来初始化错误信息
explicit IioSensorError(const std::string& message) : std::runtime_error(message) {}
};
/**
* @brief Linux Industrial I/O (IIO) ADC值的类
*
* IIO设备文件交互的细节
*
* IIO
*/
class IioSensor {
public:
/**
* @brief IIO传感器读取器
*
* ****
* readRawValue() readVoltage()
*
* @param devicePath IIO设备的绝对路径 (e.g., "/sys/bus/iio/devices/iio:device0").
* @param channelName (e.g., "in_voltage2_raw").
* @throws IioSensorError
*/
IioSensor(const std::string& devicePath, const std::string& channelName);
/**
* @brief RAII在每次读取时管理
*/
~IioSensor();
/**
* @brief IIO通道读取一次原始ADC值
*
*
*
* @return int64_t
* @throws IioSensorError
*/
int64_t readRawValue();
/**
* @brief IIO通道读取一次原始ADC值并转换为电压
*
* `readRawValue()`
*
* @param referenceVoltage ADC的参考电压 (e.g., 3.3, 1.8).
* @param adcResolution ADC的分辨率 (e.g., 4096 for 12-bit, 65536 for 16-bit).
* @param gain () (e.g., 11 for 11x gain).
* @return double
* @throws IioSensorError
*/
double readVoltage(double referenceVoltage, int64_t adcResolution, double gain = 1.0);
private:
// --- 私有成员变量 ---
std::string devicePath_; // IIO设备路径
std::string channelName_; // IIO通道名称
std::string fullFilePath_; // 完整的IIO通道文件路径
// PIMPL 结构体,用来隐藏实现细节
// 虽然我们不再在构造函数里打开文件,但保留它可以将来轻松扩展
struct Impl;
std::unique_ptr<Impl> pImpl_;
};
#endif // IIO_SENSOR_H

View File

@ -1,16 +1,53 @@
#include "piper_tts_interface.h"
#include <string>
#include <iostream>
// #include "piper_tts_interface.h"
// #include <string>
// #include <iostream>
// int main() {
// 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;
// }
#include <iostream>
#include <chrono>
#include <thread>
#include "systemMonitor/iio_sensor.h" // 包含我们刚刚创建的头文件
int main() {
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;
// --- 配置参数 ---
// !!! 修改这里以匹配你的设备和通道 !!!
const std::string iio_device_path = "/sys/bus/iio/devices/iio:device0";
const std::string iio_channel_name = "in_voltage2_raw"; // 例如,连接到 IN2 通道
const double adc_reference_voltage = 1.8; // ADC参考电压
const int64_t adc_resolution = 4096; // ADC分辨率 (e.g., 2^12 for 12-bit)
const double signal_gain = 11.0; // 信号通路的增益
std::cout << "--- Starting IIO Sensor Reader (Version 2) ---" << std::endl;
std::cout << "Reading from device: " << iio_device_path << std::endl;
std::cout << "Reading channel: " << iio_channel_name << std::endl;
std::cout << "-----------------------------------------------" << std::endl;
// 注意:传感器对象在 try 块外创建,如果构造失败(找不到文件),会立即被捕获
IioSensor sensor(iio_device_path, iio_channel_name);
while (true) {
try {
// 封装后的调用方式非常简洁!
// 每次调用 readVoltage内部都会重新打开文件读取一次
double actual_voltage = sensor.readVoltage(adc_reference_voltage, adc_resolution, signal_gain);
// 输出结果
std::cout << "Actual Voltage: " << actual_voltage << " V" << std::endl;
} catch (const IioSensorError& e) {
// 如果单次读取失败(例如文件内容格式错误、无权限等),打印错误但继续循环
std::cerr << "[!] Read Error: " << e.what() << std::endl;
}
// 每秒钟读取一次
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}
}