首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >拦截对std::streambuf的所有写入

拦截对std::streambuf的所有写入
EN

Stack Overflow用户
提问于 2014-04-25 14:16:46
回答 1查看 1.3K关注 0票数 2

我正在创建一个继承std::streambuf (异步写入UART)的类。当持有std::ostreamstreambuf向它写入字符时,我需要能够在我的类中告诉它(这样我就可以启用“写就绪”中断并实际地写入数据)。我的印象是,我只需要覆盖xsputn(),但似乎没有被调用。

我可以:

  • 保持中断启用(低效)
  • 使用std::endl调用std::streambuf::sync() (阻塞,丑陋)
  • 公开另一个函数以启动写入(非常难看)
  • 继承std::ostream (大量工作)
  • 一些其他的东西

从设计的角度来看,做这件事的“正确”方法是什么?

代码:

代码语言:javascript
复制
#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
}
EN

回答 1

Stack Overflow用户

发布于 2014-04-25 15:51:33

您需要重写overflow(),而不需要其他任何东西。在初始化时,std::streambuf将缓冲区指针设置为nullptr;如果不主动更改,则将为输出的每个字符调用overflow。(使用setp设置缓冲区。)

你是否想激活每个字符的输入,我不知道。您曾经提到过“异步写入”。这意味着有一个以上的缓冲区。在sync中,启动当前缓冲区的输出,并将其设置为使用下一个缓冲区。在某个时候,您还需要检查异步输出是否已经完成,以便回收缓冲区。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23295693

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档