#pragma once

#include <EnergyMonitor_Interface.hpp>
#include <I2C_Interface.hpp>

/* I2C Address Options
| LTC2946 I2C Address Assignment    | Value |   AD1    |   AD2    |
| :-------------------------------- | :---: | :------: | :------: |
| LTC2946_I2C_ADDRESS               | 0x67  |   High   |   Low    |
| LTC2946_I2C_ADDRESS               | 0x68  |   Float  |   High   |
| LTC2946_I2C_ADDRESS               | 0x69  |   High   |   High   |
| LTC2946_I2C_ADDRESS               | 0x6A  | 	Float  |   Float  |
| LTC2946_I2C_ADDRESS               | 0x6B  | 	Float  |   Low    |
| LTC2946_I2C_ADDRESS               | 0x6C  | 	Low    |   High   |
| LTC2946_I2C_ADDRESS               | 0x6D  | 	High   |   Float  |
| LTC2946_I2C_ADDRESS               | 0x6E  | 	Low    |   Float  |
| LTC2946_I2C_ADDRESS               | 0x6F  | 	Low    |   Low    |
*/

/**
 *
 * Internally, LSB weights are assigned. You may need to adjust these against a reference
 * source and adjust the LSBs to get to a precise measurement.
 *
 * Note that this implementation expects a blocking I2C driver, not a DMA-capable one.
 * If you want to use a DMA-capable one, you will need to adjust the implementation so that
 * in the interrupt handler, you update the latest_<Type>_ member variable and fire an event.
 *
 * You would need to adjust teh code in __LTC2946_LinearDriver.cpp that interacts with the I2C bus,
 * along with the LTC driver implementation (would need to pass callabck info into the internal
 * driver implementation. Or use a new implementation altogether.)
 */
class LTC2946 final : public EnergyMonitor
{
  public:
	/// Construct an LTC2946
	/// @param [in] id The name of this device
	/// @param [in] i2c_bus The I2C bus to use. This must be a blocking driver implementation.
	/// @param [in] i2c_address The I2C address of this device. Possible values are provided
	/// @param [in] resistor_val The value of the sense resitor - required for accurate conversions.
	///		On the demo board this is 0.02, but it needs to be tuned for the design
  /// @param [in] vin_scale Division ratio for resistive divider on the ADIN pin.
  ///		the default here is what is used in the demo app. It needs to be tuned based on the design.
	/// in a table above.
	LTC2946(std::string id, I2C& i2c_bus, uint8_t i2c_address, float resistor_val = 0.02f, float adin_scale = 1.113f) :
		EnergyMonitor(id), i2c_(i2c_bus), i2c_address_(i2c_address), resistor_val_(resistor_val), adin_scale_(adin_scale)
	{
	}
	~LTC2946()
	{
	}

	void start() override;
	void stop() override;

	bool requestCurrent() final;
	bool requestVoltage() final;

	/// This implementation expects a blocking I2C driver and will not
	/// behave properly if a DMA or interrupt-driven driver is used.
	bool isBlocking() final
	{
		return true;
	}

  private:
	bool started_ = false;
	I2C& i2c_;
	uint8_t i2c_address_;
	float resistor_val_;
	float adin_scale_;
};
