#ifndef BSP_Q7S_XADC_XADC_H_
#define BSP_Q7S_XADC_XADC_H_

#include <string>

#include "fsfw/returnvalues/HasReturnvaluesIF.h"

namespace xadc {
using namespace std;
static const string iioPath = "/sys/bus/iio/devices/iio:device1";
namespace file {
static const string tempOffset = iioPath + "/in_temp0_offset";
static const string tempRaw = iioPath + "/in_temp0_raw";
static const string tempScale = iioPath + "/in_temp0_scale";
static const string vccintRaw = iioPath + "/in_voltage0_vccint_raw";
static const string vccintScale = iioPath + "/in_voltage0_vccint_scale";
static const string vccauxRaw = iioPath + "/in_voltage1_vccaux_raw";
static const string vccauxScale = iioPath + "/in_voltage1_vccaux_scale";
static const string vccbramRaw = iioPath + "/in_voltage2_vccbram_raw";
static const string vccbramScale = iioPath + "/in_voltage2_vccbram_scale";
static const string vccpintRaw = iioPath + "/in_voltage3_vccpint_raw";
static const string vccpintScale = iioPath + "/in_voltage3_vccpint_scale";
static const string vccpauxRaw = iioPath + "/in_voltage4_vccpaux_raw";
static const string vccpauxScale = iioPath + "/in_voltage4_vccpaux_scale";
static const string vccoddrRaw = iioPath + "/in_voltage5_vccoddr_raw";
static const string vccoddrScale = iioPath + "/in_voltage5_vccoddr_scale";
static const string vrefpRaw = iioPath + "/in_voltage6_vrefp_raw";
static const string vrefpScale = iioPath + "/in_voltage6_vrefp_scale";
static const string vrefnRaw = iioPath + "/in_voltage7_vrefn_raw";
static const string vrefnScale = iioPath + "/in_voltage7_vrefn_scale";
}  // namespace file
}  // namespace xadc

/**
 * @brief   Class providing access to the data generated by the analog mixed signal module (XADC).
 *
 * @details Details about the XADC peripheral of the Zynq-7020 can be found in the UG480 "7-Series
 *          FPGAs and Zynq-7000 SoC XADC Dual 12-Bit 1 MSPS Analog-to-Digital Converter" user guide
 *          from Xilinx.
 *
 * @author  J. Meier
 */
class Xadc {
 public:
  /**
   * @brief Constructor
   */
  Xadc();
  virtual ~Xadc();

  /**
   * @brief Returns on-chip temperature degree celcius
   */
  ReturnValue_t getTemperature(float& temperature);

  /**
   * @brief Returns PS internal logic supply voltage in millivolts
   */
  ReturnValue_t getVccPint(float& vccPint);

  /**
   * @brief Returns PS auxiliary supply voltage in millivolts
   */
  ReturnValue_t getVccPaux(float& vccPaux);

  /**
   * @brief Returns PL internal supply voltage in millivolts
   */
  ReturnValue_t getVccInt(float& vccInt);

  /**
   * @brief Returns PL auxiliary supply voltage in millivolts
   */
  ReturnValue_t getVccAux(float& vccAux);

  /**
   * @brief Returns PL block RAM supply voltage in millivolts
   */
  ReturnValue_t getVccBram(float& vccBram);

  /**
   * @brief Returns the PS DDR I/O supply voltage
   */
  ReturnValue_t getVccOddr(float& vcOddr);

  /**
   * @brief Returns XADC reference input voltage relative to GND in millivolts
   */
  ReturnValue_t getVrefp(float& vrefp);

  /**
   * @brief Returns negative reference input voltage. Should normally be 0 V.
   */
  ReturnValue_t getVrefn(float& vrefn);

 private:
  // Maximum length of the string representation of a value in a xadc sysfs file
  static const uint8_t MAX_STR_LENGTH = 15;

  ReturnValue_t readVoltageFromSysfs(std::string rawFile, std::string scaleFile, float& voltage);

  float calculateVoltage(int raw, float scale);

  template <typename T>
  ReturnValue_t readValFromFile(const char* filename, T& val);
};

#endif /* BSP_Q7S_XADC_XADC_H_ */