C

Qt Quick Ultralite imagedecoder Example

/******************************************************************************
**
** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Quick Ultralite module.
**
** $QT_BEGIN_LICENSE:COMM$
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** $QT_END_LICENSE$
**
******************************************************************************/

#include "cy_project.h"
#include "cyjpg_def.h"
#include "cyjpg_basetypes.h"
#include "cyjpg_typedef.h"
#include "cyjpg.h"

#include <cygfx_driver_api.h>
#include <cygfx_basetypes.h>
#include <sm_util.h>

#include <platforminterface/printf.h>

// #define TVII_DEBUG_JPEG_DECODER

// Fetch/store buffer information
#define FETCH_BUF_START_ADDR 0x28028000U
#define FETCH_BUF_LENGTH 0x70000U

#define STORE_BUF0_START_ADDR 0x243a0000
#define STORE_BUF0_LENGTH 0x60000U
#define STORE_BUF1_START_ADDR 0x24340000
#define STORE_BUF1_LENGTH 0x60000U

/* Subsample type */
// CYJPG_YUV444 (CYJPG_U32) 0
// CYJPG_YUV422 (CYJPG_U32) 1
// CYJPG_YUV411 (CYJPG_U32) 6
// CYJPG_YUV420 (CYJPG_U32) 2
// CYJPG_GRAYSCALE (CYJPG_U32) 3
// CYJPG_CMYK (CYJPG_U32) 4
// CYJPG_INVALID (CYJPG_U32) 7

/* Call Sample Application function if the previous operation did not fail. */
#define CALL_APPL_FUNC(ret_appl, execute) \
    do { \
        if ((ret_appl) == RES_DEC_SUCCESS) { \
            (ret_appl) = (execute); \
        } \
    } while (0)

/* Call JPEG Deocde Driver function if the previous operation did not fail. */
#define CALL_JPGDRV_FUNC(ret_appl, ret_drv, execute) \
    do { \
        if ((ret_appl) == RES_DEC_SUCCESS) { \
            (ret_drv) = (execute); \
            if ((ret_drv) != CYJPG_OK) { \
                (ret_appl) = RES_DEC_FAILED_DRIVER; \
            } \
        } \
    } while (0)

/* AXI bus configuration */
CYJPG_AXICTL_S axi_config;

/* IRQ configuration */
CYJPG_IRQCTL_S irq_config;

/* JPEG Decode Core Configuration */
CYJPG_DECODEINFO_S dec_core_config;

/* JPEG Decode Configuration */
CYJPG_JPGINFO_S jpg_config;

/* Configuration for JPEG Driver initialization */
CYJPG_INIT_S init_config;

/* IRQ Configuration for JPEGDEC */
CYJPG_STATIC const cy_stc_sysint_irq_t irq_cfg_jpeg = {.sysIntSrc = jpegdec_interrupt_jpeg_IRQn, //156
                                                       .intIdx = CPUIntIdx3_IRQn,
                                                       .isEnabled = true};

