我正在创建一个继承std::streambuf
的类(异步写入UART)。每当持有std::ostream
streambuf
的{{1}}向其写入字符时,我都需要能够在课堂上讲话(因此我可以启用“写入就绪”中断并实际写入数据)。我的印象是我只需要覆盖xsputn()
,但似乎没有被调用。
我可以:
std::endl
来呼叫std::streambuf::sync()
(阻止,丑陋)std::ostream
(很多工作)从设计的角度来看,做到这一点的“正确”方法是什么?
代码:
#include <algorithm>
#include <ostream>
extern "C" void UART0_IRQHandler(void);
#define UART_BUFLEN 128
class uartbuf : public std::streambuf
{
public:
uartbuf(/*hardware stuff*/);
~uartbuf() {};
protected:
int sync();
std::streambuf::int_type overflow(std::streambuf::int_type ch);
std::streamsize xsputn(const char* s, std::streamsize count);
private:
UART_MemMapPtr regs;
char buffer[UART_BUFLEN];
uint8_t fifo_depth;
bool empty() {return pbase() == pptr();}
uint8_t fifo_space() {return /*hardware stuff*/;}
void adjust();
void write_some();
uartbuf(const uartbuf&);
friend void UART0_IRQHandler(void);
friend void UART_Init();
};
//global instances
uartbuf uart0_sb(/*hardware stuff*/);
std::ostream uart0(&uart0_sb);
//buffer management...
uartbuf::uartbuf(/*hardware stuff*/)
: regs(r), fifo_depth(1)
{
setp(buffer, buffer, buffer + UART_BUFLEN);
//A bunch of hardware setup
}
//move back to the start of the buffer
void uartbuf::adjust()
{
if (pbase() == buffer)
return;
//move unwritten characters to beginning of buffer
std::copy(pbase(), pptr(), buffer);
//(pptr - pbase) stays the same, same number of characters
setp(buffer, buffer + (pptr() - pbase()), epptr());
}
//flush the entire buffer
int uartbuf::sync()
{
while (!empty())
write_some();
return 0; //always succeeds
}
std::streambuf::int_type uartbuf::overflow(std::streambuf::int_type ch)
{
//entirely full, can't adjust yet
if (pbase() == buffer)
write_some();
adjust();
//this is guaranteed to not call overflow again
if (ch != std::streambuf::traits_type::eof())
sputc(ch);
return 1; //always succeeds
}
//hardware management...
//writes at least one character
void uartbuf::write_some()
{
//spin until there is some room
while(!fifo_space()) ;
while(!empty() && fifo_space())
{
//clear interrupt flag
clear_interrupt();
write_char_to_fifo(*pbase());
setp(pbase() + 1, pptr(), epptr());
}
//don't generate any more TDRE interrupts if the buffer is empty
if (empty())
turn_off_interrupt();
}
std::streamsize uartbuf::xsputn(const char* s, std::streamsize count)
{
//don't need to do anything special with the data
std::streamsize result = std::streambuf::xsputn(s, count);
//start the TDRE interrupt cycling
turn_on_interrupt();
return result;
}
extern "C" void UART0_IRQHandler(void)
{
//it's a TDRE interrupt
if (/*it's the interrupt we want*/)
uart0_sb.write_some(); //this won't block
}
答案 0 :(得分:1)
您需要覆盖overflow()
,而不是其他任何内容。上
初始化,std::streambuf
设置缓冲区指针
nullptr
;如果你不积极改变这一点,overflow
将是。setp
要求输出的每个字符。 (您使用sync
来
设置缓冲区。)
是否要为每个角色激活输入, 我不知道。你提到&#34; asynchrously写&#34;在一个点上。 这表明不止一个缓冲区。在{{1}}中,您将开始 当前缓冲区的输出,并设置使用 下一个。在某些时候,你还需要检查一下 异步输出已经完成,以便回收 缓冲。