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返回负值,我们将抛出一个异常,以指示读取失败。这种方式在多线程环境中能够更好地处理错误,并提高代码的健壮性。

相关推荐
徐小黑ACG12 分钟前
GO语言 使用protobuf
开发语言·后端·golang·protobuf
0白露1 小时前
Apifox Helper 与 Swagger3 区别
开发语言
Tanecious.2 小时前
机器视觉--python基础语法
开发语言·python
叠叠乐2 小时前
rust Send Sync 以及对象安全和对象不安全
开发语言·安全·rust
Tttian6224 小时前
Python办公自动化(3)对Excel的操作
开发语言·python·excel
Merokes5 小时前
关于Gstreamer+MPP硬件加速推流问题:视频输入video0被占用
c++·音视频·rk3588
独好紫罗兰5 小时前
洛谷题单2-P5713 【深基3.例5】洛谷团队系统-python-流程图重构
开发语言·python·算法
闪电麦坤956 小时前
C#:base 关键字
开发语言·c#
Mason Lin6 小时前
2025年3月29日(matlab -ss -lti)
开发语言·matlab
请来次降维打击!!!6 小时前
优选算法系列(5.位运算)
java·前端·c++·算法