static void jpeg_configuration_init(void)
{
    /* AXI bus configuration */
    axi_config.arcache = 0U;          /* ARCACHE value of AXI transactions on Fetch Unit */
    axi_config.awcache = 0U;          /* AWCACHE value of AXI transactions on Store Unit */
    axi_config.fetchburstlength = 0U; /* Maximum burst length for Fetch Unit */
    axi_config.storeburstlength = 0U; /* Maximum burst length for Store Unit */

    /* IRQ configuration */
    irq_config.decodeintrmask = CYJPG_ENABLE;      /* Masks assertion of INTR.CORE due to decoding completion */
    irq_config.frameCompleteClear = CYJPG_DISABLE; /* Clear INTR.FRAME_COMPLETE  */
    irq_config.jpegCoreClear = CYJPG_DISABLE;      /* Clear INTR.JPEG_CORE */
    irq_config.fetchErrorClear = CYJPG_DISABLE;    /* Clear INTR.FETCH_ERROR */
    irq_config.storeErrorClear = CYJPG_DISABLE;    /* Clear INTR.STORE_ERROR */
    irq_config.frameCompleteMask = CYJPG_ENABLE;   /* Interrupt mask for FRAME_COMPLETE */
    irq_config.jpegCoreMask = CYJPG_ENABLE;        /* Interrupt mask for JPEG_CORE */
    irq_config.fetchErrorMask = CYJPG_ENABLE;      /* Interrupt mask for FETCH_ERROR */
    irq_config.storeErrorMask = CYJPG_ENABLE;      /* Interrupt mask for STORE_ERROR */
    irq_config.appMarkerEn = CYJPG_ENABLE;         /* Interrupt Setting for INTR_DEC_EN.APPMARKER */
    irq_config.comMarkerEn = CYJPG_ENABLE;         /* Interrupt Setting for INTR_DEC_EN.COMMARKER */
    irq_config.unknownMarkerEn = CYJPG_ENABLE;     /* Interrupt Setting for INTR_DEC_EN.UNKNOWNMARKER */
    irq_config.sizeAvailableEn = CYJPG_ENABLE;     /* Interrupt Setting for INTR_DEC_EN.SIZEAVAILABLE */
    irq_config.errorIntervalEn = CYJPG_DISABLE;    /* Interrupt Setting for INTR_DEC_EN.ERRORINTERVAL */
    irq_config.errorTotalDataEn = CYJPG_DISABLE;   /* Interrupt Setting for INTR_DEC_EN.ERRORTOTALDATA */
    irq_config.intMaskEn = CYJPG_DISABLE;          /* Interrupt Setting for INTR_DEC_EN.INTMASK */

    /* JPEG Decode Core Configuration */
    dec_core_config.subsample = 0U;  /* Sub-sampling mode defined in SOF marker segment */
    dec_core_config.dri = 0U;        /* Value downloaded from DRI marker segment */
    dec_core_config.sizey = 0U;      /* Y size value downloaded from SOF marker segment */
    dec_core_config.sizex = 0U;      /* X size value downloaded from SOF marker segment */
    dec_core_config.cropstarty = 0U; /* Y crop start position */
    dec_core_config.cropstartx = 0U; /* X crop start position */
    dec_core_config.cropsizey = 0U;  /* Crop size for Y direction */
    dec_core_config.cropsizex = 0U;  /* Crop size for X direction */

    /* JPEG Decode Configuration */
    jpg_config.fetchAddress = FETCH_BUF_START_ADDR; /* Start address of the JPEG image in bytes */
    jpg_config.fetchLength = FETCH_BUF_LENGTH;      /* JPEG image length in bytes */
    jpg_config.storeAddress0
        = STORE_BUF0_START_ADDR;                 /* Start address of the destination buffer 0 in multiple of 64 bytes */
    jpg_config.storeStride0 = 0;                 /* Line stride of the destination buffer 0 in multiple of 64 bytes */
    jpg_config.storeLength0 = STORE_BUF0_LENGTH; /* Destination buffer 0 length in multiple of 64 bytes */
    jpg_config.storeAddress1
        = STORE_BUF1_START_ADDR;                 /* Start address of the destination buffer 1 in multiple of 64 bytes */
    jpg_config.storeStride1 = 0;                 /* Line stride of the destination buffer 1 in multiple of 64 bytes */
    jpg_config.storeLength1 = STORE_BUF1_LENGTH; /* Destination buffer 1 length in multiple of 64 bytes */
    jpg_config.upsamplingEn = CYJPG_DISABLE;     /* Decoded pixels are up-sampled to YUV 4:4:4 */
    jpg_config.markerskipEn = CYJPG_DISABLE;     /* Enable/Disable Marker Skip Function */
    jpg_config.cropEn = CYJPG_DISABLE;           /* Enable/Disable Crop Function */
    jpg_config.correctionEn = CYJPG_DISABLE;     /* Enable/Disable Correction Function */
    jpg_config.decodeinfo_s = &dec_core_config;  /* Pointer to JPEG Decode Core Configuration */

    /* JPEG Initial Configuration  */
    init_config.axictl_s = &axi_config;
    init_config.irqctl_s = &irq_config;
    init_config.jpginfo_s = &jpg_config;
}

/*****************************************************************************/
/* Macro Definitions                                                         */
/*****************************************************************************/
/* Result of Decoding APIs */
#define RES_DEC_SUCCESS 0x0U                /* Success */
#define RES_DEC_FAILED_DRIVER 0x101U        /* JPEG Driver API failed */
#define RES_DEC_FAILED_ILLEGAL_STATE 0x102U /* Illegal state error */
#define RES_DEC_FAILED_TIMEOUT_AXI 0x103U   /* Timeout of AXI inactive timer */
#define RES_DEC_FAILED_CROPAREALIST 0x104U  /* Crop areas include errors */
#define RES_DEC_FAILED_ABNORMAL 0x1FFU      /* Abnormal error */

/*****************************************************************************/
/* Type Definitions                                                          */
/*****************************************************************************/
/* Decode State */
typedef enum {
    DEC_STATE_DISABLED = 0,            /* Disabled */
    DEC_STATE_CONFIG = 1,              /* Configuration */
    DEC_STATE_DECODING = 2,            /* Decoding */
    DEC_STATE_SUSPENDED = 3,           /* Suspended */
    DEC_STATE_SUSPENDED_SIZEAVAIL = 4, /* Suspended (SIZEAVAILABLE) */
    DEC_STATE_COMPLETED = 5,           /* Completed */
    DEC_STATE_RECOVERY = 6             /* Recovery */
} JPG_SAMPLE_DEC_STATE_E;

