上位机(Upper Computer)基础入门及其C与C++实例
1. 上位机基础概念
1.1 什么是上位机
上位机(Upper Computer)是指在主从式计算机系统中,用于监控、控制、数据采集、分析与处理的主控计算机。它通常负责人机交互界面、数据存储、高级算法运算以及下位机控制。
在工业控制系统、智能设备、实验室仪器、物联网设备等场景中,上位机担任关键角色,负责协调系统整体运行,并提供用户友好的操作界面。
1.2 上位机的主要功能
- 人机交互:提供图形用户界面(GUI),使操作人员能够方便地监控系统状态及发送控制命令
- 数据采集:从下位机或传感器网络获取数据
- 数据显示:以图表、仪表盘、趋势图等形式可视化展示数据
- 数据存储:将采集的数据保存到数据库或文件系统
- 远程控制:向下位机发送控制命令和参数
- 数据分析:对采集的数据进行处理、分析、计算,提取有价值的信息
- 报警管理:检测异常情况并提示操作人员
- 系统配置:提供接口设置系统参数
1.3 上位机开发方式分类
- 专用软件开发:使用C/C++、C#、Java等编程语言自主开发完整的上位机软件
- 开发环境集成:使用LabVIEW、MATLAB、Python等集成开发环境快速搭建
- 工业软件二次开发:基于SCADA、组态软件等工业控制软件进行二次开发
- Web应用开发:开发基于浏览器的上位机系统,便于远程访问和跨平台使用
1.4 通信接口与协议
上位机与下位机之间的通信是系统正常运行的关键,常见接口和协议包括:
-
硬件接口:
- 串口(RS-232/RS-485/RS-422)
- USB
- 以太网
- CAN总线
- 无线通信(Wi-Fi/蓝牙/ZigBee等)
-
通信协议:
- Modbus
- PROFINET
- OPC UA
- MQTT
- 自定义协议
2. C语言上位机开发基础
2.1 串口通信基础示例
c
/**
* serial_port_example.c - 串口通信示例
* 演示如何使用C语言实现基本的串口通信功能
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#endif
// 平台无关的串口处理结构体
typedef struct {
#ifdef _WIN32
HANDLE handle;
#else
int fd;
#endif
char port_name[64];
int baud_rate;
} SerialPort;
// 打开串口
int serialport_open(SerialPort* port) {
#ifdef _WIN32
// Windows 平台
char port_path[64];
sprintf(port_path, "\\\\.\\%s", port->port_name); // 例如:\\.\COM1
port->handle = CreateFile(port_path,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (port->handle == INVALID_HANDLE_VALUE) {
printf("Error opening serial port: %s\n", port->port_name);
return -1;
}
// 设置串口参数
DCB dcb = {0};
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(port->handle, &dcb)) {
printf("Error getting comm state\n");
CloseHandle(port->handle);
return -1;
}
// 设置波特率
dcb.BaudRate = port->baud_rate;
dcb.ByteSize = 8; // 8位数据位
dcb.StopBits = ONESTOPBIT; // 1个停止位
dcb.Parity = NOPARITY; // 无校验
if (!SetCommState(port->handle, &dcb)) {
printf("Error setting comm state\n");
CloseHandle(port->handle);
return -1;
}
// 设置超时
COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (!SetCommTimeouts(port->handle, &timeouts)) {
printf("Error setting timeouts\n");
CloseHandle(port->handle);
return -1;
}
#else
// Linux/Unix 平台
port->fd = open(port->port_name, O_RDWR | O_NOCTTY | O_NDELAY);
if (port->fd < 0) {
printf("Error opening serial port: %s\n", port->port_name);
return -1;
}
// 设置串口参数
struct termios options;
tcgetattr(port->fd, &options);
// 设置波特率
speed_t baud;
switch (port->baud_rate) {
case 9600: baud = B9600; break;
case 19200: baud = B19200; break;
case 38400: baud = B38400; break;
case 57600: baud = B57600; break;
case 115200: baud = B115200; break;
default: baud = B9600; break;
}
cfsetispeed(&options, baud);
cfsetospeed(&options, baud);
options.c_cflag |= (CLOCAL | CREAD); // 启用接收器并忽略调制解调器控制线
options.c_cflag &= ~PARENB; // 无校验
options.c_cflag &= ~CSTOPB; // 1个停止位
options.c_cflag &= ~CSIZE; // 掩码字符大小位
options.c_cflag |= CS8; // 8位数据位
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始输入
options.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控
options.c_oflag &= ~OPOST; // 原始输出
// 设置超时
options.c_cc[VMIN] = 0; // 非阻塞读取
options.c_cc[VTIME] = 10; // 100ms超时
tcsetattr(port->fd, TCSANOW, &options);
#endif
return 0;
}
// 关闭串口
void serialport_close(SerialPort* port) {
#ifdef _WIN32
if (port->handle != INVALID_HANDLE_VALUE) {
CloseHandle(port->handle);
port->handle = INVALID_HANDLE_VALUE;
}
#else
if (port->fd >= 0) {
close(port->fd);
port->fd = -1;
}
#endif
}
// 发送数据
int serialport_write(SerialPort* port, const void* buffer, size_t size) {
#ifdef _WIN32
DWORD bytes_written = 0;
if (!WriteFile(port->handle, buffer, size, &bytes_written, NULL)) {
printf("Error writing to serial port\n");
return -1;
}
return bytes_written;
#else
return write(port->fd, buffer, size);
#endif
}
// 接收数据
int serialport_read(SerialPort* port, void* buffer, size_t size) {
#ifdef _WIN32
DWORD bytes_read = 0;
if (!ReadFile(port->handle, buffer, size, &bytes_read, NULL)) {
printf("Error reading from serial port\n");
return -1;
}
return bytes_read;
#else
return read(port->fd, buffer, size);
#endif
}
// 主程序
int main(int argc, char* argv[]) {
SerialPort port;
// 默认参数
#ifdef _WIN32
strcpy(port.port_name, "COM1");
#else
strcpy(port.port_name, "/dev/ttyUSB0");
#endif
port.baud_rate = 9600;
// 处理命令行参数
if (argc > 1) {
strncpy(port.port_name, argv[1], sizeof(port.port_name)-1);
}
if (argc > 2) {
port.baud_rate = atoi(argv[2]);
}
printf("Opening %s at %d baud\n", port.port_name, port.baud_rate);
// 打开串口
if (serialport_open(&port) < 0) {
printf("Failed to open serial port\n");
return -1;
}
printf("Serial port opened successfully\n");
// 发送测试数据
const char* test_message = "Hello from upper computer\r\n";
int bytes_written = serialport_write(&port, test_message, strlen(test_message));
printf("Sent %d bytes: %s\n", bytes_written, test_message);
// 接收数据
char buffer[128];
printf("Waiting for data...\n");
// 简单的循环接收和显示数据
int loop_count = 0;
while (loop_count < 10) { // 执行10次读取操作
memset(buffer, 0, sizeof(buffer));
int bytes_read = serialport_read(&port, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
printf("Received %d bytes: %s\n", bytes_read, buffer);
} else if (bytes_read < 0) {
printf("Error reading from serial port\n");
break;
}
// 简单的等待
#ifdef _WIN32
Sleep(500); // 500毫秒
#else
usleep(500000); // 500000微秒 = 500毫秒
#endif
loop_count++;
}
// 关闭串口
serialport_close(&port);
printf("Serial port closed\n");
return 0;
}
2.2 简单文件数据记录器
c
/**
* data_logger.c - 简单的数据记录器
* 演示如何使用C语言开发数据采集和记录功能
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#define sleep_ms(ms) Sleep(ms)
#else
#include <unistd.h>
#define sleep_ms(ms) usleep((ms) * 1000)
#endif
// 数据记录结构
typedef struct {
FILE* file;
char filename[128];
int is_open;
int record_count;
time_t start_time;
} DataLogger;
// 传感器数据结构
typedef struct {
float temperature;
float humidity;
float pressure;
float voltage;
time_t timestamp;
} SensorData;
// 初始化数据记录器
int logger_init(DataLogger* logger, const char* prefix) {
time_t now;
struct tm* timeinfo;
char timestamp[64];
// 获取当前时间
time(&now);
timeinfo = localtime(&now);
strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", timeinfo);
// 创建文件名: prefix_YYYYMMDD_HHMMSS.csv
snprintf(logger->filename, sizeof(logger->filename),
"%s_%s.csv", prefix, timestamp);
// 打开文件
logger->file = fopen(logger->filename, "w");
if (!logger->file) {
printf("Error: Unable to open file %s\n", logger->filename);
return -1;
}
// 写入CSV头
fprintf(logger->file, "Timestamp,DateTime,Temperature,Humidity,Pressure,Voltage\n");
fflush(logger->file);
logger->is_open = 1;
logger->record_count = 0;
logger->start_time = now;
printf("Data logger initialized. Recording to %s\n", logger->filename);
return 0;
}
// 记录数据
int logger_record(DataLogger* logger, const SensorData* data) {
char datetime[64];
struct tm* timeinfo;
if (!logger->is_open || !logger->file) {
printf("Error: Logger not initialized\n");
return -1;
}
// 格式化时间
timeinfo = localtime(&data->timestamp);
strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", timeinfo);
// 写入数据记录
fprintf(logger->file, "%ld,%s,%.2f,%.2f,%.2f,%.2f\n",
data->timestamp,
datetime,
data->temperature,
data->humidity,
data->pressure,
data->voltage);
// 确保及时写入到文件
fflush(logger->file);
logger->record_count++;
return 0;
}
// 关闭数据记录器
void logger_close(DataLogger* logger) {
time_t now;
double elapsed_seconds;
if (logger->is_open && logger->file) {
time(&now);
elapsed_seconds = difftime(now, logger->start_time);
printf("Data logger closed. Recorded %d samples in %.1f seconds (%.2f samples/sec)\n",
logger->record_count, elapsed_seconds,
logger->record_count / (elapsed_seconds > 0 ? elapsed_seconds : 1));
fclose(logger->file);
logger->file = NULL;
logger->is_open = 0;
}
}
// 模拟传感器数据采集
void simulate_sensor_reading(SensorData* data) {
static float temp_base = 25.0;
static float humid_base = 50.0;
static float pressure_base = 1013.0;
static float voltage_base = 12.0;
// 生成带有一些随机变化的模拟数据
data->temperature = temp_base + ((float)rand() / RAND_MAX * 2.0f - 1.0f);
data->humidity = humid_base + ((float)rand() / RAND_MAX * 5.0f - 2.5f);
data->pressure = pressure_base + ((float)rand() / RAND_MAX * 3.0f - 1.5f);
data->voltage = voltage_base + ((float)rand() / RAND_MAX * 0.4f - 0.2f);
// 添加缓慢的变化趋势
temp_base += ((float)rand() / RAND_MAX * 0.1f - 0.05f);
humid_base += ((float)rand() / RAND_MAX * 0.2f - 0.1f);
// 设置当前时间戳
time(&data->timestamp);
}
// 显示传感器数据
void display_sensor_data(const SensorData* data) {
char datetime[64];
struct tm* timeinfo;
// 格式化时间
timeinfo = localtime(&data->timestamp);
strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", timeinfo);
printf("\rTime: %s | Temp: %.2f°C | Humidity: %.2f%% | Pressure: %.2f hPa | Voltage: %.2f V",
datetime, data->temperature, data->humidity, data->pressure, data->voltage);
fflush(stdout);
}
int main(int argc, char* argv[]) {
DataLogger logger;
SensorData sensor_data;
int sample_rate_ms = 1000; // 默认每秒采样一次
int max_samples = 60; // 默认采集60个样本
int i;
// 处理命令行参数
if (argc > 1) {
sample_rate_ms = atoi(argv[1]);
if (sample_rate_ms < 100) sample_rate_ms = 100; // 最小100毫秒
}
if (argc > 2) {
max_samples = atoi(argv[2]);
if (max_samples < 1) max_samples = 1;
}
printf("Data Logger Example\n");
printf("Sample rate: %d ms, Max samples: %d\n", sample_rate_ms, max_samples);
// 初始化随机数生成器
srand((unsigned int)time(NULL));
// 初始化数据记录器
if (logger_init(&logger, "sensor_data") < 0) {
return -1;
}
printf("Starting data collection...\n");
// 采集并记录数据
for (i = 0; i < max_samples && logger.is_open; i++) {
// 模拟传感器读数
simulate_sensor_reading(&sensor_data);
// 显示数据
display_sensor_data(&sensor_data);
// 记录数据
logger_record(&logger, &sensor_data);
// 等待到下一个采样时间
sleep_ms(sample_rate_ms);
}
printf("\nData collection completed.\n");
// 关闭数据记录器
logger_close(&logger);
return 0;
}
2.3 简单命令行解析器
c
/**
* command_parser.c - 简单的命令行解析器
* 演示如何实现命令行接口来控制设备
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_CMD_LEN 256
#define MAX_ARGS 16
// 命令处理函数原型
typedef int (*CommandFunc)(int argc, char* argv[]);
// 命令结构
typedef struct {
const char* name;
const char* help;
CommandFunc func;
} Command;
// 系统状态
typedef struct {
int is_connected;
int device_status;
float temperature;
float setpoint;
int output_power;
} SystemState;
// 全局系统状态
SystemState system_state = {
.is_connected = 0,
.device_status = 0,
.temperature = 25.0f,
.setpoint = 22.0f,
.output_power = 0
};
// 命令: help
int cmd_help(int argc, char* argv[]);
// 命令: connect
int cmd_connect(int argc, char* argv[]) {
if (system_state.is_connected) {
printf("Already connected\n");
return 0;
}
if (argc < 2) {
printf("Usage: connect <device>\n");
return -1;
}
printf("Connecting to %s...\n", argv[1]);
// 这里只是模拟连接
system_state.is_connected = 1;
system_state.device_status = 1;
printf("Connected successfully\n");
return 0;
}
// 命令: disconnect
int cmd_disconnect(int argc, char* argv[]) {
if (!system_state.is_connected) {
printf("Not connected\n");
return 0;
}
printf("Disconnecting...\n");
// 模拟断开连接
system_state.is_connected = 0;
system_state.device_status = 0;
printf("Disconnected\n");
return 0;
}
// 命令: status
int cmd_status(int argc, char* argv[]) {
printf("System Status:\n");
printf(" Connection: %s\n", system_state.is_connected ? "Connected" : "Disconnected");
if (system_state.is_connected) {
printf(" Device Status: %s\n", system_state.device_status ? "ON" : "OFF");
printf(" Temperature: %.1f°C\n", system_state.temperature);
printf(" Setpoint: %.1f°C\n", system_state.setpoint);
printf(" Output Power: %d%%\n", system_state.output_power);
}
return 0;
}
// 命令: set
int cmd_set(int argc, char* argv[]) {
if (!system_state.is_connected) {
printf("Error: Not connected\n");
return -1;
}
if (argc < 3) {
printf("Usage: set <parameter> <value>\n");
printf("Parameters: setpoint, power\n");
return -1;
}
if (strcmp(argv[1], "setpoint") == 0) {
float setpoint = atof(argv[2]);
if (setpoint < 10.0f || setpoint > 30.0f) {
printf("Error: Setpoint must be between 10.0 and 30.0\n");
return -1;
}
system_state.setpoint = setpoint;
printf("Setpoint set to %.1f°C\n", setpoint);
return 0;
}
else if (strcmp(argv[1], "power") == 0) {
int power = atoi(argv[2]);
if (power < 0 || power > 100) {
printf("Error: Power must be between 0 and 100\n");
return -1;
}
system_state.output_power = power;
printf("Output power set to %d%%\n", power);
return 0;
}
else {
printf("Unknown parameter: %s\n", argv[1]);
return -1;
}
}
// 命令: on
int cmd_on(int argc, char* argv[]) {
if (!system_state.is_connected) {
printf("Error: Not connected\n");
return -1;
}
if (system_state.device_status) {
printf("Device is already ON\n");
return 0;
}
printf("Turning device ON...\n");
system_state.device_status = 1;
return 0;
}
// 命令: off
int cmd_off(int argc, char* argv[]) {
if (!system_state.is_connected) {
printf("Error: Not connected\n");
return -1;
}
if (!system_state.device_status) {
printf("Device is already OFF\n");
return 0;
}
printf("Turning device OFF...\n");
system_state.device_status = 0;
system_state.output_power = 0;
return 0;
}
// 命令: simulate
int cmd_simulate(int argc, char* argv[]) {
if (!system_state.is_connected) {
printf("Error: Not connected\n");
return -1;
}
// 模拟温度变化
if (system_state.device_status) {
// 如果设备开启,温度会朝着设定值移动
if (system_state.temperature > system_state.setpoint) {
system_state.temperature -= 0.5f * (system_state.output_power / 100.0f);
} else {
system_state.temperature += 0.3f * (system_state.output_power / 100.0f);
}
} else {
// 如果设备关闭,温度会缓慢回到室温
if (system_state.temperature > 25.0f) {
system_state.temperature -= 0.2f;
} else if (system_state.temperature < 25.0f) {
system_state.temperature += 0.2f;
}
}
printf("Temperature updated to %.1f°C\n", system_state.temperature);
return 0;
}
// 命令: exit
int cmd_exit(int argc, char* argv[]) {
printf("Exiting...\n");
// 如果连接了,自动断开
if (system_state.is_connected) {
printf("Automatically disconnecting...\n");
cmd_disconnect(0, NULL);
}
return -100; // 特殊返回值表示退出
}
// 命令: help
int cmd_help(int argc, char* argv[]) {
printf("Available commands:\n");
printf(" help - Show this help message\n");
printf(" connect <device> - Connect to device\n");
printf(" disconnect - Disconnect from device\n");
printf(" status - Show system status\n");
printf(" set <param> <val>- Set parameter value (setpoint, power)\n");
printf(" on - Turn device ON\n");
printf(" off - Turn device OFF\n");
printf(" simulate - Simulate temperature change\n");
printf(" exit - Exit the program\n");
return 0;
}
// 命令表
Command commands[] = {
{"help", "Show available commands", cmd_help},
{"connect", "Connect to device", cmd_connect},
{"disconnect","Disconnect from device", cmd_disconnect},
{"status", "Show system status", cmd_status},
{"set", "Set parameter value", cmd_set},
{"on", "Turn device ON", cmd_on},
{"off", "Turn device OFF", cmd_off},
{"simulate", "Simulate temperature change", cmd_simulate},
{"exit", "Exit the program", cmd_exit},
{NULL, NULL, NULL} // 终止表
};
// 解析命令行
int parse_command(char* cmd_line, char* argv[]) {
int argc = 0;
char* token;
// 跳过前导空白
while (isspace(*cmd_line)) cmd_line++;
// 空行
if (*cmd_line == '\0') return 0;
// 解析命令参数
token = strtok(cmd_line, " \t\n\r");
while (token != NULL && argc < MAX_ARGS) {
argv[argc++] = token;
token = strtok(NULL, " \t\n\r");
}
return argc;
}
// 主命令循环
void command_loop() {
char cmd_line[MAX_CMD_LEN];
char* argv[MAX_ARGS];
int argc;
int i, cmd_found, result;
printf("Simple Command Line Interface\n");
printf("Type 'help' for available commands\n");
while (1) {
// 显示提示符
printf("> ");
fflush(stdout);
// 读取一行命令
if (fgets(cmd_line, sizeof(cmd_line), stdin) == NULL) {
break;
}
// 解析命令
argc = parse_command(cmd_line, argv);
if (argc == 0) continue; // 空行
// 查找命令
cmd_found = 0;
for (i = 0; commands[i].name != NULL; i++) {
if (strcmp(argv[0], commands[i].name) == 0) {
result = commands[i].func(argc, argv);
cmd_found = 1;
// 检查特殊退出代码
if (result == -100) {
return; // 退出程序
}
break;
}
}
// 命令未找到
if (!cmd_found) {
printf("Unknown command: %s\n", argv[0]);
printf("Type 'help' for available commands\n");
}
}
}
int main() {
command_loop();
return 0;
}
3. C++上位机开发基础
3.1 基于C++的简单上位机框架
cpp
/**
* upper_computer_framework.cpp - C++上位机基础框架
* 演示C++上位机的基本架构设计
*/
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <thread>
#include <mutex>
#include <chrono>
#include <condition_variable>
#include <atomic>
#include <fstream>
#include <ctime>
#include <iomanip>
#include <memory>
// 前向声明
class Device;
class DataProcessor;
class Logger;
class CommandHandler;
// 设备接口
class Device {
public:
Device() : connected_(false) {}
virtual ~Device() { disconnect(); }
virtual bool connect(const std::string& port, int baudRate) {
if (connected_) {
std::cout << "Already connected" << std::endl;
return true;
}
std::cout << "Connecting to " << port << " at " << baudRate << " baud..." << std::endl;
// 实际实现中需要打开设备
// 这里仅作演示,假设总是成功
connected_ = true;
devicePort_ = port;
baudRate_ = baudRate;
std::cout << "Connected successfully" << std::endl;
return true;
}
virtual void disconnect() {
if (!connected_) return;
std::cout << "Disconnecting..." << std::endl;
// 实际实现中需要关闭设备
connected_ = false;
std::cout << "Disconnected" << std::endl;
}
virtual bool isConnected() const {
return connected_;
}
virtual bool sendCommand(const std::string& command) {
if (!connected_) {
std::cerr << "Error: Not connected" << std::endl;
return false;
}
std::cout << "Sending command: " << command << std::endl;
// 实际实现中需要向设备发送命令
// 这里仅作演示
lastCommand_ = command;
return true;
}
virtual std::string receiveData(int timeout_ms = 1000) {
if (!connected_) {
std::cerr << "Error: Not connected" << std::endl;
return "";
}
// 实际实现中需要从设备接收数据
// 这里仅作演示,返回模拟数据
std::string response = "TEMP=24.5,HUMIDITY=48.2,PRESSURE=1012.3";
std::cout << "Received data: " << response << std::endl;
return response;
}
protected:
bool connected_;
std::string devicePort_;
int baudRate_;
std::string lastCommand_;
};
// 数据存储结构
struct SensorData {
double temperature;
double humidity;
double pressure;
std::chrono::system_clock::time_point timestamp;
SensorData() : temperature(0.0), humidity(0.0), pressure(0.0),
timestamp(std::chrono::system_clock::now()) {}
std::string toString() const {
std::time_t time = std::chrono::system_clock::to_time_t(timestamp);
std::tm tm = *std::localtime(&time);
std::stringstream ss;
ss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << " | ";
ss << "Temperature: " << temperature << "°C, ";
ss << "Humidity: " << humidity << "%, ";
ss << "Pressure: " << pressure << " hPa";
return ss.str();
}
};
// 数据处理器
class DataProcessor {
public:
DataProcessor() : running_(false) {}
~DataProcessor() { stop(); }
void process(const std::string& rawData) {
// 解析原始数据
SensorData data;
parseData(rawData, data);
// 添加到数据队列
{
std::lock_guard<std::mutex> lock(dataMutex_);
dataQueue_.push_back(data);
// 限制队列大小
if (dataQueue_.size() > 1000) {
dataQueue_.erase(dataQueue_.begin());
}
}
// 通知等待的线程
dataCondition_.notify_all();
}
void start() {
if (running_) return;
running_ = true;
processorThread_ = std::thread(&DataProcessor::processingLoop, this);
}
void stop() {
if (!running_) return;
running_ = false;
dataCondition_.notify_all();
if (processorThread_.joinable()) {
processorThread_.join();
}
}
const std::vector<SensorData>& getDataHistory() const {
return dataQueue_;
}
// 注册回调函数,当有新数据处理完成时调用
void registerCallback(std::function<void(const SensorData&)> callback) {
dataCallback_ = callback;
}
private:
void parseData(const std::string& rawData, SensorData& data) {
// 简单的数据解析,实际应用中可能需要更复杂的解析器
data.timestamp = std::chrono::system_clock::now();
size_t temp_pos = rawData.find("TEMP=");
size_t humi_pos = rawData.find("HUMIDITY=");
size_t pres_pos = rawData.find("PRESSURE=");
if (temp_pos != std::string::npos) {
size_t end_pos = rawData.find(',', temp_pos);
if (end_pos == std::string::npos) end_pos = rawData.length();
std::string temp_str = rawData.substr(temp_pos + 5, end_pos - temp_pos - 5);
data.temperature = std::stod(temp_str);
}
if (humi_pos != std::string::npos) {
size_t end_pos = rawData.find(',', humi_pos);
if (end_pos == std::string::npos) end_pos = rawData.length();
std::string humi_str = rawData.substr(humi_pos + 9, end_pos - humi_pos - 9);
data.humidity = std::stod(humi_str);
}
if (pres_pos != std::string::npos) {
size_t end_pos = rawData.find(',', pres_pos);
if (end_pos == std::string::npos) end_pos = rawData.length();
std::string pres_str = rawData.substr(pres_pos + 9, end_pos - pres_pos - 9);
data.pressure = std::stod(pres_str);
}
}
void processingLoop() {
while (running_) {
SensorData latestData;
bool hasData = false;
// 等待新数据或停止信号
{
std::unique_lock<std::mutex> lock(dataMutex_);
dataCondition_.wait_for(lock, std::chrono::seconds(1),
[this] { return !running_ || !dataQueue_.empty(); });
if (!running_) break;
if (!dataQueue_.empty()) {
latestData = dataQueue_.back();
hasData = true;
}
}
// 处理数据
if (hasData && dataCallback_) {
// 调用回调函数
dataCallback_(latestData);
}
}
}
private:
std::vector<SensorData> dataQueue_;
std::mutex dataMutex_;
std::condition_variable dataCondition_;
std::atomic<bool> running_;
std::thread processorThread_;
std::function<void(const SensorData&)> dataCallback_;
};
// 日志记录器
class Logger {
public:
enum class LogLevel {
DEBUG,
INFO,
WARNING,
ERROR
};
Logger(const std::string& filename = "upper_computer.log") {
logFile_.open(filename, std::ios::out | std::ios::app);
if (!logFile_.is_open()) {
std::cerr << "Failed to open log file: " << filename << std::endl;
}
}
~Logger() {
if (logFile_.is_open()) {
logFile_.close();
}
}
void log(LogLevel level, const std::string& message) {
std::lock_guard<std::mutex> lock(logMutex_);
// 获取当前时间
auto now = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(now);
std::tm tm = *std::localtime(&time);
// 格式化日志消息
std::stringstream ss;
ss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << " ";
switch (level) {
case LogLevel::DEBUG: ss << "[DEBUG] "; break;
case LogLevel::INFO: ss << "[INFO] "; break;
case LogLevel::WARNING: ss << "[WARNING] "; break;
case LogLevel::ERROR: ss << "[ERROR] "; break;
}
ss << message;
// 输出到控制台
std::cout << ss.str() << std::endl;
// 写入到日志文件
if (logFile_.is_open()) {
logFile_ << ss.str() << std::endl;
logFile_.flush();
}
}
void debug(const std::string& message) {
log(LogLevel::DEBUG, message);
}
void info(const std::string& message) {
log(LogLevel::INFO, message);
}
void warning(const std::string& message) {
log(LogLevel::WARNING, message);
}
void error(const std::string& message) {
log(LogLevel::ERROR, message);
}
private:
std::ofstream logFile_;
std::mutex logMutex_;
};
// 命令处理器
class CommandHandler {
public:
using CommandFunc = std::function<bool(const std::vector<std::string>&)>;
CommandHandler(std::shared_ptr<Device> device,
std::shared_ptr<DataProcessor> processor,
std::shared_ptr<Logger> logger)
: device_(device), processor_(processor), logger_(logger) {
// 注册内置命令
registerCommand("connect", [this](const std::vector<std::string>& args) -> bool {
if (args.size() < 2) {
logger_->error("Usage: connect <port> [baudrate]");
return false;
}
int baudRate = 9600; // 默认波特率
if (args.size() > 2) {
baudRate = std::stoi(args[2]);
}
return device_->connect(args[1], baudRate);
});
registerCommand("disconnect", [this](const std::vector<std::string>& args) -> bool {
device_->disconnect();
return true;
});
registerCommand("send", [this](const std::vector<std::string>& args) -> bool {
if (args.size() < 2) {
logger_->error("Usage: send <command>");
return false;
}
std::string cmd = args[1];
for (size_t i = 2; i < args.size(); i++) {
cmd += " " + args[i];
}
return device_->sendCommand(cmd);
});
registerCommand("read", [this](const std::vector<std::string>& args) -> bool {
int timeout = 1000; // 默认超时1秒
if (args.size() > 1) {
timeout = std::stoi(args[1]);
}
std::string data = device_->receiveData(timeout);
if (!data.empty()) {
processor_->process(data);
return true;
}
return false;
});
registerCommand("status", [this](const std::vector<std::string>& args) -> bool {
logger_->info("Device status: " +
std::string(device_->isConnected() ? "Connected" : "Disconnected"));
// 显示最近数据
const auto& history = processor_->getDataHistory();
if (!history.empty()) {
logger_->info("Latest data: " + history.back().toString());
} else {
logger_->info("