#ifndef LINUX_OBC_AXIPTMECONFIG_H_
#define LINUX_OBC_AXIPTMECONFIG_H_

#include <string>

#include "fsfw/ipc/MutexIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/returnvalues/returnvalue.h"

/**
 * @brief   Class providing low level access to the configuration interface of the PTME.
 *
 * @author  J. Meier
 */
class AxiPtmeConfig : public SystemObject {
 public:
  /**
   * @brief   Constructor
   * @param axiUio    Device file of UIO belonging to the AXI configuration interface.
   * @param mapNum    Number of map belonging to axi configuration interface.
   */
  AxiPtmeConfig(object_id_t objectId, std::string axiUio, int mapNum);
  virtual ~AxiPtmeConfig();

  virtual ReturnValue_t initialize() override;
  /**
   * @brief Will write to the bitrate configuration register. Actual generated rate depends on
   *        frequency of the clock connected to the bit clock input of PTME.
   */
  ReturnValue_t writeCaduRateReg(uint8_t rateVal);

  /**
   * @brief Next to functions control the tx clock manipulator component
   *
   * @details   If the tx clock manipulator is enabled the output clock of the PTME is manipulated
   *            in a way that both high and low periods in the clock signal have equal lengths.
   *            The default implementation of the PTME generates a clock where the high level is
   *            only one bit clock period long. This might be too short to match the setup and hold
   *            times of the S-and transceiver.
   *            Default: Enables TX clock manipulator
   *
   */
  ReturnValue_t enableTxclockManipulator();
  ReturnValue_t disableTxclockManipulator();

  /**
   * @brief The next to functions control whether data will be updated on the rising or falling edge
   *        of the tx clock.
   *        Enable inversion will update data on falling edge (not the configuration required by the
   *        syrlinks)
   *        Disable clock inversion. Data updated on rising edge.
   *        Default: Inversion is disabled
   */
  ReturnValue_t enableTxclockInversion();
  ReturnValue_t disableTxclockInversion();

 private:
  // Address of register storing the bitrate configuration parameter
  static const uint32_t CADU_BITRATE_REG = 0x0;
  // Address of register storing common configuration parameters
  static const uint32_t COMMON_CONFIG_REG = 0x4;
  static const uint32_t ADRESS_DIVIDER = 4;

  enum class BitPos : uint32_t { EN_TX_CLK_MANIPULATOR, INVERT_CLOCK };

  std::string axiUio;
  std::string uioMap;
  int mapNum = 0;
  MutexIF* mutex = nullptr;
  MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
  uint32_t mutexTimeout = 20;

  uint32_t* baseAddress = nullptr;

  /**
   * @brief Function to write to configuration registers
   *
   * @param writeVal    Value to write
   */
  ReturnValue_t writeReg(uint32_t regOffset, uint32_t writeVal);

  /**
   * @brief Reads value from configuration register
   *
   * @param regOffset   Offset of register from base address to read from
   * Qparam readVal     Pointer to variable where read value will be written to
   */
  ReturnValue_t readReg(uint32_t regOffset, uint32_t* readVal);

  /**
   * @brief Sets one bit in a register
   *
   * @param regOffset    Offset of the register where to set the bit
   * @param bitVal       The value of the bit to set (1 or 0)
   * @param bitPos       The position of the bit within the register to set
   *
   * @return             returnvalue::OK if successful, otherwise returnvalue::FAILED
   */
  ReturnValue_t writeBit(uint32_t regOffset, bool bitVal, BitPos bitPos);
};

#endif /* LINUX_OBC_AXIPTMECONFIG_H_ */