#pragma once

#include <BellowsPosition_Interface.hpp>
#include <I2C_Interface.hpp>
#include <DevicePowerSwitch.hpp>

class LTC2493 final : public BellowsPosition
{
public:
	// Configuration type to indicate weather the measurement is differential (and which
	// pin is Positive (P), and which is Negative (N), or single-ended (measured relative
	// to COM pin.
	enum class ChannelConfig : uint8_t
	{
		DIFF_0P_1N = 0,
		DIFF_2P_3N,
		DIFF_0N_1P,
		DIFF_2N_3P,
		SINGLE_0P,
		SINGLE_2P,
		SINGLE_1P,
		SINGLE_3P
	};
	
	enum class FilterConfig : uint8_t
	{
		EN_50HZ_REJECTION = 0,
		EN_60HZ_REJECTION,
		EN_50HZ_60HZ_REJECTION
	};
	
	enum class SpeedConfig : uint8_t
	{
		SPEED_1X = 0,
		SPEED_2X		
	};
	
	struct ADC_Config_t
	{
		ChannelConfig chan;
		FilterConfig filt;
		SpeedConfig speed;
		
		float vRefPos_volts;	// GND reference voltage tied to REF+
		float vRefNeg_volts;	// GND reference voltage tied to REF-
	};
	
public:
	LTC2493(std::string id, I2C& i2c_bus, uint8_t i2c_address, DevicePowerSwitch& pwrSwitch, bellowsPosSensorCfg_t sensorCfg, ADC_Config_t adcCfg)
		: BellowsPosition(id, sensorCfg)
		, i2c_(i2c_bus)
		, sw_(pwrSwitch)
		, i2c_address_(i2c_address)
		, adcCfg_(adcCfg)
	{
	}
	~LTC2493()
	{
	}

	BellowPosError start() final;
	BellowPosError stop() final;
	BellowPosError sleep() final;

	// Update the device configuration after creation. By default, the device
	// is configured upon calling start(), 
	void updateConfig(bellowsPosSensorCfg_t sensorCfg, ADC_Config_t adcCfg)
	{
		sensorCfg_ = sensorCfg;
		adcCfg_ = adcCfg;
		
		// Need to send the new config to the device
		start();
	}

	// Request a measurement from the device. This is a BLOCKING CALL!
	// The measurement will be available via getMeasurement() after calling this.
	BellowPosError requestMeasurement() 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;
	}
	
	/// Check weather the inner bellows is within the min and max limits,
	/// which are specified in the config params.
	/// If takeNewMeasurement is ture, a new I2C call and measurement will
	/// be made, and the assesment will be based on the new data.
	/// If no call has been made to requestMeasurement(), a request will be made
	/// to ensure no undefined behavior.
	/// If the driver fails (i2c error), return false;
	bool isWithinLimits(bool takeNewMeasurement = false) final;
	
	// Bellows position specific conversions
	float counts2volts(const int32_t counts, const float refNegVolts, const float refPosVolts);
	float volts2bellowsPosition_mm(const float sensorVolts, const float slope, const float intercept);
	float bellowsPosition_mm2percent(const float pos, const float lowLim_mm, const float highLim_mm);

private:
	bool started_ = false;
	bool measurement_taken_since_start_;
	I2C& i2c_;
	DevicePowerSwitch& sw_;
	uint8_t i2c_address_;
	
	ADC_Config_t adcCfg_;
	
#ifdef SIM_PLATFORM
	Measurement get_fake_measurement();
#endif
};
	