使用标准 C++ fstream 在串行设备 (/dev/ttyGS0) 上读写?
Read & write on serial device (/dev/ttyGS0) with standard C++ fstream?
我想使用标准 C++ fstream 从串行端口 (/dev/ttyGS0) 读取和写入数据 class。
两个小时前我认为这是一个微不足道的任务(它只是一个文件(好吧,它是一个特殊的......)),直到写入串口引发错误并且 perror() 揭示了一个 "Illegal seek"。进一步调查显示 /dev/ttyGS0(与每个串行设备一样)是一个不可搜索的文件,这可能导致了错误。
如何使用标准 C++ 库写入串行端口?
完全有可能还是我必须回退到像 open() 这样的 C 函数或使用像 LibSerial 这样的附加库?
同时,我自己想出了一个解决办法。
简短回答:使用标准 C++ 库读取或写入不可搜索的设备并非易事。
长答案:可以通过从 std::filebuf 派生并更改实现来实现。理论上其实很简单,因为只需要在函数std::filebuf::_M_seek.[=13=中注释掉一行代码]
实际上并没有这么简单,因为std::filebuf::_M_seek本身不是虚拟的,也就是说在派生中不能被覆盖class。幸运的是,它(在这种情况下)仅被另一个虚拟函数 std::filebuf::overflow 使用。
所以这是我的 class 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++ 实现复制的。由于版权原因,我还发布了原始文件的header。
您可以轻松找到被注释掉的一行 - 这是 "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;
}
下面是如何使用 class 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();
希望这对您有所帮助 - 祝您好运!
我想使用标准 C++ fstream 从串行端口 (/dev/ttyGS0) 读取和写入数据 class。
两个小时前我认为这是一个微不足道的任务(它只是一个文件(好吧,它是一个特殊的......)),直到写入串口引发错误并且 perror() 揭示了一个 "Illegal seek"。进一步调查显示 /dev/ttyGS0(与每个串行设备一样)是一个不可搜索的文件,这可能导致了错误。
如何使用标准 C++ 库写入串行端口?
完全有可能还是我必须回退到像 open() 这样的 C 函数或使用像 LibSerial 这样的附加库?
同时,我自己想出了一个解决办法。
简短回答:使用标准 C++ 库读取或写入不可搜索的设备并非易事。
长答案:可以通过从 std::filebuf 派生并更改实现来实现。理论上其实很简单,因为只需要在函数std::filebuf::_M_seek.[=13=中注释掉一行代码]
实际上并没有这么简单,因为std::filebuf::_M_seek本身不是虚拟的,也就是说在派生中不能被覆盖class。幸运的是,它(在这种情况下)仅被另一个虚拟函数 std::filebuf::overflow 使用。
所以这是我的 class 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++ 实现复制的。由于版权原因,我还发布了原始文件的header。
您可以轻松找到被注释掉的一行 - 这是 "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;
}
下面是如何使用 class 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();
希望这对您有所帮助 - 祝您好运!