/* Recovery Cause */
typedef enum {
    DEC_RCV_CAUSE_NOTHING = 0,             /* No cause */
    DEC_RCV_CAUSE_CANCEL = 1,              /* Cancel on-going decoding */
    DEC_RCV_CAUSE_FETCH_STORE_ERR = 2,     /* Fetch/Store Error */
    DEC_RCV_CAUSE_INTR_DEC_ERR = 3,        /* INTR_DEC Error */
    DEC_RCV_CAUSE_NO_NORMAL_CORRECTED = 4, /* NORMALEND/CORRECTEDEND not generated */
    DEC_RCV_CAUSE_UNDEFINED_STATE = 5,     /* Undefined State */
} JPG_SAMPLE_DEC_RCV_CAUSE_E;

/*****************************************************************************/
/* Local Variables/Constants                                                 */
/*****************************************************************************/
CYJPG_STATIC JPG_SAMPLE_DEC_STATE_E decode_state = DEC_STATE_DISABLED;          /* Decode State */
CYJPG_STATIC JPG_SAMPLE_DEC_RCV_CAUSE_E recovery_cause = DEC_RCV_CAUSE_NOTHING; /* Recovery Cause */

CYJPG_STATIC CYJPG_BOOL first_dec_comp = CYJPG_FALSE;       /* First decode completion */
CYJPG_STATIC CYJPG_BOOL gen_normal_corrected = CYJPG_FALSE; /* NORMALEND/CORRECTEDEND generated Flag */

/** \brief Update Decode State
 ** \param upd_state [in] Decode state to be updated
 ** \return result
 **          RES_DEC_SUCCESS: Success
 **          RES_DEC_FAILED_ILLEGAL_STATE: Illegal state error
 **          RES_DEC_FAILED_ABNORMAL: Abnormal error
 **
 ** No remarks
 ** */
CYJPG_U32 Jpeg_DecUpdateState(JPG_SAMPLE_DEC_STATE_E upd_state)
{
    /* Local variables */
    CYJPG_U32 ret = RES_DEC_SUCCESS;

    /* Check current decode state */
    switch (decode_state) {
    case DEC_STATE_DISABLED: {
        if (upd_state == DEC_STATE_CONFIG) {
            /* Update decode state */
            decode_state = upd_state;
        } else {
            /* Illegal state transition */
            ret = RES_DEC_FAILED_ILLEGAL_STATE;
        }
        break;
    }
    case DEC_STATE_CONFIG: {
        if ((upd_state == DEC_STATE_DECODING) || (upd_state == DEC_STATE_DISABLED)) {
            decode_state = upd_state;
        } else {
            ret = RES_DEC_FAILED_ILLEGAL_STATE;
        }
        break;
    }
    case DEC_STATE_DECODING: {
        if ((upd_state == DEC_STATE_SUSPENDED) || (upd_state == DEC_STATE_SUSPENDED_SIZEAVAIL)
            || (upd_state == DEC_STATE_COMPLETED) || (upd_state == DEC_STATE_RECOVERY)
            || (upd_state == DEC_STATE_DISABLED)) {
            decode_state = upd_state;
        } else {
            ret = RES_DEC_FAILED_ILLEGAL_STATE;
        }
        break;
    }
    case DEC_STATE_SUSPENDED:
    case DEC_STATE_SUSPENDED_SIZEAVAIL: {
        if ((upd_state == DEC_STATE_DECODING) || (upd_state == DEC_STATE_RECOVERY)
            || (upd_state == DEC_STATE_DISABLED)) {
            decode_state = upd_state;
        } else {
            ret = RES_DEC_FAILED_ILLEGAL_STATE;
        }
        break;
    }
    case DEC_STATE_COMPLETED: {
        if ((upd_state == DEC_STATE_CONFIG) || (upd_state == DEC_STATE_RECOVERY) || (upd_state == DEC_STATE_DISABLED)) {
            decode_state = upd_state;
        } else {
            ret = RES_DEC_FAILED_ILLEGAL_STATE;
        }
        break;
    }
    case DEC_STATE_RECOVERY: {
        if ((upd_state == DEC_STATE_CONFIG) || (upd_state == DEC_STATE_DISABLED)) {
            decode_state = upd_state;
        } else {
            ret = RES_DEC_FAILED_ILLEGAL_STATE;
        }
        break;
    }
    default: {
        ret = RES_DEC_FAILED_ABNORMAL;
        break;
    }
    }

    return ret;
}

/** \brief Notify NORMALEND/CORRECTEDEND is generated
 ** \param gen_normal [in] NORMALEND/CORRECTEDEND is generated or not
 ** \return void
 **
 ** No remarks
 ** */
