本文介绍了拦截所有写入std :: streambuf的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个继承std::streambuf的类(以异步方式写入UART).每当拥有streambufstd::ostream向其写入字符时,我就必须能够在班级中告诉我(这样我就可以启用"write ready"中断并实际写入数据).我的印象是我只需要重写xsputn(),但这似乎没有被调用.

I am making a class that inherits std::streambuf (to asynchronously write to a UART). I need to be able to tell in my class whenever the std::ostream that holds the streambuf writes characters to it (so I can enable the "write ready" interrupt and actually write the data). I was under the impression that I just needed to override xsputn(), but that does not seem to get called.

我可以:

  • 使中断保持启用状态(效率低下)
  • 使用std::endl呼叫std::streambuf::sync()(阻塞,难看)
  • 暴露另一个函数以开始写入(非常难看)
  • 继承std::ostream(很多工作)
  • 还有其他事情
  • Keep the interrupt enabled (inefficient)
  • Use std::endl to call std::streambuf::sync() (blocking, ugly)
  • Expose another function to start the write (very ugly)
  • Inherit std::ostream (a lot of work)
  • Something else

从设计的角度来看,做到这一点的正确"方法是什么?

From a design standpoint, what is the "right" way to do this?

代码:

#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
}

推荐答案

您需要覆盖overflow(),仅此而已.在初始化时,std::streambuf将缓冲区指针设置为nullptr;如果您不主动更改此设置,则overflow将是要求输出的每个字符. (您使用setp设置缓冲区.)

You need to override overflow(), and nothing else. Oninitialization, std::streambuf sets the buffer pointers tonullptr; if you don't actively change this, overflow will becalled for every character which is output. (You use setp toset the buffer.)

是否要为每个字符激活输入,我不知道.您曾经提到异步写入".这将建议多个缓冲区.在sync中,您开始当前缓冲区的输出,并进行设置以使用下一个.在某些时候,您还需要检查异步输出已完成,以便回收缓冲.

Whether you want to activate input for every character or not,I don't know. You mention "asynchrously write" at one point.This would suggest more than one buffer. In sync, you startthe output for the current buffer, and set things up to use thenext. At some point, you will also need to check that theasynchronous output has finished, in order to recycle thebuffer.

这篇关于拦截所有写入std :: streambuf的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-15 03:49