#pragma once

#include <I2C_Interface.hpp>
#include <cstdint>
#include <cstdlib>
#include <STM32DMA.hpp>
#include <Timer_Interface.hpp>
#include "STM32_I2C_Definitions.hpp"


/** Blocking I2C Master Implementation
 *
 * The current implementation does not support SMBus.
 *
 * This version of the I2C driver blocks, rather than using interrupts or DMA.
 *
 * The I2C driver will handle its specific configuration, address assignment, interrupt handlers,
 * and starting/stopping of the driver internally.
 *
 * @see STM32DMA
 */
class STM32I2CMaster final : public I2C
{
  public:
	explicit STM32I2CMaster(STM32I2C::device dev,
			STM32I2C::baud baudrate = STM32I2C::baud::standard,
			STM32I2C::pullups pull = STM32I2C::pullups::external) noexcept
		: device_(dev), pull_setting_(pull), baudrate_(baudrate)
	{
	}
	~STM32I2CMaster() noexcept = default;

	/// Start the device, turning it on and configuring it
	/// @pre The device is stopped
	void start() noexcept final;

	/// Stop the device, turning it off and de-initializing it
	/// @pre The device is started
	void stop() noexcept final;

	/// Configure the device to use internal or external pullups.
	/// By default, the driver assumes external pullups
	/// @pre The driver is stopped
	///		The changes are only applied during start(), so this function
	///		can only be invoked when the driver is stopped.
	void setPullups(STM32I2C::pullups setting) noexcept;

	/// Set the baudrate for the I2C bus.
	///
	/// @param in baud The requested baudrate.
	/// @pre The driver is stopped
	///		The changes are only applied during start(), so this function
	///		can only be invoked when the driver is stopped.
	void baudrate(STM32I2C::baud baud) noexcept;

	I2C::status transfer(I2C::op_t& op,
						 const I2C::cb_t& cb) noexcept final;

private:

  private:
	const STM32I2C::device device_;
	bool started_ = false;
	bool busy_ = false;
	I2C::op_t active_op_{};
	STM32I2C::pullups pull_setting_ = STM32I2C::pullups::external;
	STM32I2C::baud baudrate_ = STM32I2C::baud::standard;
};
