#ifndef LINUX_OBC_PTME_H_
#define LINUX_OBC_PTME_H_

#include "OBSWConfig.h"
#include "linux/obc/PtmeIF.h"
#include "linux/obc/VcInterfaceIF.h"
#include <fsfw_hal/common/gpio/gpioDefinitions.h>
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>
#include "fsfw/returnvalues/HasReturnvaluesIF.h"

#include <cstring>
#include <unordered_map>

/**
 * @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 HasReturnvaluesIF {
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);

#if BOARD_TE0720 == 1
    /** Size of mapped address space */
    static const int MAP_SIZE = 0x40000;
#else
    /** Size of mapped address space */
    static const int MAP_SIZE = 0x40000;
#endif /* BOARD_TE0720 == 1 */

    /**
     * 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_ */