我正在创建一个继承std::streambuf (异步写入UART)的类。当持有std::ostream的streambuf向它写入字符时,我需要能够在我的类中告诉它(这样我就可以启用“写就绪”中断并实际地写入数据)。我的印象是,我只需要覆盖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
}发布于 2014-04-25 15:51:33
您需要重写overflow(),而不需要其他任何东西。在初始化时,std::streambuf将缓冲区指针设置为nullptr;如果不主动更改,则将为输出的每个字符调用overflow。(使用setp设置缓冲区。)
你是否想激活每个字符的输入,我不知道。您曾经提到过“异步写入”。这意味着有一个以上的缓冲区。在sync中,启动当前缓冲区的输出,并将其设置为使用下一个缓冲区。在某个时候,您还需要检查异步输出是否已经完成,以便回收缓冲区。
https://stackoverflow.com/questions/23295693
复制相似问题