// intellectual property is bullshit bgdc

#ifndef BUFSERIAL_HPP
#define BUFSERIAL_HPP

#include <stdbool.h>
#include <stddef.h>
#include <inttypes.h>
#include <avrstuff/serial.hpp>
#include <avrstuff/ringbuf.hpp>

// Buffered interrupt-driven wrapper around a serial port. Transmit and receive
// are both optional - specify their buffer sizes as zero to omit.
template<unsigned Txsize, unsigned Rxsize>
class bufserial: public serial
{
public:
	virtual ~bufserial() = default;

	bufserial(serial & sp)
		: m_serial(&sp)
	{
		m_serial->rxcie(true);
	}

	// Receive Complete interrupt handler. Must be called from the relevant
	// vector if receive buffering is used.
	void rxc()
	{
		int c = m_serial->recv();
		m_rxbuf.push(c); // TODO what if it overflows?
	}

	// Data Register Empty interrupt handler. Must be called from the
	// relevant vector if transmit buffering is used.
	void dre()
	{
		int c;
		bool has_c = m_txbuf.pop(c);

		if (has_c)
			m_serial->send(c);
		else
			m_serial->dreie(false);
	}

	virtual int recv() override
	{
		int c;
		if (m_rxbuf.pop(c))
			return c;
		else
			return EOF;
	}

	virtual void send(int b) override
	{
		m_txbuf.push_wait(b);
		m_serial->dreie(true);
	}

private:
	serial * m_serial;
	ringbuf<int, Txsize> m_txbuf;
	ringbuf<int, Rxsize> m_rxbuf;
};

#endif // !defined(BUFSERIAL_HPP)
