c++中串口的安全封装使用

固定缓冲区大小:在这种情况下,你将缓冲区大小固定为4096字节。如果你的数据量可能超过这个限制,可能需要反复调用读取操作以确保读取完整的数据。

局部变量初始化:在C++中,局部变量如果不是内置类型(如int、char等),编译器会自动调用其默认构造函数进行初始化。对于内置类型,如果不显式初始化,它们的值是未定义的,可能包含任何内容。在你的代码中,buffer是一个字符数组,不需要显式初始化,因为你马上就会用::read函数把数据填充进去。

错误处理:::read函数可能会返回负值,以指示读取失败。你应该检查bytes_read是否为负值,并相应地处理错误情况。

字符串构造:如果::read返回负值,那么std::string(buffer, bytes_read)中的bytes_read将是负值,这会导致未定义行为。你需要确保bytes_read是非负的。

综合这些考虑,可以改进你的代码如下:

cpp

#include

#include

#include

#include <fcntl.h>

#include <unistd.h>

#include <termios.h>

#include

class ThreadSafeSerialPort {

public:

ThreadSafeSerialPort(const std::string& port_name, int baud_rate) {

fd_ = open(port_name.c_str(), O_RDWR | O_NOCTTY | O_SYNC);

if (fd_ < 0) {

throw std::runtime_error("Failed to open serial port");

}

    struct termios tty;
    memset(&tty, 0, sizeof tty);
    if (tcgetattr(fd_, &tty) != 0) {
        close(fd_);
        throw std::runtime_error("Failed to get terminal attributes");
    }

    cfsetospeed(&tty, baud_rate);
    cfsetispeed(&tty, baud_rate);

    tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
    tty.c_iflag &= ~IGNBRK; // disable break processing
    tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing
    tty.c_oflag = 0; // no remapping, no delays
    tty.c_cc[VMIN]  = 1; // read doesn't block
    tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout

    tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
    tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, enable reading
    tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CRTSCTS;

    if (tcsetattr(fd_, TCSANOW, &tty) != 0) {
        close(fd_);
        throw std::runtime_error("Failed to set terminal attributes");
    }
}

~ThreadSafeSerialPort() {
    close(fd_);
}

void write(const std::string& data) {
    std::lock_guard<std::mutex> guard(mutex_);
    ::write(fd_, data.c_str(), data.size());
}

std::string read() {
    std::lock_guard<std::mutex> guard(mutex_);
    const size_t buffer_size = 4096; // 设定一个固定的缓冲区大小
    char buffer[buffer_size];
    ssize_t bytes_read = ::read(fd_, buffer, buffer_size);
    if (bytes_read < 0) {
        throw std::runtime_error("Failed to read from serial port");
    }
    return std::string(buffer, bytes_read);
}

private:

int fd_;

std::mutex mutex_;

};

使用示例

cpp

#include

#include

int main() {

try {

// 创建线程安全的串口对象

ThreadSafeSerialPort serial_port("/dev/ttyUSB0", B9600);

    // 创建一个线程进行写操作
    std::thread writer([&]() {
        while (true) {
            std::string data_to_write = "Hello Serial\n";
            serial_port.write(data_to_write);
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    });

    // 创建另一个线程进行读操作
    std::thread reader([&]() {
        while (true) {
            try {
                std::string data_read = serial_port.read(); // 使用新的读取方法
                if (!data_read.empty()) {
                    std::cout << "Read: " << data_read << std::endl;
                }
            } catch (const std::exception& ex) {
                std::cerr << "Error: " << ex.what() << std::endl;
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
    });

    // 等待线程结束
    writer.join();
    reader.join();

} catch (const std::exception& ex) {
    std::cerr << "Error: " << ex.what() << std::endl;
}

return 0;

}

在上述代码中,我添加了对read函数返回值的检查,以确保没有发生错误。如果::read返回负值,我们将抛出一个异常,以指示读取失败。这种方式在多线程环境中能够更好地处理错误,并提高代码的健壮性。

相关推荐
PieroPc几秒前
Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
开发语言·python·excel
2401_857439693 小时前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna3 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
xlsw_3 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
Dream_Snowar4 小时前
速通Python 第三节
开发语言·python
唐诺4 小时前
几种广泛使用的 C++ 编译器
c++·编译器
高山我梦口香糖5 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
冷眼看人间恩怨5 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
信号处理学渣5 小时前
matlab画图,选择性显示legend标签
开发语言·matlab
红龙创客5 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++