void Jpeg_DecNotifyNormalCorrected(CYJPG_BOOL gen_flag)
{
    /* Set NORMALEND/CORRECTEDEND generated flag */
    gen_normal_corrected = gen_flag;

    return;
}

/** \brief Notify cause of recovery
 ** \param rcv_cause [in] cause of recovery
 ** \return void
 **
 ** No remarks
 ** */
void Jpeg_DecNotifyRcvCause(JPG_SAMPLE_DEC_RCV_CAUSE_E rcv_cause)
{
    /* Set recovery cause */
    recovery_cause = rcv_cause;

    return;
}

/*****************************************************************************/
/* Local Functions                                                           */
/*****************************************************************************/
/** \brief JPEG Decoder Core Interrupt
 ** \param         No param
 ** \return        void
 **
 ** No remarks
 ** */
CYJPG_STATIC void Jpeg_kInterruptJpegDecoderCore(CYJPG_IRQSTATUS_S *irq_status)
{
    /* Clear IRQ causes of INTR and INTR_DEC */
    (void) CyJpg_ClearJpegCoreIrq();

    /* Crop Size/MCU Unit Error occurs */
    if ((irq_status->sizeAvailable == CYJPG_TRUE)
        && ((irq_status->cropSizeError == CYJPG_TRUE) || (irq_status->mcuUnitError == CYJPG_TRUE))) {
        /* Change state to Recovery */
        (void) Jpeg_DecUpdateState(DEC_STATE_RECOVERY);

        /* Notify recovery cause as undefined status */
        Jpeg_DecNotifyRcvCause(DEC_RCV_CAUSE_UNDEFINED_STATE);
    }
    /* Error interval/Error Total Data/Error marker occurs */
    else if ((irq_status->errorInterval == CYJPG_TRUE) || (irq_status->errorTotalData == CYJPG_TRUE)
             || (irq_status->errorMarker == CYJPG_TRUE)) {
        /* Change state to Recovery */
        (void) Jpeg_DecUpdateState(DEC_STATE_RECOVERY);

        /* Notify recovery cause as INTR_DEC error */
        Jpeg_DecNotifyRcvCause(DEC_RCV_CAUSE_INTR_DEC_ERR);
    }
    /* JPEG image size is available */
    else if (irq_status->sizeAvailable == CYJPG_TRUE) {
        /* Change state to Suspended (SIZEAVAILBLE) */
        (void) Jpeg_DecUpdateState(DEC_STATE_SUSPENDED_SIZEAVAIL);
    }
    /* APP/COM/Unknown Marker is detected or JPEG image size is available */
    else if ((irq_status->appMarker == CYJPG_TRUE) || (irq_status->comMarker == CYJPG_TRUE)
             || (irq_status->unknownMarker == CYJPG_TRUE)) {
        /* Change state to Suspended */
        (void) Jpeg_DecUpdateState(DEC_STATE_SUSPENDED);
    } else {
    }

    /* JPEG decoder core has finished normally */
    if ((irq_status->normalEnd == CYJPG_TRUE) || (irq_status->correctedEnd == CYJPG_TRUE)) {
        /* Notify NORMALEND/CORRECTEDEND generated */
        Jpeg_DecNotifyNormalCorrected(CYJPG_TRUE);
    }

    return;
}

/** \brief Pixel Data Store Completion Interrupt
 ** \param irq_state [in] IRQ status
 ** \return        void
 **
 ** No remarks
 ** */
CYJPG_STATIC void Jpeg_kInterruptPixelDataStoreComp(CYJPG_IRQSTATUS_S *irq_status)
{
    /* Clear IRQ cause of Pixel Data Store Completion Interrupt */
    (void) CyJpg_ClearFrameCompIrq();

    /* Change state to Completed */
    (void) Jpeg_DecUpdateState(DEC_STATE_COMPLETED);

    if ((irq_status->normalEnd == CYJPG_TRUE) || (irq_status->correctedEnd == CYJPG_TRUE)) {
        /* Notify NORMALEND/CORRECTEDEND generated */
        Jpeg_DecNotifyNormalCorrected(CYJPG_TRUE);
    }

    return;
}

/** \brief Fetch Unit Error Interrupt
 ** \param         No param
 ** \return        void
 **
 ** No remarks
 ** */
CYJPG_STATIC void Jpeg_kInterruptFetchUnitError(void)
{
    /* Clear IRQ cause of Fetch Unit Error Interrupt */
    (void) CyJpg_SetErrorInfo(CYJPG_FETCH_ERROR);

    /* Change state to Recovery */
    (void) Jpeg_DecUpdateState(DEC_STATE_RECOVERY);

    /* Notify recovery cause as Fetch/Store error */
    Jpeg_DecNotifyRcvCause(DEC_RCV_CAUSE_FETCH_STORE_ERR);

    return;
}

