上位机(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

#include

#include

#ifdef _WIN32

#include

#else

#include

#include

#include

#include

#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

#include

#include

#include

#ifdef _WIN32

#include

#define sleep_ms(ms) Sleep(ms)

#else

#include

#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

#include

#include

#include

#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 \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 \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 - Connect to device\n");

printf(" disconnect - Disconnect from device\n");

printf(" status - Show system status\n");

printf(" set - 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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

// 前向声明

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 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& getDataHistory() const {

return dataQueue_;

}

// 注册回调函数,当有新数据处理完成时调用

void registerCallback(std::function 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 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 dataQueue_;

std::mutex dataMutex_;

std::condition_variable dataCondition_;

std::atomic running_;

std::thread processorThread_;

std::function 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 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&)>;

CommandHandler(std::shared_ptr device,

std::shared_ptr processor,

std::shared_ptr logger)

: device_(device), processor_(processor), logger_(logger) {

// 注册内置命令

registerCommand("connect", [this](const std::vector& args) -> bool {

if (args.size() < 2) {

logger_->error("Usage: connect [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& args) -> bool {

device_->disconnect();

return true;

});

registerCommand("send", [this](const std::vector& args) -> bool {

if (args.size() < 2) {

logger_->error("Usage: send ");

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& 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& 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(