#ifndef LINUX_OBC_PAPBVCINTERFACE_H_
#define LINUX_OBC_PAPBVCINTERFACE_H_

#include "OBSWConfig.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 "fsfw/objectmanager/ObjectManager.h"

/**
 * @brief   This class handles the transmission of data to a virtual channel of the PTME IP Core
 *          via the PAPB interface.
 *
 * @author  J. Meier
 */
class PapbVcInterface: public SystemObject,
                    public VcInterfaceIF,
                    public HasReturnvaluesIF {
public:
    /**
     * @brief   Constructor
     *
     * @param objectId
     * @param papbBusyId    The ID of the GPIO which is connected to the PAPBBusy_N signal of the
     *                      VcInterface IP Core. A low logic level indicates the VcInterface is not
     *                      ready to receive more data.
     * @param papbEmptyId   The ID of the GPIO which is connected to the PAPBEmpty signal of the
     *                      VcInterface IP Core. The signal is high when there are no packets in the
     *                      external buffer memory (BRAM).
     */
    PapbVcInterface(object_id_t objectId, LinuxLibgpioIF* gpioComIF, gpioId_t papbBusyId,
            gpioId_t papbEmptyId, uint32_t vcOffset);
    virtual ~PapbVcInterface();

    ReturnValue_t write(const uint8_t* data, size_t size) override;

    void setRegisterAddress(uint32_t* ptmeBaseAddress) override;

private:

    static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_IP_CORE_BRIDGE;

    static const ReturnValue_t PAPB_BUSY = 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 VcInterface the start of a new telemetry packet
     */
    static const uint32_t CONFIG_START = 0x8;

    /**
     * Writing this word to the VcInterface base address signals to the virtual channel interface
     * that a complete tm packet has been transferred.
     */
    static const uint32_t CONFIG_END = 0x0;

    /**
     * Writing to this offset within the memory space of a virtual channel will insert data for
     * encoding to the external buffer memory of the PTME IP Core.
     * The address offset is 0x400 (= 4 * 256)
     */
    static const int DATA_REG_OFFSET = 256;

    LinuxLibgpioIF* gpioComIF = nullptr;

    /** Pulled to low when virtual channel not ready to receive data */
    gpioId_t papbBusyId = gpio::NO_GPIO;
    /** High when external buffer memory of virtual channel is empty */
    gpioId_t papbEmptyId = gpio::NO_GPIO;

    uint32_t* vcBaseReg = nullptr;

    uint32_t vcOffset = 0;

    /**
     * @brief   This function sends the config byte to the virtual channel of the PTME IP Core
     *          to initiate a packet transfer.
     */
    void startPacketTransfer();

    /**
     * @brief   This function sends the config byte to the virtual channel interface of the PTME
     *          IP Core to signal the end of a  packet transfer.
     */
    void endPacketTransfer();

    /**
     * @brief   This function reads the papb busy signal indicating whether the virtual channel
     *          interface is ready to receive more data or not. PAPB is ready when
     *          PAPB_Busy_N == '1'.
     *
     * @return  RETURN_OK when ready to receive data else PAPB_BUSY.
     */
    ReturnValue_t pollPapbBusySignal();

    /**
     * @brief   This function can be used for debugging to check whether there are packets in
     *          the packet buffer of the virtual channel or not.
     */
    void isVcInterfaceBufferEmpty();

    /**
     * @brief   This function sends a complete telemetry transfer frame data field (1105 bytes)
     *          to the papb interface of the PTME IP Core. Can be used to test the implementation.
     */
    ReturnValue_t sendTestFrame();
};

#endif /* LINUX_OBC_PAPBVCINTERFACE_H_ */