/** \brief Store Unit Error Interrupt
 ** \param         No param
 ** \return        void
 **
 ** No remarks
 ** */
CYJPG_STATIC void Jpeg_kInterruptStoreUnitError(void)
{
    /* Clear IRQ cause of Store Unit Error Interrupt */
    (void) CyJpg_SetErrorInfo(CYJPG_STORE_ERROR);

    /* Change state to Recovery */
    (void) Jpeg_DecUpdateState(DEC_STATE_RECOVERY);

    /* Notify recovery cause as Fetch/Store error */
    Jpeg_DecNotifyRcvCause(DEC_RCV_CAUSE_FETCH_STORE_ERR);

    return;
}

// JPEGDEC interrupt handler
static void Jpeg_InterruptHandler(void)
{
    /* Local variables */
    CYJPG_IRQSTATUS_S irq_status; /* JPEG Decoder IRQ Status */

    /* Get IRQ cause */
    (void) CyJpg_GetJpgIrqCause(&irq_status);

    /* Fetch Unit Error Interrupt */
    if (irq_status.intrFetchError == CYJPG_TRUE) {
        Jpeg_kInterruptFetchUnitError();
    }

    /* Store Unit Error Interrupt */
    if (irq_status.intrStoreError == CYJPG_TRUE) {
        Jpeg_kInterruptStoreUnitError();
    }

    /* JPEG Decoder Core Interrupt */
    if (irq_status.intrJpegCore == CYJPG_TRUE) {
        Jpeg_kInterruptJpegDecoderCore(&irq_status);
    }

    /* Pixel Data Store Completion Interrupt */
    if (irq_status.intrFrameComplete == CYJPG_TRUE) {
        Jpeg_kInterruptPixelDataStoreComp(&irq_status);
    }

    return;
}

static CYGFX_BE_CONTEXT_OBJECT_S ctx;  // drawing context for Blit Engine
static CYGFX_SURFACE_OBJECT_S surfSrc; // source surface
static CYGFX_SURFACE_OBJECT_S surfDst; // destination surface

uint32_t tvii_convert_decoded_buffers(unsigned char *outbuffer,
                                      uint32_t width,
                                      uint32_t height,
                                      CYGFX_SM_FORMAT dst_format)
{
    uint32_t ret_gfx = 0;
    UTIL_SUCCESS(ret_gfx, CyGfx_BeResetContext(&ctx));

    UTIL_SUCCESS(ret_gfx, CyGfx_SmResetSurfaceObject(&surfSrc));
    UTIL_SUCCESS(ret_gfx, CyGfx_SmAssignBuffer(&surfSrc, width, height, CYGFX_SM_FORMAT_YUV420, 0, 0));
    UTIL_SUCCESS(ret_gfx, CyGfx_SmSetAttribute(&surfSrc, CYGFX_SM_ATTR_STRIDE, width));
    UTIL_SUCCESS(ret_gfx, CyGfx_SmSetAttribute(&surfSrc, CYGFX_SM_ATTR_VIRT_ADDRESS, (CYGFX_U32) STORE_BUF0_START_ADDR));
    UTIL_SUCCESS(ret_gfx,
                 CyGfx_SmSetAttribute(&surfSrc, CYGFX_SM_ATTR_VIRT_ADDRESS_SEC, (CYGFX_U32) STORE_BUF1_START_ADDR));
    UTIL_SUCCESS(ret_gfx, CyGfx_BeBindSurface(&ctx, CYGFX_BE_TARGET_SRC, &surfSrc));

    UTIL_SUCCESS(ret_gfx, CyGfx_SmResetSurfaceObject(&surfDst));
    UTIL_SUCCESS(ret_gfx, CyGfx_SmAssignBuffer(&surfDst, width, height, dst_format, (void *) outbuffer, 0));
    UTIL_SUCCESS(ret_gfx, CyGfx_BeBindSurface(&ctx, CYGFX_BE_TARGET_STORE, &surfDst));

    UTIL_SUCCESS(ret_gfx, CyGfx_BeBlt(&ctx, 0, 0));
    CyGfx_BeFinish(&ctx);
}

void tvii_jpeg_init(void)
{
    // Configuration
    jpeg_configuration_init();

    // Initialize JPEG Interrupts
    int ret = Cy_SysInt_InitIRQ(&irq_cfg_jpeg);
    if (ret != 0) {
        qul_printf("Cy_SysInt_InitIRQ() failed\n");
        return;
    }

    // Set interrupt handler
    Cy_SysInt_SetSystemIrqVector(irq_cfg_jpeg.sysIntSrc, Jpeg_InterruptHandler);

    // Set Priority/Enable IRQ
    NVIC_SetPriority(CPUIntIdx3_IRQn, 3);
    NVIC_ClearPendingIRQ(CPUIntIdx3_IRQn);
    NVIC_EnableIRQ(CPUIntIdx3_IRQn);

    // Initialize JPEG Decode Driver
    ret = CyJpg_Init(&init_config);
    if (ret != 0) {
        qul_printf("CyJpg_Init() failed\n");
        return;
    }

    // Change state to Configuration */
    Jpeg_DecUpdateState(DEC_STATE_CONFIG);

    return;
}

