读,使用标准c++ fstream在串行设备(/dev/ttyGS0)上编写

Read & write on serial device (/dev/ttyGS0) with standard C++ fstream?

本文关键字:dev ttyGS0 标准 c++ fstream      更新时间:2023-10-16

我想使用标准c++ fstream类从串行端口(/dev/ttyGS0)读取和写入数据。

我认为这是一个微不足道的任务(它只是一个文件(好吧,它是一个特殊的…)),直到写入串行端口引发了一个错误,perror()显示了一个"非法查找"。进一步调查发现/dev/ttygs0(像每个串行设备一样)是一个不可搜索的文件,这可能导致错误。

如何使用标准c++库写入串行端口?

它可能在所有或我必须回落到C函数,如open()或使用LibSerial等额外的库?

与此同时,我自己想出了一个解决办法。

简短的回答:使用标准c++库从不可寻的设备中读取或写入数据并不是一件简单的事情。

长话短说:从std::filebuf派生并更改实现是可能的。理论上,它实际上非常简单,因为在函数std::filebuf::_M_seek中只需要注释掉一行代码。实际上,

并没有这么简单,因为std::filebuf::_M_seek本身不是虚拟的,这意味着它不能在派生类中被覆盖。幸运的是,它(在这种情况下)仅由另一个函数std::filebuf::overflow使用,该函数是虚拟的。

所以这是我的类FilebufNoSeek它可以用于访问不可寻的设备:

/*
 * filebufNoSeek.hpp
 */
#ifndef INCLUDE_SYSTEMIO_FILEBUFNOSEEK_HPP_
#define INCLUDE_SYSTEMIO_FILEBUFNOSEEK_HPP_
#include <fstream>
using namespace std;

class FilebufNoSeek : public filebuf
{
public:
    FilebufNoSeek() {};
protected:
    filebuf::pos_type _M_seek(filebuf::off_type __off, ios_base::seekdir __way, filebuf::__state_type __state);
    virtual filebuf::int_type overflow(filebuf::int_type __c);
};

#endif /* INCLUDE_SYSTEMIO_FILEBUFNOSEEK_HPP_ */

这个实现是100%从我在gcc源代码中找到的libstdc++实现复制的。出于版权原因,我还发布了原始文件的头文件。

你可以很容易地发现那一行被注释掉了——这就是"illegal seek"错误的来源。

// File based streams -*- C++ -*-
// Copyright (C) 1997-2014 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.
/** @file bits/fstream.tcc
 *  This is an internal header file, included by other library headers.
 *  Do not attempt to use it directly. @headername{fstream}
 */
/*
 * FilebufNoSeek.cpp
 *
 *  Created / copied / modified on: 21.12.2015 by ChristophK
 */
#include "FilebufNoSeek.hpp"

filebuf::pos_type FilebufNoSeek::_M_seek(filebuf::off_type __off, ios_base::seekdir __way, filebuf::__state_type __state)
{
    pos_type __ret = pos_type(off_type(-1));
    if (_M_terminate_output())
    {
//      off_type __file_off = _M_file.seekoff(__off, __way); // Causes "illegal seek"
        off_type __file_off = off_type(0); // New - no seek
        if (__file_off != off_type(-1))
        {
            _M_reading = false;
            _M_writing = false;
            _M_ext_next = _M_ext_end = _M_ext_buf;
            _M_set_buffer(-1);
            _M_state_cur = __state;
            __ret = __file_off;
            __ret.state(_M_state_cur);
        }
    }
    return __ret;
}

filebuf::int_type FilebufNoSeek::overflow(filebuf::int_type __c)
{
    int_type __ret = traits_type::eof();
    const bool __testeof = traits_type::eq_int_type(__c, __ret);
    const bool __testout = (_M_mode & ios_base::out
            || _M_mode & ios_base::app);
    if (__testout)
    {
        if (_M_reading)
        {
            _M_destroy_pback();
            const int __gptr_off = _M_get_ext_pos(_M_state_last);
            if (_M_seek(__gptr_off, ios_base::cur, _M_state_last)
                    == pos_type(off_type(-1)))
                return __ret;
        }
        if (this->pbase() < this->pptr())
        {
            // If appropriate, append the overflow char.
            if (!__testeof)
            {
                *this->pptr() = traits_type::to_char_type(__c);
                this->pbump(1);
            }
            // Convert pending sequence to external representation,
            // and output.
            if (_M_convert_to_external(this->pbase(),
                    this->pptr() - this->pbase()))
            {
                _M_set_buffer(0);
                __ret = traits_type::not_eof(__c);
            }
        }
        else if (_M_buf_size > 1)
        {
            // Overflow in 'uncommitted' mode: set _M_writing, set
            // the buffer to the initial 'write' mode, and put __c
            // into the buffer.
            _M_set_buffer(0);
            _M_writing = true;
            if (!__testeof)
            {
                *this->pptr() = traits_type::to_char_type(__c);
                this->pbump(1);
            }
            __ret = traits_type::not_eof(__c);
        }
        else
        {
            // Unbuffered.
            char_type __conv = traits_type::to_char_type(__c);
            if (__testeof || _M_convert_to_external(&__conv, 1))
            {
                _M_writing = true;
                __ret = traits_type::not_eof(__c);
            }
        }
    }
    return __ret;
}
下面是如何使用类FilebufNoSeek。只需将它传递给std::iostream: 的构造函数
FilebufNoSeek serialFilebuf;
serialFilebuf.open("/dev/ttyGS0");
std::iostream serialStream(serialFilebuf);
serialStream << "I'm writing to a nonseekable file" << std::endl;
serialFilebuf.close();

希望这有助于-祝你好运!