#ifndef LINUX_OBC_PTME_H_
#define LINUX_OBC_PTME_H_

#include <fsfw_hal/common/gpio/gpioDefinitions.h>
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>

#include <cstring>
#include <unordered_map>

#include "OBSWConfig.h"
#include "fsfw/returnvalues/returnvalue.h"
#include "linux/obc/PtmeIF.h"
#include "linux/obc/VcInterfaceIF.h"

/**
 * @brief   This class handles the interfacing to the telemetry (PTME) IP core responsible for the
 *          encoding of telemetry packets according to the CCSDS standards CCSDS 131.0-B-3 (TM
 * Synchro- nization and channel coding) and CCSDS 132.0-B-2 (TM Space Data Link Protocoll). The IP
 * cores are implemented on the programmable logic and are accessible through the linux UIO driver.
 */
class Ptme : public PtmeIF, public SystemObject {
 public:
  using VcId_t = uint8_t;

  /**
   * @brief   Constructor
   *
   * @param objectId
   */
  Ptme(object_id_t objectId);
  virtual ~Ptme();

  ReturnValue_t initialize() override;
  ReturnValue_t writeToVc(uint8_t vcId, const uint8_t* data, size_t size) override;

  /**
   * @brief   This function adds the reference to a virtual channel interface to the vcInterface
   *          map.
   */
  void addVcInterface(VcId_t vcId, VcInterfaceIF* vc);

 private:
  static const uint8_t INTERFACE_ID = CLASS_ID::PTME;

  static const ReturnValue_t UNKNOWN_VC_ID = MAKE_RETURN_CODE(0xA0);

  /**
   * Configuration bits:
   * bit[1:0]: Size of data (1,2,3 or 4 bytes). 1 Byte <=> b00
   * bit[2]: Set this bit to 1 to abort a transfered packet
   * bit[3]: Signals to PTME the start of a new telemetry packet
   */
  static const uint32_t PTME_CONFIG_START = 0x8;

  /**
   * Writing this word to the ptme base address signals to the PTME that a complete tm packet has
   * been transferred.
   */
  static const uint32_t PTME_CONFIG_END = 0x0;

  /**
   * Writing to this offset within the PTME memory space will insert data for encoding to the
   * PTME IP core.
   * The address offset is 0x400 (= 4 * 256)
   */
  static const int PTME_DATA_REG_OFFSET = 256;

  /** The file descriptor of the UIO driver */
  int fd = 0;

  uint32_t* ptmeBaseAddress = nullptr;

  using VcInterfaceMap = std::unordered_map<VcId_t, VcInterfaceIF*>;
  using VcInterfaceMapIter = VcInterfaceMap::iterator;

  VcInterfaceMap vcInterfaceMap;
};

#endif /* LINUX_OBC_PTME_H_ */