CYJPG_STATIC CYJPG_U32 Jpeg_DecOpeStartDec(void);
CYJPG_STATIC CYJPG_U32 Jpeg_DecOpeSizeAvailIntr(void);
CYJPG_STATIC CYJPG_U32 Jpeg_DecOpeCompletion(void);
CYJPG_STATIC CYJPG_U32 Jpeg_DecOpeRecovery(void);

/** \brief Decode JPEG images periodically
 ** \param         No param
 ** \return        Result of initialization
 **                 RES_DEC_SUCCESS: OK
 **                 Others         : NG
 **
 ** No remarks
 ** */
CYJPG_U32 Jpeg_DecStart(uint32_t addr, uint32_t size, uint32_t stride)
{
    /* Local variables */
    CYJPG_U32 result_appl = RES_DEC_SUCCESS; /* Result of Sample Application */
    CYJPG_ERROR ret_drv;                     /* Return value from Jpeg Decode Driver */

    /* Initialize variables */
    first_dec_comp = CYJPG_FALSE;       /* First decode completion */
    gen_normal_corrected = CYJPG_FALSE; /* NORMALEND/CORRECTEDEND generated Flag */

    jpg_config.fetchAddress = addr;
    jpg_config.fetchLength = size;
    jpg_config.storeStride0 = stride;
    jpg_config.storeStride1 = stride;

#ifdef TVII_DEBUG_JPEG_DECODER
    qul_printf("jpg_config.storeStride0 %u\n", jpg_config.storeStride0);
#endif
    /* Change state to Decoding */
    CALL_APPL_FUNC(result_appl, Jpeg_DecUpdateState(DEC_STATE_DECODING));

    /* Start decoding 1st JPEG image */
    CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_StartDecoding(&jpg_config));

    while (result_appl == RES_DEC_SUCCESS) {
        switch (decode_state) {
        case DEC_STATE_CONFIG: {
#ifdef TVII_DEBUG_JPEG_DECODER
            qul_printf("DEC_STATE_CONFIG\n");
#endif
            /* Start JPEG decoding */
            CALL_APPL_FUNC(result_appl, Jpeg_DecOpeStartDec());
            break;
        }
        case DEC_STATE_DECODING: {
#ifdef TVII_DEBUG_JPEG_DECODER
            qul_printf("DEC_STATE_DECODING\n");

            CYJPG_DECODEINFO_S dec_info; /* Decode Information */
            CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_GetDecInfo(&dec_info));
            qul_printf("dec_info.subsample %u\n", dec_info.subsample);
#endif
            break;
        }
        case DEC_STATE_SUSPENDED: {
#ifdef TVII_DEBUG_JPEG_DECODER
            qul_printf("DEC_STATE_SUSPENDED\n");
#endif
            /* Change state to Decoding */
            CALL_APPL_FUNC(result_appl, Jpeg_DecUpdateState(DEC_STATE_DECODING));

            /* Resume Decoding */
            CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_ResumeDecoding(&jpg_config));

#ifdef TVII_DEBUG_JPEG_DECODER
            CYJPG_DECODEINFO_S dec_info; /* Decode Information */
            CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_GetDecInfo(&dec_info));
            qul_printf("DEC_STATE_SUSPENDED\tdec_info.subsample %u\n", dec_info.subsample);
#endif
            break;
        }
        case DEC_STATE_SUSPENDED_SIZEAVAIL: {
#ifdef TVII_DEBUG_JPEG_DECODER
            qul_printf("DEC_STATE_SUSPENDED_SIZEAVAIL\n");
#endif

            /* Operation when Size Available Interrupt occurs */
            CALL_APPL_FUNC(result_appl, Jpeg_DecOpeSizeAvailIntr());

            break;
        }
        case DEC_STATE_COMPLETED: {
#ifdef TVII_DEBUG_JPEG_DECODER
            qul_printf("DEC_STATE_COMPLETED\n");
#endif
            /* Operation for decoding completion */
            CALL_APPL_FUNC(result_appl, Jpeg_DecOpeCompletion());
            return RES_DEC_SUCCESS;
            break;
        }
        case DEC_STATE_RECOVERY: {
#ifdef TVII_DEBUG_JPEG_DECODER
            qul_printf("DEC_STATE_RECOVERY\n");
#endif
            /* Operation for recovery */
            CALL_APPL_FUNC(result_appl, Jpeg_DecOpeRecovery());
            break;
        }
        default: {
            /* Abnormal error */
            qul_printf("Jpeg Decoder: Abnormal error detected.\n");
            result_appl = RES_DEC_FAILED_ABNORMAL;
            break;
        }
        }
    }

    return result_appl;
}

