#ifndef CHROMARTDMA_HPP
#define CHROMARTDMA_HPP

#include <touchgfx/hal/DMA.hpp>

#ifndef NO_USING_NAMESPACE_TOUCHGFX
using namespace touchgfx;
#endif

// Macro to get variable aligned on 4-bytes
#ifdef __GNUC__
#define ALIGN_PRAGMA
#define ALIGN_ATTRIBUTE __attribute__ ((aligned(4)))
#elif defined __ICCARM__
#define ALIGN_PRAGMA //_Pragma("data_alignment=4")
#define ALIGN_ATTRIBUTE
#elif defined(__ARMCC_VERSION)
#define ALIGN_PRAGMA
#define ALIGN_ATTRIBUTE __attribute__ ((aligned(4)))
#endif

/**
 * @class ChromArtDMA ChromArtDMA.hpp
 *
 * @brief This class specializes DMA_Interface for the ChromART DMA hardware.
 *
 * @sa touchgfx::DMA_Interface
 */
class ChromArtDMA : public touchgfx::DMA_Interface
{
    /**
     * @typedef touchgfx::DMA_Interface Base
     *
     * @brief Defines an alias representing the base.
     *
     Defines an alias representing the base.
     */
    typedef touchgfx::DMA_Interface Base;

public:
    /**
     * @fn ChromArtDMA::ChromArtDMA();
     *
     * @brief Default constructor.
     *
     *        Default constructor.
     */
    ChromArtDMA();

    /**
     * @fn ChromArtDMA::~ChromArtDMA();
     *
     * @brief Destructor.
     *
     *        Destructor.
     */
    virtual ~ChromArtDMA();

    /**
     * @fn touchgfx::BlitOperations ChromArtDMA::getBlitCaps();
     *
     * @brief Gets the blit capabilities.
     *
     *        Gets the blit capabilities.
     *
     *        This DMA supports a range of blit caps: BLIT_OP_COPY, BLIT_OP_COPY_ARGB8888,
     *        BLIT_OP_COPY_ARGB8888_WITH_ALPHA, BLIT_OP_COPY_A4, BLIT_OP_COPY_A8.
     *
     * @note For demonstration purposes, the blitcaps can be overridden at runtime to return zero
     *       by setting the overrideBlitCaps boolean to true.
     *
     * @return Currently supported blitcaps.
     */
    virtual touchgfx::BlitOperations getBlitCaps();

    /**
     * @fn void ChromArtDMA::initialize();
     *
     * @brief Perform hardware specific initialization.
     *
     *        Perform hardware specific initialization.
     */
    virtual void initialize();

    /**
     * @fn void ChromArtDMA::signalDMAInterrupt()
     *
     * @brief Raises a DMA interrupt signal.
     *
     *        Raises a DMA interrupt signal.
     */
    virtual void signalDMAInterrupt()
    {
        executeCompleted();
    }

protected:
    /**
     * @fn virtual void ChromArtDMA::setupDataCopy(const touchgfx::BlitOp& blitOp);
     *
     * @brief Configures the DMA for copying data to the frame buffer.
     *
     *        Configures the DMA for copying data to the frame buffer.
     *
     * @param blitOp Details on the copy to perform.
     */
    virtual void setupDataCopy(const touchgfx::BlitOp& blitOp);

    /**
     * @fn virtual void ChromArtDMA::setupDataFill(const touchgfx::BlitOp& blitOp);
     *
     * @brief Configures the DMA for "filling" the frame-buffer with a single color.
     *
     *        Configures the DMA for "filling" the frame-buffer with a single color.
     *
     * @param blitOp Details on the "fill" to perform.
     */
    virtual void setupDataFill(const touchgfx::BlitOp& blitOp);

    /**
     * @fn void STM32H7DMA::start();
     *
     * @brief Signals that DMA transfers can start.
     *
     *        Signals that DMA transfers can start. If any elements are in the queue, start it.
     */
    virtual void start();

    /**
     * @fn virtual DMAType ChromArtDMA::getDMAType()
     *
     * @brief Function for obtaining the DMA type of the concrete ChromArtDMA implementation.
     *
     *        Function for obtaining the DMA type of the concrete ChromArtDMA implementation.
     *        This will return DMA_TYPE_CHROMART type value.
     *
     * @return a DMAType value of the concrete ChromArtDMA implementation.
     */
    virtual DMAType getDMAType(void);

    /**
     * @fn virtual void ChromArtDMA::CleanInvalidateCache()
     *
     * @brief Function to clean and invalidate data cache.
     *
     *        Function to clean and invalidate data cache if the concrete MCU support it.
     *        Default implementation for MCU without Data Cache.
     */
    virtual void CleanInvalidateCache(void);
private:
    typedef struct
    {
        uint16_t format;
        uint16_t size;
        uint32_t data[];
    } clutData_t;

    static const uint16_t   TILE_RAM_SIZE = (1024 * 1);                 // This should be enough to convert L8_RGB565 CLUT entries to L8_RGB888 ones
    ALIGN_PRAGMA uint32_t   _tile_ram[TILE_RAM_SIZE] ALIGN_ATTRIBUTE;   // ARGB8888 one line or L8_RGB888 256 entries Tile RAM

    // Get Input/Output ChromART format
    uint32_t getChromARTInputFormat(Bitmap::BitmapFormat format);
    uint32_t getChromARTOutputFormat(Bitmap::BitmapFormat format);

    // Setup Dummy BlitOp. This will signal DMA Interrupt
    void setupDummyFillOp(void);

    // Blending hardware acceleration support for LCD8bpp
    void blitBlend_8Bits(const BlitOp& blitOp);
    void fillBlend_8Bits(const BlitOp& blitOp);
    void textBlend_8Bits(const BlitOp& blitOp);

    // Copy/Blend hardware acceleration support for L8 (indexed) formats
    void setupDataCopyL8(const BlitOp& blitOp, bool blendingImage);

    // Software Pixel Format Conversion support (to supported ChromART 8-bit formats)
    void convertARGB8888ToLCD8bpp_NoAlpha (const uint32_t* Src, uint8_t* Dst, uint32_t Pixels);
    void convertARGB8888ToLCD8bpp         (const uint32_t* Src, uint8_t* Dst, uint32_t Pixels);

    // Hardware Pixel Format Conversion support 
    void convertRGB565ToARGB8888           (const uint32_t* Src, uint32_t* Dst, uint32_t Pixels);
    void convertRGB565ToRGB888             (const uint32_t* Src, uint32_t* Dst, uint32_t Pixels);

    uint16_t TileRamLineWidth;

    touchgfx::LockFreeDMA_Queue dma_queue;
    touchgfx::BlitOp            queue_storage[96];

    uint32_t blitCaps;
};

#endif // CHROMARTDMA_HPP
