新增 pELoad 电子负载(IT6000C)控制程序:以太网 Raw Socket SCPI 直连设备,100ms 周期功率控制(订阅 MOOS 功率消息按 P/U 折算电流,CC/CV 双环路优先 + FUNC:MODE FIX 防护),网页人机交互(步骤引导/防误触确认),sqlite3 存储(100ms 高采样 V/I/P 测量表 meas_log + CSV 导出分析),并接入 scripts/build-board.sh 板卡部署与 systemd 服务、missions/h100.moos 配置
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
#ifndef PELOAD_SCPI_CLIENT_H
|
||||
#define PELOAD_SCPI_CLIENT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
namespace eload {
|
||||
|
||||
//============================================================================
|
||||
// ScpiClient:IT6000C Raw Socket SCPI 客户端(TCP,LF 结尾,自动重连)。
|
||||
//
|
||||
// 协议要点(docs/电子负载说明手册/IT6000C User Manual-CN 2.5.2.3 使用套接字):
|
||||
// - 仪器提供 SCPI 套接字服务(Socket Port 可配置,出厂默认 30000);
|
||||
// - 所有命令必须以换行符(\n)结尾;查询响应同样以换行符结束;
|
||||
// - 仪器最多同时允许 6 个套接字/telnet 连接。
|
||||
//
|
||||
// 线程模型:
|
||||
// - 内部一个 IO 线程:负责连接/重连、命令写出、响应读取;
|
||||
// - cmd() 非阻塞入队(写后无响应);
|
||||
// - query() 同步等待响应(同一时刻仅允许一个查询,互斥保护);
|
||||
// - 本线程不调用任何 MOOS 接口,跨线程数据仅通过回调投递。
|
||||
//============================================================================
|
||||
|
||||
class ScpiClient {
|
||||
public:
|
||||
// SCPI 收发记录回调(落库用,IO 线程内调用):
|
||||
// 命令型:resp 为空;查询型:resp 为响应文本(含失败标记)
|
||||
using LogSink = std::function<void(const std::string& cmd, const std::string& resp)>;
|
||||
// 连接状态变化回调(IO 线程内调用)
|
||||
using StateCallback = std::function<void(bool connected)>;
|
||||
|
||||
ScpiClient();
|
||||
~ScpiClient();
|
||||
|
||||
void configure(const std::string& host, long port); // start 前调用
|
||||
void setLogSink(LogSink cb); // start 前调用
|
||||
void setStateCallback(StateCallback cb); // start 前调用
|
||||
|
||||
bool start(); // 启动 IO 线程(自动连接/重连)
|
||||
void stop();
|
||||
|
||||
bool isConnected() const { return m_connected; }
|
||||
|
||||
// 写命令(无响应期待)。未连接/发送失败按错误计数并丢弃。
|
||||
bool cmd(const std::string& scpi);
|
||||
|
||||
// 同步查询:发送 scpi 并等待一行响应。
|
||||
// timeoutMs 建议不大于控制周期(100ms 循环里建议 <= 80)。
|
||||
bool query(const std::string& scpi, std::string& resp, int timeoutMs = 200);
|
||||
|
||||
// 统计
|
||||
unsigned long txCount() const { return m_txCount; }
|
||||
unsigned long txErrorCount() const { return m_txErrorCount; }
|
||||
unsigned long rxCount() const { return m_rxCount; }
|
||||
unsigned long errorCount() const { return m_errorCount; }
|
||||
unsigned long reconnectCount() const { return m_reconnectCount; }
|
||||
double lastRxTime() const { return m_lastRxTime; }
|
||||
|
||||
const std::string& host() const { return m_host; }
|
||||
long port() const { return m_port; }
|
||||
|
||||
private:
|
||||
struct Work {
|
||||
std::string cmd;
|
||||
bool expectReply;
|
||||
std::string resp;
|
||||
bool done;
|
||||
bool ok;
|
||||
Work() : expectReply(false), done(false), ok(false) {}
|
||||
};
|
||||
|
||||
void threadFunc();
|
||||
bool connectOnce();
|
||||
void closeSocket();
|
||||
bool writeLine(const std::string& scpi);
|
||||
// 从 socket 读一行(LF 结尾),deadlineMs 内未完成返回 false
|
||||
bool readLine(std::string& line, int deadlineMs);
|
||||
void runQueue();
|
||||
|
||||
std::string m_host;
|
||||
long m_port = 30000;
|
||||
int m_fd = -1;
|
||||
|
||||
std::atomic<bool> m_running{false};
|
||||
std::atomic<bool> m_connected{false};
|
||||
std::thread m_thread;
|
||||
|
||||
// 命令队列:cmd() 与 query() 共用;IO 线程逐条处理
|
||||
std::mutex m_queueMutex;
|
||||
std::condition_variable m_queueCv;
|
||||
std::deque<std::shared_ptr<Work> > m_queue;
|
||||
// 同一时刻仅允许一个同步查询
|
||||
std::mutex m_queryMutex;
|
||||
|
||||
LogSink m_logSink; // 任意线程注册,IO 线程调用(start 前 set)
|
||||
StateCallback m_stateCb;
|
||||
|
||||
std::vector<uint8_t> m_buf; // 流式接收缓冲(半包/粘包按 \n 切分)
|
||||
|
||||
std::atomic<unsigned long> m_txCount{0};
|
||||
std::atomic<unsigned long> m_txErrorCount{0};
|
||||
std::atomic<unsigned long> m_rxCount{0};
|
||||
std::atomic<unsigned long> m_errorCount{0};
|
||||
std::atomic<unsigned long> m_reconnectCount{0};
|
||||
std::atomic<double> m_lastRxTime{0.0};
|
||||
};
|
||||
|
||||
} // namespace eload
|
||||
#endif // PELOAD_SCPI_CLIENT_H
|
||||
Reference in New Issue
Block a user