/** \brief Wait for AXI transactions to become inactive
 ** \param  No param
 ** \return result
 **          RES_DEC_SUCCESS: Success
 **          RES_DEC_FAILED_DRIVER: JPEG Driver API failed
 **          RES_DEC_FAILED_TIMEOUT_AXI: Timeout of AXI inactive timer
 **
 ** No remarks
 ** */
CYJPG_STATIC CYJPG_U32 Jpeg_DecWaitAxiInactive(void)
{
    /* Local variables */
    CYJPG_U32 result_appl = RES_DEC_SUCCESS; /* Result of Sample Application */
    CYJPG_ERROR ret_drv;                     /* Return value from Jpeg Decode Driver */
    // float elapsed_time;                      /* Elapsed Time */
    CYJPG_CORESTATUS_S core_status; /* HW core status */

    /* Get HW status */
    CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_GetHwStatus(&core_status));

    /* Check fetch/store AXI burst are finished */
    if ((core_status.fetchAxiActive != CYJPG_FALSE) || (core_status.storeAxiActive != CYJPG_FALSE)) {
        do {
            /* Get HW status */
            CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_GetHwStatus(&core_status));

            if (result_appl == RES_DEC_SUCCESS) {
                /* Check fetch/store AXI burst are inactive */
                if ((core_status.fetchAxiActive == CYJPG_FALSE) && (core_status.storeAxiActive == CYJPG_FALSE)) {
                    /* Finish fetch/store AXI burst */
                    break;
                }
            }
        } while (result_appl == RES_DEC_SUCCESS);
    }

    return result_appl;
}

/** \brief Operation for Starting JPEG decode
 ** \param  No param
 ** \return result
 **          RES_DEC_SUCCESS: Success
 **          RES_DEC_FAILED_DRIVER: JPEG Driver API failed
 **          RES_DEC_FAILED_ILLEGAL_STATE: Illegal state error
 **
 ** No remarks
 ** */
CYJPG_STATIC CYJPG_U32 Jpeg_DecOpeStartDec(void)
{
    /* Local variables */
    CYJPG_U32 result_appl = RES_DEC_SUCCESS; /* Result of Sample Application */
    CYJPG_ERROR ret_drv;                     /* Return value from Jpeg Decode Driver */
    CYJPG_BOOL mod_config = CYJPG_FALSE;     /* Flag of modifying configuration */

    /* Change state to Decoding */
    CALL_APPL_FUNC(result_appl, Jpeg_DecUpdateState(DEC_STATE_DECODING));

    if (mod_config == CYJPG_FALSE) {
        /* Continue decoding JPEG image */
        CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_ContinueDecoding(&jpg_config));
    } else {
        /* Start decoding with configuration changes */
        CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_StartDecoding(&jpg_config));
    }

    return result_appl;
}

/** \brief Operation when Size Available Interrupt occurs
 ** \param  No param
 ** \return result
 **          RES_DEC_SUCCESS: Success
 **          RES_DEC_FAILED_DRIVER: JPEG Driver API failed
 **          RES_DEC_FAILED_ILLEGAL_STATE: Illegal state error
 **
 ** No remarks
 ** */
CYJPG_STATIC CYJPG_U32 Jpeg_DecOpeSizeAvailIntr(void)
{
    /* Local variables */
    CYJPG_U32 result_appl = RES_DEC_SUCCESS; /* Result of Sample Application */
    CYJPG_ERROR ret_drv;                     /* Return value from Jpeg Decode Driver */
    CYJPG_HWERRINFO_S hw_err_info;           /* HW Error Information */
    CYJPG_BOOL crop_error = CYJPG_FALSE;     /* Crop Error Flag */

    if (jpg_config.cropEn == CYJPG_ENABLE) {
        /* Get HW error information to check crop errors */
        CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_GetHwErrorInfo(&hw_err_info));

        if ((hw_err_info.correctionCropStatus[hw_err_info.correctionCropNum] & 0x00000030U) != 0U) {
            /* Crop Size Error (Bit#4) or MCU Unit Error (Bit#5) occurs */
            crop_error = CYJPG_TRUE;
        }
    }

    if (crop_error == CYJPG_FALSE) {
        /* Change state to Decoding */
        CALL_APPL_FUNC(result_appl, Jpeg_DecUpdateState(DEC_STATE_DECODING));

        /* Resume Decoding */
        CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_ResumeDecoding(&jpg_config));
    } else {
        /* Change state to Recovery */
        CALL_APPL_FUNC(result_appl, Jpeg_DecUpdateState(DEC_STATE_RECOVERY));

        /* Notify recovery cause as undefined status */
        Jpeg_DecNotifyRcvCause(DEC_RCV_CAUSE_UNDEFINED_STATE);
    }

    return result_appl;
}

/** \brief Operation for JPEG decode completion
 ** \param  No param
 ** \return result
 **          RES_DEC_SUCCESS: Success
 **          RES_DEC_FAILED_ILLEGAL_STATE: Illegal state error
 **
 ** No remarks
 ** */
CYJPG_STATIC CYJPG_U32 Jpeg_DecOpeCompletion(void)
{
    /* Local variables */
    CYJPG_U32 result_appl = RES_DEC_SUCCESS; /* Result of Sample Application */

    /* Check Decode error: Not generated NORMALEND/CORRECTEDEND */
    if (gen_normal_corrected == CYJPG_TRUE) {
        /* Check if the decoded data is 1st JPEG image */
        if (first_dec_comp == CYJPG_FALSE) {
            first_dec_comp = CYJPG_TRUE;
        }
        /* Change state to Configuration */
        CALL_APPL_FUNC(result_appl, Jpeg_DecUpdateState(DEC_STATE_CONFIG));
    } else {
        /* Change state to Recovery */
        CALL_APPL_FUNC(result_appl, Jpeg_DecUpdateState(DEC_STATE_RECOVERY));

        /* Set recovery cause to "NORMALEND/CORRECTEDEND not generated" */
        Jpeg_DecNotifyRcvCause(DEC_RCV_CAUSE_NO_NORMAL_CORRECTED);
    }

    /* Initialize NORMALEND/CORRECTEDEND generated flag */
    Jpeg_DecNotifyNormalCorrected(CYJPG_FALSE);

    return result_appl;
}

/** \brief Operation for hardware status recovery
 ** \param  No param
 ** \return result
 **          RES_DEC_SUCCESS: Success
 **          RES_DEC_FAILED_DRIVER: JPEG Driver API failed
 **          RES_DEC_FAILED_TIMEOUT_AXI: Timeout of AXI inactive timer
 **          RES_DEC_FAILED_ABNORMAL: Abnormal error
 **
 ** No remarks
 ** */
CYJPG_STATIC CYJPG_U32 Jpeg_DecOpeRecovery(void)
{
    /* Local variables */
    CYJPG_U32 result_appl = RES_DEC_SUCCESS; /* Result of Sample Application */
    CYJPG_ERROR ret_drv;                     /* Return value from Jpeg Decode Driver */

    switch (recovery_cause) {
    case DEC_RCV_CAUSE_FETCH_STORE_ERR: {
        /* Wait for AXI transactions to become inactive */
        CALL_APPL_FUNC(result_appl, Jpeg_DecWaitAxiInactive());

        /* Perform SW reset */
        CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_SwReset());

        break;
    }
    case DEC_RCV_CAUSE_INTR_DEC_ERR: {
        /* Wait for AXI transactions to become inactive */
        CALL_APPL_FUNC(result_appl, Jpeg_DecWaitAxiInactive());

        break;
    }
    case DEC_RCV_CAUSE_CANCEL:
    case DEC_RCV_CAUSE_NO_NORMAL_CORRECTED: {
        /* Perform SW reset */
        CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_SwReset());

        /* Wait for AXI transactions to become inactive */
        CALL_APPL_FUNC(result_appl, Jpeg_DecWaitAxiInactive());

        break;
    }
    case DEC_RCV_CAUSE_UNDEFINED_STATE: {
        /* Perform SW reset */
        CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_SwReset());

        /* Wait for AXI transactions to become inactive */
        CALL_APPL_FUNC(result_appl, Jpeg_DecWaitAxiInactive());

        /* Deinitialize JPEG decode driver */
        CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_DeInit());

        if (result_appl == RES_DEC_SUCCESS) {
            /* Marker Skip Function must be disabled */
            jpg_config.markerskipEn = CYJPG_DISABLE;

            /* Initialize JPEG decode driver */
            CALL_JPGDRV_FUNC(result_appl, ret_drv, CyJpg_Init(&init_config));
        }

        break;
    }
    default: {
        /* Abnormal error */
        result_appl = RES_DEC_FAILED_ABNORMAL;
        break;
    }
    }

    if (result_appl == RES_DEC_SUCCESS) {
        /* Change state to Configuration */
        CALL_APPL_FUNC(result_appl, Jpeg_DecUpdateState(DEC_STATE_CONFIG));

        /* Initialize Recovery Cause */
        Jpeg_DecNotifyRcvCause(DEC_RCV_CAUSE_NOTHING);

        /* Initialize first decode completion */
        first_dec_comp = CYJPG_FALSE;
    }

    return result_appl;
}