/**
  ******************************************************************************
  * @file    stm32h7xx_hal_jpeg.c
  * @author  MCD Application Team
  * @brief   JPEG HAL module driver.
  *          This file provides firmware functions to manage the following
  *          functionalities of the JPEG encoder/decoder peripheral:
  *           + Initialization and de-initialization functions
  *           + JPEG processing functions encoding and decoding
  *           + JPEG decoding Getting Info and encoding configuration setting
  *           + JPEG enable/disable header parsing functions (for decoding)
  *           + JPEG Input/Output Buffer configuration.
  *           + JPEG callback functions
  *           + JPEG Abort/Pause/Resume functions
  *           + JPEG custom quantization tables setting functions
  *           + IRQ handler management
  *           + Peripheral State and Error functions
  *
  @verbatim
  ==============================================================================
                     ##### How to use this driver #####
  ==============================================================================
    [..]
     (#) Initialize the JPEG peripheral using HAL_JPEG_Init : No initialization parameters are required.
         Only the call to HAL_JPEG_Init is necessary to initialize the JPEG peripheral.

     (#) If operation is JPEG encoding use function HAL_JPEG_ConfigEncoding to set
         the encoding parameters (mandatory before calling the encoding function).
         the application can change the encoding parameter ImageQuality from
         1 to 100 to obtain a more or less quality (visual quality vs the original row image),
         and inversely more or less jpg file size.

     (#) Note that for decoding operation the JPEG peripheral output data are organized in
         YCbCr blocks called MCU (Minimum Coded Unit) as defioned in the JPEG specification
         ISO/IEC 10918-1 standard.
         It is up to the application to transform these YCbCr blocks to RGB data that can be display.

         Respectively, for Encoding operation the JPEG peripheral input should be organized
         in YCbCr MCU blocks. It is up to the application to perform the necessary RGB to YCbCr
         MCU blocks transformation before feeding the JPEG peripheral with data.

     (#) Use functions HAL_JPEG_Encode and HAL_JPEG_Decode to start respectively
         a JPEG encoding/decoding operation in polling method (blocking).

     (#) Use functions HAL_JPEG_Encode_IT and HAL_JPEG_Decode_IT to start respectively
         a JPEG encoding/decoding operation with Interrupt method (not blocking).

     (#) Use functions HAL_JPEG_Encode_DMA and HAL_JPEG_Decode_DMA to start respectively
         a JPEG encoding/decoding operation with DMA method (not blocking).

     (#) Callback HAL_JPEG_InfoReadyCallback is asserted if the current operation
         is a JPEG decoding to provide the application with JPEG image  parameters.
         This callback is asserted when the JPEG peripheral successfully parse the
         JPEG header.

     (#) Callback HAL_JPEG_GetDataCallback is asserted for both encoding and decoding
         operations to inform the application that the input buffer has been
         consumed by the peripheral and to ask for a new data chunk if the operation
         (encoding/decoding) has not been complete yet.

        (++) This CallBack should be implemented in the application side. It should
             call the function HAL_JPEG_ConfigInputBuffer if new input data are available,
             or call HAL_JPEG_Pause with parameter XferSelection set to JPEG_PAUSE_RESUME_INPUT
             to inform the JPEG HAL driver that the ongoing operation shall pause waiting for the
             application to provide a new input data chunk.
             Once the application succeed getting new data and if the input has been paused,
             the application can call the function HAL_JPEG_ConfigInputBuffer to set the new
             input buffer and size, then resume the JPEG HAL input by calling new function HAL_JPEG_Resume.
             If the application has ended feeding the HAL JPEG with input data (no more input data), the application
             Should call the function HAL_JPEG_ConfigInputBuffer (within the callback HAL_JPEG_GetDataCallback)
             with the parameter InDataLength set to zero.

         (++) The mechanism of HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume allows
              to the application to provide the input data (for encoding or decoding) by chunks.
              If the new input data chunk is not available (because data should be read from an input file
              for example) the application can pause the JPEG input (using function HAL_JPEG_Pause)
              Once the new input data chunk is available ( read from a file for example), the application
              can call the function HAL_JPEG_ConfigInputBuffer to provide the HAL with the new chunk
              then resume the JPEG HAL input by calling function HAL_JPEG_Resume.

         (++) The application can call functions HAL_JPEG_ConfigInputBuffer then HAL_JPEG_Resume.
              any time (outside the HAL_JPEG_GetDataCallback)  Once the new input chunk data available.
              However, to keep data coherency, the function HAL_JPEG_Pause must be imperatively called
              (if necessary) within the callback HAL_JPEG_GetDataCallback, i.e when the HAL JPEG has ended
              Transferring the previous chunk buffer to the JPEG peripheral.

     (#) Callback HAL_JPEG_DataReadyCallback is asserted when the HAL JPEG driver
         has filled the given output buffer with the given size.

         (++) This CallBack should be implemented in the application side. It should
              call the function HAL_JPEG_ConfigOutputBuffer to provide the HAL JPEG driver
              with the new output buffer location and size to be used  to store next data chunk.
              if the application is not ready to provide the output chunk location then it can
              call the function HAL_JPEG_Pause with parameter XferSelection set to JPEG_PAUSE_RESUME_OUTPUT
              to inform the JPEG HAL driver that it shall pause output data. Once the application
              is ready to receive the new data chunk (output buffer location free or available) it should call
              the function HAL_JPEG_ConfigOutputBuffer to provide the HAL JPEG driver
              with the new output chunk buffer location and size, then call HAL_JPEG_Resume
              to inform the HAL that it shall resume outputting data in the given output buffer.

         (++) The mechanism of HAL_JPEG_ConfigOutputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume allows
              the application to receive data from the JPEG peripheral by chunks. when a chunk
              is received, the application can pause the HAL JPEG output data to be able to process
              these received data (YCbCr to RGB conversion in case of decoding or data storage in case
              of encoding).

         (++) The application can call  functions HAL_JPEG_ ConfigOutputBuffer then HAL_JPEG_Resume.
              any time (outside the HAL_JPEG_DataReadyCallback) Once the output data buffer is free to use.
              However, to keep data coherency, the function HAL_JPEG_Pause must be imperatively called
              (if necessary) within the callback HAL_JPEG_ DataReadyCallback, i.e when the HAL JPEG has ended
              Transferring the previous chunk buffer from the JPEG peripheral to the application.

     (#) Callback HAL_JPEG_EncodeCpltCallback is asserted when the HAL JPEG driver has
         ended the current JPEG encoding operation, and all output data has been transmitted
         to the application.

     (#) Callback HAL_JPEG_DecodeCpltCallback is asserted when the HAL JPEG driver has
         ended the current JPEG decoding operation. and all output data has been transmitted
         to the application.

     (#) Callback HAL_JPEG_ErrorCallback is asserted when an error occurred during
         the current operation. the application can call the function HAL_JPEG_GetError()
         to retrieve the error codes.

     (#) By default the HAL JPEG driver uses the default quantization tables
         as provide in the JPEG specification (ISO/IEC 10918-1 standard) for encoding.
         User can change these default tables if necessary using the function HAL_JPEG_SetUserQuantTables
         Note that for decoding the quantization tables are automatically extracted from
         the JPEG header.

      (#) To control JPEG state you can use the following function: HAL_JPEG_GetState()

     *** JPEG HAL driver macros list ***
     =============================================
     [..]
       Below the list of most used macros in JPEG HAL driver.

      (+) __HAL_JPEG_RESET_HANDLE_STATE : Reset JPEG handle state.
      (+) __HAL_JPEG_ENABLE             : Enable the JPEG peripheral.
      (+) __HAL_JPEG_DISABLE            : Disable the JPEG peripheral.
      (+) __HAL_JPEG_GET_FLAG           : Check the specified JPEG status flag.
      (+) __HAL_JPEG_CLEAR_FLAG         : Clear the specified JPEG status flag.
      (+) __HAL_JPEG_ENABLE_IT          : Enable the specified JPEG Interrupt.
      (+) __HAL_JPEG_DISABLE_IT         : Disable the specified JPEG Interrupt.
      (+) __HAL_JPEG_GET_IT_SOURCE      : returns the state of the specified JPEG Interrupt (Enabled or disabled).

  *** Callback registration ***
  =============================================

  The compilation define  USE_HAL_JPEG_REGISTER_CALLBACKS when set to 1
  allows the user to configure dynamically the driver callbacks.
  Use Functions HAL_JPEG_RegisterCallback() or HAL_JPEG_RegisterXXXCallback()
  to register an interrupt callback.

  Function HAL_JPEG_RegisterCallback() allows to register following callbacks:
    (+) EncodeCpltCallback : callback for end of encoding operation.
    (+) DecodeCpltCallback : callback for end of decoding operation.
    (+) ErrorCallback      : callback for error detection.
    (+) MspInitCallback    : JPEG MspInit.
    (+) MspDeInitCallback  : JPEG MspDeInit.
  This function takes as parameters the HAL peripheral handle, the Callback ID
  and a pointer to the user callback function.

  For specific callbacks InfoReadyCallback, GetDataCallback and DataReadyCallback use dedicated
  register callbacks : respectively HAL_JPEG_RegisterInfoReadyCallback(),
  HAL_JPEG_RegisterGetDataCallback() and HAL_JPEG_RegisterDataReadyCallback().

  Use function HAL_JPEG_UnRegisterCallback() to reset a callback to the default
  weak function.
  HAL_JPEG_UnRegisterCallback() takes as parameters the HAL peripheral handle,
  and the Callback ID.
  This function allows to reset following callbacks:
    (+) EncodeCpltCallback : callback for end of encoding operation.
    (+) DecodeCpltCallback : callback for end of decoding operation.
    (+) ErrorCallback      : callback for error detection.
    (+) MspInitCallback    : JPEG MspInit.
    (+) MspDeInitCallback  : JPEG MspDeInit.

  For callbacks InfoReadyCallback, GetDataCallback and DataReadyCallback use dedicated
  unregister callbacks : respectively HAL_JPEG_UnRegisterInfoReadyCallback(),
  HAL_JPEG_UnRegisterGetDataCallback() and HAL_JPEG_UnRegisterDataReadyCallback().

  By default, after the HAL_JPEG_Init() and when the state is HAL_JPEG_STATE_RESET
  all callbacks are set to the corresponding weak functions :
  examples HAL_JPEG_DecodeCpltCallback() , HAL_JPEG_GetDataCallback().
  Exception done for MspInit and MspDeInit functions that are
  reset to the legacy weak function in the HAL_JPEG_Init()/ HAL_JPEG_DeInit() only when
  these callbacks are null (not registered beforehand).
  if not, MspInit or MspDeInit are not null, the HAL_JPEG_Init() / HAL_JPEG_DeInit()
  keep and use the user MspInit/MspDeInit functions (registered beforehand)

  Callbacks can be registered/unregistered in HAL_JPEG_STATE_READY state only.
  Exception done MspInit/MspDeInit callbacks that can be registered/unregistered
  in HAL_JPEG_STATE_READY or HAL_JPEG_STATE_RESET state,
  thus registered (user) MspInit/DeInit callbacks can be used during the Init/DeInit.
  In that case first register the MspInit/MspDeInit user callbacks
  using HAL_JPEG_RegisterCallback() before calling HAL_JPEG_DeInit()
  or HAL_JPEG_Init() function.

  When The compilation define USE_HAL_JPEG_REGISTER_CALLBACKS is set to 0 or
  not defined, the callback registration feature is not available and all callbacks
  are set to the corresponding weak functions.

  @endverbatim
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm32h7xx_hal.h"

/** @addtogroup STM32H7xx_HAL_Driver
  * @{
  */

/** @defgroup JPEG JPEG
  * @brief JPEG HAL module driver.
  * @{
  */

#ifdef HAL_JPEG_MODULE_ENABLED

#if defined (JPEG)

/* Private define ------------------------------------------------------------*/
/** @addtogroup JPEG_Private_Constants
  * @{
  */
#define JPEG_TIMEOUT_VALUE  ((uint32_t)1000)     /* 1s */
#define JPEG_AC_HUFF_TABLE_SIZE  ((uint32_t)162) /* Huffman AC table size : 162 codes*/
#define JPEG_DC_HUFF_TABLE_SIZE  ((uint32_t)12)  /* Huffman AC table size : 12 codes*/

#define JPEG_FIFO_SIZE ((uint32_t)16U)             /* JPEG Input/Output HW FIFO size in words*/

#define JPEG_FIFO_TH_SIZE ((uint32_t)8U)              /* JPEG Input/Output HW FIFO Threshold in words*/

#define JPEG_INTERRUPT_MASK  ((uint32_t)0x0000007EU) /* JPEG Interrupt Mask*/

#define JPEG_CONTEXT_ENCODE          ((uint32_t)0x00000001) /* JPEG context : operation is encoding*/
#define JPEG_CONTEXT_DECODE          ((uint32_t)0x00000002) /* JPEG context : operation is decoding*/
#define JPEG_CONTEXT_OPERATION_MASK  ((uint32_t)0x00000003) /* JPEG context : operation Mask */

#define JPEG_CONTEXT_POLLING        ((uint32_t)0x00000004)  /* JPEG context : Transfer use Polling */
#define JPEG_CONTEXT_IT             ((uint32_t)0x00000008)  /* JPEG context : Transfer use Interrupt */
#define JPEG_CONTEXT_DMA            ((uint32_t)0x0000000C)  /* JPEG context : Transfer use DMA */
#define JPEG_CONTEXT_METHOD_MASK    ((uint32_t)0x0000000C)  /* JPEG context : Transfer Mask */


#define JPEG_CONTEXT_CONF_ENCODING  ((uint32_t)0x00000100)  /* JPEG context : encoding config done */

#define JPEG_CONTEXT_PAUSE_INPUT    ((uint32_t)0x00001000)  /* JPEG context : Pause Input */
#define JPEG_CONTEXT_PAUSE_OUTPUT   ((uint32_t)0x00002000)  /* JPEG context : Pause Output */

#define JPEG_CONTEXT_CUSTOM_TABLES  ((uint32_t)0x00004000)  /* JPEG context : Use custom quantization tables */

#define JPEG_CONTEXT_ENDING_DMA     ((uint32_t)0x00008000)  /* JPEG context : ending with DMA in progress */

#define JPEG_PROCESS_ONGOING        ((uint32_t)0x00000000)  /* Process is on going */
#define JPEG_PROCESS_DONE           ((uint32_t)0x00000001)  /* Process is done (ends) */
/**
  * @}
  */

/* Private typedef -----------------------------------------------------------*/
/** @addtogroup JPEG_Private_Types
  * @{
  */

/*
 JPEG Huffman Table Structure definition :
 This implementation of Huffman table structure is compliant with ISO/IEC 10918-1 standard , Annex C Huffman Table specification
 */
typedef struct
{
  /* These two fields directly represent the contents of a JPEG DHT marker */
  uint8_t Bits[16];        /*!< bits[k] = # of symbols with codes of length k bits, this parameter corresponds to BITS list in the Annex C */

  uint8_t HuffVal[162];    /*!< The symbols, in order of incremented code length, this parameter corresponds to HUFFVAL list in the Annex C */


} JPEG_ACHuffTableTypeDef;

typedef struct
{
  /* These two fields directly represent the contents of a JPEG DHT marker */
  uint8_t Bits[16];        /*!< bits[k] = # of symbols with codes of length k bits, this parameter corresponds to BITS list in the Annex C */

  uint8_t HuffVal[12];    /*!< The symbols, in order of incremented code length, this parameter corresponds to HUFFVAL list in the Annex C */


} JPEG_DCHuffTableTypeDef;

typedef struct
{
  uint8_t CodeLength[JPEG_AC_HUFF_TABLE_SIZE];      /*!< Code length  */

  uint32_t HuffmanCode[JPEG_AC_HUFF_TABLE_SIZE];    /*!< HuffmanCode */

} JPEG_AC_HuffCodeTableTypeDef;

typedef struct
{
  uint8_t CodeLength[JPEG_DC_HUFF_TABLE_SIZE];        /*!< Code length  */

  uint32_t HuffmanCode[JPEG_DC_HUFF_TABLE_SIZE];    /*!< HuffmanCode */

} JPEG_DC_HuffCodeTableTypeDef;
/**
  * @}
  */

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
/** @addtogroup JPEG_Private_Variables
  * @{
  */

static const JPEG_DCHuffTableTypeDef JPEG_DCLUM_HuffTable =
{
  { 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 },   /*Bits*/

  { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb }           /*HUFFVAL */

};

static const JPEG_DCHuffTableTypeDef JPEG_DCCHROM_HuffTable =
{
  { 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },  /*Bits*/

  { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb }          /*HUFFVAL */
};

static const JPEG_ACHuffTableTypeDef JPEG_ACLUM_HuffTable =
{
  { 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d },  /*Bits*/

  {
    0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,     /*HUFFVAL */
    0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
    0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
    0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
    0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
    0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
    0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
    0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
    0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
    0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
    0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
    0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
    0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
    0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
    0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
    0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
    0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
    0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
    0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
    0xf9, 0xfa
  }
};

static const JPEG_ACHuffTableTypeDef JPEG_ACCHROM_HuffTable =
{
  { 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 },   /*Bits*/

  {
    0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,      /*HUFFVAL */
    0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
    0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
    0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
    0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
    0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
    0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
    0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
    0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
    0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
    0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
    0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
    0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
    0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
    0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
    0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
    0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
    0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
    0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
    0xf9, 0xfa
  }
};

static const uint8_t JPEG_ZIGZAG_ORDER[JPEG_QUANT_TABLE_SIZE] =
{
  0,   1,   8,  16,   9,   2,   3,  10,
  17,  24,  32,  25,  18,  11,   4,   5,
  12,  19,  26,  33,  40,  48,  41,  34,
  27,  20,  13,   6,   7,  14,  21,  28,
  35,  42,  49,  56,  57,  50,  43,  36,
  29,  22,  15,  23,  30,  37,  44,  51,
  58,  59,  52,  45,  38,  31,  39,  46,
  53,  60,  61,  54,  47,  55,  62,  63
};
/**
  * @}
  */

/* Private function prototypes -----------------------------------------------*/
/** @addtogroup JPEG_Private_Functions_Prototypes
  * @{
  */

static HAL_StatusTypeDef JPEG_Bits_To_SizeCodes(uint8_t *Bits, uint8_t *Huffsize, uint32_t *Huffcode, uint32_t *LastK);
static HAL_StatusTypeDef JPEG_DCHuff_BitsVals_To_SizeCodes(JPEG_DCHuffTableTypeDef *DC_BitsValsTable,
                                                           JPEG_DC_HuffCodeTableTypeDef *DC_SizeCodesTable);
static HAL_StatusTypeDef JPEG_ACHuff_BitsVals_To_SizeCodes(JPEG_ACHuffTableTypeDef *AC_BitsValsTable,
                                                           JPEG_AC_HuffCodeTableTypeDef *AC_SizeCodesTable);
static HAL_StatusTypeDef JPEG_Set_HuffDC_Mem(JPEG_HandleTypeDef *hjpeg, JPEG_DCHuffTableTypeDef *HuffTableDC,
                                             const __IO uint32_t *DCTableAddress);
static HAL_StatusTypeDef JPEG_Set_HuffAC_Mem(JPEG_HandleTypeDef *hjpeg, JPEG_ACHuffTableTypeDef *HuffTableAC,
                                             const __IO uint32_t *ACTableAddress);
static HAL_StatusTypeDef JPEG_Set_HuffEnc_Mem(JPEG_HandleTypeDef *hjpeg);
static void JPEG_Set_Huff_DHTMem(JPEG_HandleTypeDef *hjpeg);
static uint32_t  JPEG_Set_Quantization_Mem(JPEG_HandleTypeDef *hjpeg, uint8_t *QTable,
                                                    __IO uint32_t *QTableAddress);
static void JPEG_SetColorYCBCR(JPEG_HandleTypeDef *hjpeg);
static void JPEG_SetColorGrayScale(JPEG_HandleTypeDef *hjpeg);
static void JPEG_SetColorCMYK(JPEG_HandleTypeDef *hjpeg);

static void JPEG_Init_Process(JPEG_HandleTypeDef *hjpeg);
static uint32_t JPEG_Process(JPEG_HandleTypeDef *hjpeg);
static void JPEG_ReadInputData(JPEG_HandleTypeDef *hjpeg, uint32_t nbRequestWords);
static void JPEG_StoreOutputData(JPEG_HandleTypeDef *hjpeg, uint32_t nbOutputWords);
static uint32_t JPEG_GetQuality(JPEG_HandleTypeDef *hjpeg);

static HAL_StatusTypeDef JPEG_DMA_StartProcess(JPEG_HandleTypeDef *hjpeg);
static void JPEG_DMA_ContinueProcess(JPEG_HandleTypeDef *hjpeg);
static void JPEG_DMA_EndProcess(JPEG_HandleTypeDef *hjpeg);
static void JPEG_DMA_PollResidualData(JPEG_HandleTypeDef *hjpeg);
static void JPEG_MDMAOutCpltCallback(MDMA_HandleTypeDef *hmdma);
static void JPEG_MDMAInCpltCallback(MDMA_HandleTypeDef *hmdma);
static void JPEG_MDMAErrorCallback(MDMA_HandleTypeDef *hmdma);
static void JPEG_MDMAOutAbortCallback(MDMA_HandleTypeDef *hmdma);

/**
  * @}
  */

/** @defgroup JPEG_Exported_Functions JPEG Exported Functions
  * @{
  */

/** @defgroup JPEG_Exported_Functions_Group1 Initialization and de-initialization functions
  *  @brief    Initialization and de-initialization functions.
  *
@verbatim
  ==============================================================================
              ##### Initialization and de-initialization functions #####
  ==============================================================================
    [..]  This section provides functions allowing to:
      (+) Initialize the JPEG peripheral and creates the associated handle
      (+) DeInitialize the JPEG peripheral

@endverbatim
  * @{
  */

/**
  * @brief  Initializes the JPEG according to the specified
  *         parameters in the JPEG_InitTypeDef and creates the associated handle.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)
{
  /* These are the sample quantization tables given in JPEG spec ISO/IEC 10918-1 standard , section K.1. */
  static const uint8_t JPEG_LUM_QuantTable[JPEG_QUANT_TABLE_SIZE] =
  {
    16,  11,  10,  16,  24,  40,  51,  61,
    12,  12,  14,  19,  26,  58,  60,  55,
    14,  13,  16,  24,  40,  57,  69,  56,
    14,  17,  22,  29,  51,  87,  80,  62,
    18,  22,  37,  56,  68, 109, 103,  77,
    24,  35,  55,  64,  81, 104, 113,  92,
    49,  64,  78,  87, 103, 121, 120, 101,
    72,  92,  95,  98, 112, 100, 103,  99
  };
  static const uint8_t JPEG_CHROM_QuantTable[JPEG_QUANT_TABLE_SIZE] =
  {
    17,  18,  24,  47,  99,  99,  99,  99,
    18,  21,  26,  66,  99,  99,  99,  99,
    24,  26,  56,  99,  99,  99,  99,  99,
    47,  66,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99,
    99,  99,  99,  99,  99,  99,  99,  99
  };

  /* Check the JPEG handle allocation */
  if (hjpeg == NULL)
  {
    return HAL_ERROR;
  }

#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
  if (hjpeg->State == HAL_JPEG_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hjpeg->Lock = HAL_UNLOCKED;

    hjpeg->InfoReadyCallback  = HAL_JPEG_InfoReadyCallback;  /* Legacy weak InfoReadyCallback  */
    hjpeg->EncodeCpltCallback = HAL_JPEG_EncodeCpltCallback; /* Legacy weak EncodeCpltCallback */
    hjpeg->DecodeCpltCallback = HAL_JPEG_DecodeCpltCallback; /* Legacy weak DecodeCpltCallback */
    hjpeg->ErrorCallback      = HAL_JPEG_ErrorCallback;      /* Legacy weak ErrorCallback      */
    hjpeg->GetDataCallback    = HAL_JPEG_GetDataCallback;    /* Legacy weak GetDataCallback    */
    hjpeg->DataReadyCallback  = HAL_JPEG_DataReadyCallback;  /* Legacy weak DataReadyCallback  */

    if (hjpeg->MspInitCallback == NULL)
    {
      hjpeg->MspInitCallback = HAL_JPEG_MspInit; /* Legacy weak MspInit  */
    }

    /* Init the low level hardware */
    hjpeg->MspInitCallback(hjpeg);
  }
#else
  if (hjpeg->State == HAL_JPEG_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hjpeg->Lock = HAL_UNLOCKED;

    /* Init the low level hardware : GPIO, CLOCK */
    HAL_JPEG_MspInit(hjpeg);
  }
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

  /* Change the JPEG state */
  hjpeg->State = HAL_JPEG_STATE_BUSY;

  /* Start the JPEG Core*/
  __HAL_JPEG_ENABLE(hjpeg);

  /* Stop the JPEG encoding/decoding process*/
  hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;

  /* Disable All Interrupts */
  __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_INTERRUPT_MASK);


  /* Flush input and output FIFOs*/
  hjpeg->Instance->CR |= JPEG_CR_IFF;
  hjpeg->Instance->CR |= JPEG_CR_OFF;

  /* Clear all flags */
  __HAL_JPEG_CLEAR_FLAG(hjpeg, JPEG_FLAG_ALL);

  /* init default quantization tables*/
  hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);
  hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);
  hjpeg->QuantTable2 = NULL;
  hjpeg->QuantTable3 = NULL;

  /* init the default Huffman tables*/
  if (JPEG_Set_HuffEnc_Mem(hjpeg) != HAL_OK)
  {
    hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;

    return HAL_ERROR;
  }

  /* Enable header processing*/
  hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;

  /* Reset JpegInCount and JpegOutCount */
  hjpeg->JpegInCount = 0;
  hjpeg->JpegOutCount = 0;

  /* Change the JPEG state */
  hjpeg->State = HAL_JPEG_STATE_READY;

  /* Reset the JPEG ErrorCode */
  hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;

  /*Clear the context filelds*/
  hjpeg->Context = 0;

  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  DeInitializes the JPEG peripheral.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_DeInit(JPEG_HandleTypeDef *hjpeg)
{
  /* Check the JPEG handle allocation */
  if (hjpeg == NULL)
  {
    return HAL_ERROR;
  }

#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
  if (hjpeg->MspDeInitCallback == NULL)
  {
    hjpeg->MspDeInitCallback = HAL_JPEG_MspDeInit; /* Legacy weak MspDeInit  */
  }

  /* DeInit the low level hardware */
  hjpeg->MspDeInitCallback(hjpeg);

#else
  /* DeInit the low level hardware: CLOCK, NVIC.*/
  HAL_JPEG_MspDeInit(hjpeg);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

  /* Change the JPEG state */
  hjpeg->State = HAL_JPEG_STATE_BUSY;

  /* Reset the JPEG ErrorCode */
  hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;

  /* Reset JpegInCount and JpegOutCount */
  hjpeg->JpegInCount = 0;
  hjpeg->JpegOutCount = 0;

  /* Change the JPEG state */
  hjpeg->State = HAL_JPEG_STATE_RESET;

  /*Clear the context fields*/
  hjpeg->Context = 0;

  /* Release Lock */
  __HAL_UNLOCK(hjpeg);

  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Initializes the JPEG MSP.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
__weak void HAL_JPEG_MspInit(JPEG_HandleTypeDef *hjpeg)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hjpeg);

  /* NOTE : This function Should not be modified, when the callback is needed,
            the HAL_JPEG_MspInit could be implemented in the user file
   */
}

/**
  * @brief  DeInitializes JPEG MSP.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
__weak void HAL_JPEG_MspDeInit(JPEG_HandleTypeDef *hjpeg)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hjpeg);

  /* NOTE : This function Should not be modified, when the callback is needed,
            the HAL_JPEG_MspDeInit could be implemented in the user file
   */
}

#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
/**
  * @brief  Register a User JPEG Callback
  *         To be used instead of the weak predefined callback
  * @param  hjpeg JPEG handle
  * @param  CallbackID ID of the callback to be registered
  *         This parameter can be one of the following values:
  *          @arg @ref HAL_JPEG_ENCODE_CPLT_CB_ID Encode Complete callback ID
  *          @arg @ref HAL_JPEG_DECODE_CPLT_CB_ID Decode Complete callback ID
  *          @arg @ref HAL_JPEG_ERROR_CB_ID Error callback ID
  *          @arg @ref HAL_JPEG_MSPINIT_CB_ID MspInit callback ID
  *          @arg @ref HAL_JPEG_MSPDEINIT_CB_ID MspDeInit callback ID
  * @param  pCallback pointer to the Callback function
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_RegisterCallback(JPEG_HandleTypeDef *hjpeg, HAL_JPEG_CallbackIDTypeDef CallbackID,
                                            pJPEG_CallbackTypeDef pCallback)
{
  HAL_StatusTypeDef status = HAL_OK;

  if (pCallback == NULL)
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    return HAL_ERROR;
  }
  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (HAL_JPEG_STATE_READY == hjpeg->State)
  {
    switch (CallbackID)
    {
      case HAL_JPEG_ENCODE_CPLT_CB_ID :
        hjpeg->EncodeCpltCallback = pCallback;
        break;

      case HAL_JPEG_DECODE_CPLT_CB_ID :
        hjpeg->DecodeCpltCallback = pCallback;
        break;

      case HAL_JPEG_ERROR_CB_ID :
        hjpeg->ErrorCallback = pCallback;
        break;

      case HAL_JPEG_MSPINIT_CB_ID :
        hjpeg->MspInitCallback = pCallback;
        break;

      case HAL_JPEG_MSPDEINIT_CB_ID :
        hjpeg->MspDeInitCallback = pCallback;
        break;

      default :
        /* Update the error code */
        hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
        /* Return error status */
        status =  HAL_ERROR;
        break;
    }
  }
  else if (HAL_JPEG_STATE_RESET == hjpeg->State)
  {
    switch (CallbackID)
    {
      case HAL_JPEG_MSPINIT_CB_ID :
        hjpeg->MspInitCallback = pCallback;
        break;

      case HAL_JPEG_MSPDEINIT_CB_ID :
        hjpeg->MspDeInitCallback = pCallback;
        break;

      default :
        /* Update the error code */
        hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
        /* Return error status */
        status =  HAL_ERROR;
        break;
    }
  }
  else
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    /* Return error status */
    status =  HAL_ERROR;
  }

  /* Release Lock */
  __HAL_UNLOCK(hjpeg);
  return status;
}

/**
  * @brief  Unregister a JPEG Callback
  *         JPEG callabck is redirected to the weak predefined callback
  * @param  hjpeg JPEG handle
  * @param  CallbackID ID of the callback to be unregistered
  *         This parameter can be one of the following values:
  *         This parameter can be one of the following values:
  *          @arg @ref HAL_JPEG_ENCODE_CPLT_CB_ID Encode Complete callback ID
  *          @arg @ref HAL_JPEG_DECODE_CPLT_CB_ID Decode Complete callback ID
  *          @arg @ref HAL_JPEG_ERROR_CB_ID Error callback ID
  *          @arg @ref HAL_JPEG_MSPINIT_CB_ID MspInit callback ID
  *          @arg @ref HAL_JPEG_MSPDEINIT_CB_ID MspDeInit callback ID
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_UnRegisterCallback(JPEG_HandleTypeDef *hjpeg, HAL_JPEG_CallbackIDTypeDef CallbackID)
{
  HAL_StatusTypeDef status = HAL_OK;

  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (HAL_JPEG_STATE_READY == hjpeg->State)
  {
    switch (CallbackID)
    {
      case HAL_JPEG_ENCODE_CPLT_CB_ID :
        hjpeg->EncodeCpltCallback = HAL_JPEG_EncodeCpltCallback; /* Legacy weak EncodeCpltCallback  */
        break;

      case HAL_JPEG_DECODE_CPLT_CB_ID :
        hjpeg->DecodeCpltCallback = HAL_JPEG_DecodeCpltCallback; /* Legacy weak DecodeCpltCallback  */
        break;

      case HAL_JPEG_ERROR_CB_ID :
        hjpeg->ErrorCallback = HAL_JPEG_ErrorCallback;           /* Legacy weak ErrorCallback  */
        break;

      case HAL_JPEG_MSPINIT_CB_ID :
        hjpeg->MspInitCallback = HAL_JPEG_MspInit;              /* Legacy weak MspInit  */
        break;

      case HAL_JPEG_MSPDEINIT_CB_ID :
        hjpeg->MspDeInitCallback = HAL_JPEG_MspDeInit;          /* Legacy weak MspDeInit  */
        break;

      default :
        /* Update the error code */
        hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
        /* Return error status */
        status =  HAL_ERROR;
        break;
    }
  }
  else if (HAL_JPEG_STATE_RESET == hjpeg->State)
  {
    switch (CallbackID)
    {
      case HAL_JPEG_MSPINIT_CB_ID :
        hjpeg->MspInitCallback = HAL_JPEG_MspInit;           /* Legacy weak MspInit  */
        break;

      case HAL_JPEG_MSPDEINIT_CB_ID :
        hjpeg->MspDeInitCallback = HAL_JPEG_MspDeInit;       /* Legacy weak MspInit  */
        break;

      default :
        /* Update the error code */
        hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
        /* Return error status */
        status =  HAL_ERROR;
        break;
    }
  }
  else
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    /* Return error status */
    status =  HAL_ERROR;
  }

  /* Release Lock */
  __HAL_UNLOCK(hjpeg);
  return status;
}

/**
  * @brief  Register Info Ready JPEG Callback
  *         To be used instead of the weak HAL_JPEG_InfoReadyCallback() predefined callback
  * @param  hjpeg JPEG handle
  * @param  pCallback pointer to the Info Ready Callback function
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_RegisterInfoReadyCallback(JPEG_HandleTypeDef *hjpeg,
                                                     pJPEG_InfoReadyCallbackTypeDef pCallback)
{
  HAL_StatusTypeDef status = HAL_OK;

  if (pCallback == NULL)
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    return HAL_ERROR;
  }
  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (HAL_JPEG_STATE_READY == hjpeg->State)
  {
    hjpeg->InfoReadyCallback = pCallback;
  }
  else
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    /* Return error status */
    status =  HAL_ERROR;
  }

  /* Release Lock */
  __HAL_UNLOCK(hjpeg);
  return status;
}

/**
  * @brief  UnRegister the Info Ready JPEG Callback
  *         Info Ready JPEG Callback is redirected to the weak HAL_JPEG_InfoReadyCallback() predefined callback
  * @param  hjpeg JPEG handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_UnRegisterInfoReadyCallback(JPEG_HandleTypeDef *hjpeg)
{
  HAL_StatusTypeDef status = HAL_OK;

  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (HAL_JPEG_STATE_READY == hjpeg->State)
  {
    hjpeg->InfoReadyCallback = HAL_JPEG_InfoReadyCallback; /* Legacy weak InfoReadyCallback  */
  }
  else
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    /* Return error status */
    status =  HAL_ERROR;
  }

  /* Release Lock */
  __HAL_UNLOCK(hjpeg);
  return status;
}

/**
  * @brief  Register Get Data JPEG Callback
  *         To be used instead of the weak HAL_JPEG_GetDataCallback() predefined callback
  * @param  hjpeg JPEG handle
  * @param  pCallback pointer to the Get Data Callback function
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_RegisterGetDataCallback(JPEG_HandleTypeDef *hjpeg, pJPEG_GetDataCallbackTypeDef pCallback)
{
  HAL_StatusTypeDef status = HAL_OK;

  if (pCallback == NULL)
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    return HAL_ERROR;
  }
  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (HAL_JPEG_STATE_READY == hjpeg->State)
  {
    hjpeg->GetDataCallback = pCallback;
  }
  else
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    /* Return error status */
    status =  HAL_ERROR;
  }

  /* Release Lock */
  __HAL_UNLOCK(hjpeg);
  return status;
}

/**
  * @brief  UnRegister the Get Data JPEG Callback
  *         Get Data JPEG Callback is redirected to the weak HAL_JPEG_GetDataCallback() predefined callback
  * @param  hjpeg JPEG handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_UnRegisterGetDataCallback(JPEG_HandleTypeDef *hjpeg)
{
  HAL_StatusTypeDef status = HAL_OK;

  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (HAL_JPEG_STATE_READY == hjpeg->State)
  {
    hjpeg->GetDataCallback = HAL_JPEG_GetDataCallback;  /* Legacy weak GetDataCallback  */
  }
  else
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    /* Return error status */
    status =  HAL_ERROR;
  }

  /* Release Lock */
  __HAL_UNLOCK(hjpeg);
  return status;
}

/**
  * @brief  Register Data Ready JPEG Callback
  *         To be used instead of the weak HAL_JPEG_DataReadyCallback() predefined callback
  * @param  hjpeg JPEG handle
  * @param  pCallback pointer to the Get Data Callback function
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_RegisterDataReadyCallback(JPEG_HandleTypeDef *hjpeg,
                                                     pJPEG_DataReadyCallbackTypeDef pCallback)
{
  HAL_StatusTypeDef status = HAL_OK;

  if (pCallback == NULL)
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    return HAL_ERROR;
  }
  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (HAL_JPEG_STATE_READY == hjpeg->State)
  {
    hjpeg->DataReadyCallback = pCallback;
  }
  else
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    /* Return error status */
    status =  HAL_ERROR;
  }

  /* Release Lock */
  __HAL_UNLOCK(hjpeg);
  return status;
}

/**
  * @brief  UnRegister the Data Ready JPEG Callback
  *         Get Data Ready Callback is redirected to the weak HAL_JPEG_DataReadyCallback() predefined callback
  * @param  hjpeg JPEG handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_UnRegisterDataReadyCallback(JPEG_HandleTypeDef *hjpeg)
{
  HAL_StatusTypeDef status = HAL_OK;

  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (HAL_JPEG_STATE_READY == hjpeg->State)
  {
    hjpeg->DataReadyCallback = HAL_JPEG_DataReadyCallback;  /* Legacy weak DataReadyCallback  */
  }
  else
  {
    /* Update the error code */
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_INVALID_CALLBACK;
    /* Return error status */
    status =  HAL_ERROR;
  }

  /* Release Lock */
  __HAL_UNLOCK(hjpeg);
  return status;
}

#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

/**
  * @}
  */

/** @defgroup JPEG_Exported_Functions_Group2 Configuration functions
  *  @brief    JPEG Configuration functions.
  *
@verbatim
  ==============================================================================
              ##### Configuration functions #####
  ==============================================================================
    [..]  This section provides functions allowing to:
      (+) HAL_JPEG_ConfigEncoding() : JPEG encoding configuration
      (+) HAL_JPEG_GetInfo() :  Extract the image configuration from the JPEG header during the decoding
      (+) HAL_JPEG_EnableHeaderParsing() :  Enable JPEG Header parsing for decoding
      (+) HAL_JPEG_DisableHeaderParsing() : Disable JPEG Header parsing for decoding
      (+) HAL_JPEG_SetUserQuantTables : Modify the default Quantization tables used for JPEG encoding.

@endverbatim
  * @{
  */

/**
  * @brief  Set the JPEG encoding configuration.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pConf pointer to a JPEG_ConfTypeDef structure that contains
  *         the encoding configuration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_ConfigEncoding(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pConf)
{
  uint32_t error;
  uint32_t numberMCU, hfactor, vfactor, hMCU, vMCU;

  /* Check the JPEG handle allocation */
  if ((hjpeg == NULL) || (pConf == NULL))
  {
    return HAL_ERROR;
  }
  else
  {
    /* Check the parameters */
    assert_param(IS_JPEG_COLORSPACE(pConf->ColorSpace));
    assert_param(IS_JPEG_CHROMASUBSAMPLING(pConf->ChromaSubsampling));
    assert_param(IS_JPEG_IMAGE_QUALITY(pConf->ImageQuality));

    /* Process Locked */
    __HAL_LOCK(hjpeg);

    if (hjpeg->State == HAL_JPEG_STATE_READY)
    {
      hjpeg->State = HAL_JPEG_STATE_BUSY;

      hjpeg->Conf.ColorSpace          =  pConf->ColorSpace;
      hjpeg->Conf.ChromaSubsampling   =  pConf->ChromaSubsampling;
      hjpeg->Conf.ImageHeight         =  pConf->ImageHeight;
      hjpeg->Conf.ImageWidth          =  pConf->ImageWidth;
      hjpeg->Conf.ImageQuality        =  pConf->ImageQuality;

      /* Reset the Color Space : by default only one quantization table is used*/
      hjpeg->Instance->CONFR1 &= ~JPEG_CONFR1_COLORSPACE;

      /* Set Number of color components*/
      if (hjpeg->Conf.ColorSpace == JPEG_GRAYSCALE_COLORSPACE)
      {
        /*Gray Scale is only one component 8x8 blocks i.e 4:4:4*/
        hjpeg->Conf.ChromaSubsampling = JPEG_444_SUBSAMPLING;

        JPEG_SetColorGrayScale(hjpeg);
        /* Set quantization table 0*/
        error = JPEG_Set_Quantization_Mem(hjpeg, hjpeg->QuantTable0, (hjpeg->Instance->QMEM0));
      }
      else if (hjpeg->Conf.ColorSpace == JPEG_YCBCR_COLORSPACE)
      {
        /*
           Set the Color Space for YCbCr : 2 quantization tables are used
           one for Luminance(Y) and one for both Chrominances (Cb & Cr)
          */
        hjpeg->Instance->CONFR1 |= JPEG_CONFR1_COLORSPACE_0;

        JPEG_SetColorYCBCR(hjpeg);

        /* Set quantization table 0*/
        error  = JPEG_Set_Quantization_Mem(hjpeg, hjpeg->QuantTable0, (hjpeg->Instance->QMEM0));
        /*By default quantization table 0 for component 0 and quantization table 1 for both components 1 and 2*/
        error |= JPEG_Set_Quantization_Mem(hjpeg, hjpeg->QuantTable1, (hjpeg->Instance->QMEM1));

        if ((hjpeg->Context & JPEG_CONTEXT_CUSTOM_TABLES) != 0UL)
        {
          /*Use user customized quantization tables , 1 table per component*/
          /* use 3 quantization tables , one for each component*/
          hjpeg->Instance->CONFR1 &= (~JPEG_CONFR1_COLORSPACE);
          hjpeg->Instance->CONFR1 |= JPEG_CONFR1_COLORSPACE_1;

          error |= JPEG_Set_Quantization_Mem(hjpeg, hjpeg->QuantTable2, (hjpeg->Instance->QMEM2));

          /*Use Quantization 1 table for component 1*/
          hjpeg->Instance->CONFR5 &= (~JPEG_CONFR5_QT);
          hjpeg->Instance->CONFR5 |=  JPEG_CONFR5_QT_0;

          /*Use Quantization 2 table for component 2*/
          hjpeg->Instance->CONFR6 &= (~JPEG_CONFR6_QT);
          hjpeg->Instance->CONFR6 |=  JPEG_CONFR6_QT_1;
        }
      }
      else /* ColorSpace == JPEG_CMYK_COLORSPACE */
      {
        JPEG_SetColorCMYK(hjpeg);

        /* Set quantization table 0*/
        error  = JPEG_Set_Quantization_Mem(hjpeg, hjpeg->QuantTable0, (hjpeg->Instance->QMEM0));
        /*By default quantization table 0 for All components*/

        if ((hjpeg->Context & JPEG_CONTEXT_CUSTOM_TABLES) != 0UL)
        {
          /*Use user customized quantization tables , 1 table per component*/
          /* use 4 quantization tables , one for each component*/
          hjpeg->Instance->CONFR1 |= JPEG_CONFR1_COLORSPACE;

          error |= JPEG_Set_Quantization_Mem(hjpeg, hjpeg->QuantTable1, (hjpeg->Instance->QMEM1));
          error |= JPEG_Set_Quantization_Mem(hjpeg, hjpeg->QuantTable2, (hjpeg->Instance->QMEM2));
          error |= JPEG_Set_Quantization_Mem(hjpeg, hjpeg->QuantTable3, (hjpeg->Instance->QMEM3));

          /*Use Quantization 1 table for component 1*/
          hjpeg->Instance->CONFR5 |=  JPEG_CONFR5_QT_0;

          /*Use Quantization 2 table for component 2*/
          hjpeg->Instance->CONFR6 |=  JPEG_CONFR6_QT_1;

          /*Use Quantization 3 table for component 3*/
          hjpeg->Instance->CONFR7 |=  JPEG_CONFR7_QT;
        }
      }

      if (error != 0UL)
      {
        hjpeg->ErrorCode = HAL_JPEG_ERROR_QUANT_TABLE;

        /* Process Unlocked */
        __HAL_UNLOCK(hjpeg);

        /* Set the JPEG State to ready */
        hjpeg->State = HAL_JPEG_STATE_READY;

        return  HAL_ERROR;
      }
      /* Set the image size*/
      /* set the number of lines*/
      MODIFY_REG(hjpeg->Instance->CONFR1, JPEG_CONFR1_YSIZE, ((hjpeg->Conf.ImageHeight & 0x0000FFFFUL) << 16));
      /* set the number of pixels per line*/
      MODIFY_REG(hjpeg->Instance->CONFR3, JPEG_CONFR3_XSIZE, ((hjpeg->Conf.ImageWidth & 0x0000FFFFUL) << 16));


      if (hjpeg->Conf.ChromaSubsampling == JPEG_420_SUBSAMPLING) /* 4:2:0*/
      {
        hfactor = 16;
        vfactor = 16;
      }
      else if (hjpeg->Conf.ChromaSubsampling == JPEG_422_SUBSAMPLING) /* 4:2:2*/
      {
        hfactor = 16;
        vfactor = 8;
      }
      else /* Default is 8x8 MCU,  4:4:4*/
      {
        hfactor = 8;
        vfactor = 8;
      }

      hMCU = (hjpeg->Conf.ImageWidth / hfactor);
      if ((hjpeg->Conf.ImageWidth % hfactor) != 0UL)
      {
        hMCU++; /*+1 for horizontal incomplete MCU */
      }

      vMCU = (hjpeg->Conf.ImageHeight / vfactor);
      if ((hjpeg->Conf.ImageHeight % vfactor) != 0UL)
      {
        vMCU++; /*+1 for vertical incomplete MCU */
      }

      numberMCU = (hMCU * vMCU) - 1UL; /* Bit Field JPEG_CONFR2_NMCU shall be set to NB_MCU - 1*/
      /* Set the number of MCU*/
      hjpeg->Instance->CONFR2 = (numberMCU & JPEG_CONFR2_NMCU);

      hjpeg->Context |= JPEG_CONTEXT_CONF_ENCODING;

      /* Process Unlocked */
      __HAL_UNLOCK(hjpeg);

      /* Set the JPEG State to ready */
      hjpeg->State = HAL_JPEG_STATE_READY;

      /* Return function status */
      return HAL_OK;
    }
    else
    {
      /* Process Unlocked */
      __HAL_UNLOCK(hjpeg);

      /* Return function status */
      return HAL_BUSY;
    }
  }
}

/**
  * @brief  Extract the image configuration from the JPEG header during the decoding
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pInfo pointer to a JPEG_ConfTypeDef structure that contains
  *         The JPEG decoded header informations
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
{
  uint32_t yblockNb, cBblockNb, cRblockNb;

  /* Check the JPEG handle allocation */
  if ((hjpeg == NULL) || (pInfo == NULL))
  {
    return HAL_ERROR;
  }

  /*Read the conf parameters */
  if ((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
  {
    pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;
  }
  else if ((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0UL)
  {
    pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;
  }
  else if ((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)
  {
    pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;
  }
  else
  {
    return HAL_ERROR;
  }

  pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000UL) >> 16;
  pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000UL) >> 16;

  if ((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))
  {
    yblockNb  = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;
    cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;
    cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;

    if ((yblockNb == 1UL) && (cBblockNb == 0UL) && (cRblockNb == 0UL))
    {
      pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/
    }
    else if ((yblockNb == 0UL) && (cBblockNb == 0UL) && (cRblockNb == 0UL))
    {
      pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    }
    else if ((yblockNb == 3UL) && (cBblockNb == 0UL) && (cRblockNb == 0UL))
    {
      pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;
    }
    else /*Default is 4:4:4*/
    {
      pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    }
  }
  else
  {
    pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
  }

  pInfo->ImageQuality = JPEG_GetQuality(hjpeg);

  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Enable JPEG Header parsing for decoding
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *               the configuration information for the JPEG.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_EnableHeaderParsing(JPEG_HandleTypeDef *hjpeg)
{
  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (hjpeg->State == HAL_JPEG_STATE_READY)
  {
    /* Change the JPEG state */
    hjpeg->State = HAL_JPEG_STATE_BUSY;

    /* Enable header processing*/
    hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;

    /* Process unlocked */
    __HAL_UNLOCK(hjpeg);

    /* Change the JPEG state */
    hjpeg->State = HAL_JPEG_STATE_READY;

    return HAL_OK;
  }
  else
  {
    /* Process unlocked */
    __HAL_UNLOCK(hjpeg);

    return HAL_BUSY;
  }
}

/**
  * @brief  Disable JPEG Header parsing for decoding
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *               the configuration information for the JPEG.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_DisableHeaderParsing(JPEG_HandleTypeDef *hjpeg)
{
  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (hjpeg->State == HAL_JPEG_STATE_READY)
  {
    /* Change the JPEG state */
    hjpeg->State = HAL_JPEG_STATE_BUSY;

    /* Disable header processing*/
    hjpeg->Instance->CONFR1 &= ~JPEG_CONFR1_HDR;

    /* Process unlocked */
    __HAL_UNLOCK(hjpeg);

    /* Change the JPEG state */
    hjpeg->State = HAL_JPEG_STATE_READY;

    return HAL_OK;
  }
  else
  {
    /* Process unlocked */
    __HAL_UNLOCK(hjpeg);

    return HAL_BUSY;
  }
}

/**
  * @brief  Modify the default Quantization tables used for JPEG encoding.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  QTable0  pointer to uint8_t , define the user quantification table for color component 1.
  *                  If NULL assume no need to update  the table and no error return
  * @param  QTable1  pointer to uint8_t , define the user quantification table for color component 2.
  *                  If NULL assume no need to update  the table and no error return.
  * @param  QTable2  pointer to uint8_t , define the user quantification table for color component 3,
  *                  If NULL assume no need to update  the table and no error return.
  * @param  QTable3  pointer to uint8_t , define the user quantification table for color component 4.
  *                  If NULL assume no need to update  the table and no error return.
  *
  * @retval HAL status
  */


HAL_StatusTypeDef  HAL_JPEG_SetUserQuantTables(JPEG_HandleTypeDef *hjpeg, uint8_t *QTable0, uint8_t *QTable1,
                                               uint8_t *QTable2, uint8_t *QTable3)
{
  /* Process Locked */
  __HAL_LOCK(hjpeg);

  if (hjpeg->State == HAL_JPEG_STATE_READY)
  {
    /* Change the DMA state */
    hjpeg->State = HAL_JPEG_STATE_BUSY;

    hjpeg->Context |= JPEG_CONTEXT_CUSTOM_TABLES;

    hjpeg->QuantTable0 = QTable0;
    hjpeg->QuantTable1 = QTable1;
    hjpeg->QuantTable2 = QTable2;
    hjpeg->QuantTable3 = QTable3;

    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    /* Change the DMA state */
    hjpeg->State = HAL_JPEG_STATE_READY;

    /* Return function status */
    return HAL_OK;
  }
  else
  {
    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    return HAL_BUSY;
  }
}

/**
  * @}
  */

/** @defgroup JPEG_Exported_Functions_Group3 encoding/decoding processing functions
  *  @brief   processing functions.
  *
@verbatim
  ==============================================================================
                      ##### JPEG processing functions #####
  ==============================================================================
    [..]  This section provides functions allowing to:
      (+) HAL_JPEG_Encode()     : JPEG encoding with polling process
      (+) HAL_JPEG_Decode()     : JPEG decoding with polling process
      (+) HAL_JPEG_Encode_IT()  : JPEG encoding with interrupt process
      (+) HAL_JPEG_Decode_IT()  : JPEG decoding with interrupt process
      (+) HAL_JPEG_Encode_DMA() : JPEG encoding with DMA process
      (+) HAL_JPEG_Decode_DMA() : JPEG decoding with DMA process
      (+) HAL_JPEG_Pause()      :   Pause the Input/Output processing
      (+) HAL_JPEG_Resume()     :  Resume the JPEG Input/Output processing
      (+) HAL_JPEG_ConfigInputBuffer()  : Config Encoding/Decoding Input Buffer
      (+) HAL_JPEG_ConfigOutputBuffer() : Config Encoding/Decoding Output Buffer
      (+) HAL_JPEG_Abort()              : Aborts the JPEG Encoding/Decoding

@endverbatim
  * @{
  */

/**
  * @brief  Starts JPEG encoding with polling processing
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pDataInMCU Pointer to the Input buffer
  * @param  InDataLength size in bytes Input buffer
  * @param  pDataOut Pointer to the jpeg output data buffer
  * @param  OutDataLength size in bytes of the Output buffer
  * @param  Timeout Specify Timeout value
  * @retval HAL status
  */
HAL_StatusTypeDef  HAL_JPEG_Encode(JPEG_HandleTypeDef *hjpeg, uint8_t *pDataInMCU, uint32_t InDataLength,
                                   uint8_t *pDataOut, uint32_t OutDataLength, uint32_t Timeout)
{
  uint32_t tickstart;

  /* Check the parameters */
  assert_param((InDataLength >= 4UL));
  assert_param((OutDataLength >= 4UL));

  /* Check In/out buffer allocation and size */
  if ((hjpeg == NULL) || (pDataInMCU == NULL) || (pDataOut == NULL))
  {
    return HAL_ERROR;
  }
  /* Process locked */
  __HAL_LOCK(hjpeg);

  if (hjpeg->State != HAL_JPEG_STATE_READY)
  {
    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    return HAL_BUSY;
  }

  if (hjpeg->State == HAL_JPEG_STATE_READY)
  {
    if ((hjpeg->Context & JPEG_CONTEXT_CONF_ENCODING) == JPEG_CONTEXT_CONF_ENCODING)
    {
      /*Change JPEG state*/
      hjpeg->State = HAL_JPEG_STATE_BUSY_ENCODING;

      /*Set the Context to Encode with Polling*/
      hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
      hjpeg->Context |= (JPEG_CONTEXT_ENCODE | JPEG_CONTEXT_POLLING);

      /* Get tick */
      tickstart = HAL_GetTick();

      /*Store In/out buffers pointers and size*/
      hjpeg->pJpegInBuffPtr = pDataInMCU;
      hjpeg->pJpegOutBuffPtr = pDataOut;
      hjpeg->InDataLength = InDataLength - (InDataLength % 4UL);    /* In Data length must be multiple of 4 Bytes (1 word)*/
      hjpeg->OutDataLength = OutDataLength - (OutDataLength % 4UL); /* Out Data length must be multiple of 4 Bytes (1 word)*/

      /*Reset In/out data counter */
      hjpeg->JpegInCount = 0;
      hjpeg->JpegOutCount = 0;

      /*Init decoding process*/
      JPEG_Init_Process(hjpeg);

      /*JPEG data processing : In/Out FIFO transfer*/
      while ((JPEG_Process(hjpeg) == JPEG_PROCESS_ONGOING))
      {
        if (Timeout != HAL_MAX_DELAY)
        {
          if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0UL))
          {

            /* Update error code */
            hjpeg->ErrorCode |= HAL_JPEG_ERROR_TIMEOUT;

            /* Process Unlocked */
            __HAL_UNLOCK(hjpeg);

            /*Change JPEG state*/
            hjpeg->State = HAL_JPEG_STATE_READY;

            return HAL_TIMEOUT;
          }
        }
      }

      /* Process Unlocked */
      __HAL_UNLOCK(hjpeg);

      /*Change JPEG state*/
      hjpeg->State = HAL_JPEG_STATE_READY;

    }
    else
    {
      /* Process Unlocked */
      __HAL_UNLOCK(hjpeg);

      return HAL_ERROR;
    }
  }
  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Starts JPEG decoding with polling processing
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pDataIn Pointer to the input data buffer
  * @param  InDataLength size in bytes Input buffer
  * @param  pDataOutMCU Pointer to the Output data buffer
  * @param  OutDataLength size in bytes of the Output buffer
  * @param  Timeout Specify Timeout value
  * @retval HAL status
  */
HAL_StatusTypeDef  HAL_JPEG_Decode(JPEG_HandleTypeDef *hjpeg, uint8_t *pDataIn, uint32_t InDataLength,
                                   uint8_t *pDataOutMCU, uint32_t OutDataLength, uint32_t Timeout)
{
  uint32_t tickstart;

  /* Check the parameters */
  assert_param((InDataLength >= 4UL));
  assert_param((OutDataLength >= 4UL));

  /* Check In/out buffer allocation and size */
  if ((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
  {
    return HAL_ERROR;
  }

  /* Process Locked */
  __HAL_LOCK(hjpeg);

  /* Get tick */
  tickstart = HAL_GetTick();

  if (hjpeg->State == HAL_JPEG_STATE_READY)
  {
    /*Change JPEG state*/
    hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;

    /*Set the Context to Decode with Polling*/
    /*Set the Context to Encode with Polling*/
    hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
    hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_POLLING);

    /*Store In/out buffers pointers and size*/
    hjpeg->pJpegInBuffPtr = pDataIn;
    hjpeg->pJpegOutBuffPtr = pDataOutMCU;
    hjpeg->InDataLength = InDataLength - (InDataLength % 4UL);    /*In Data length must be multiple of 4 Bytes (1 word)*/
    hjpeg->OutDataLength = OutDataLength - (OutDataLength % 4UL); /*Out Data length must be multiple of 4 Bytes (1 word)*/

    /*Reset In/out data counter */
    hjpeg->JpegInCount = 0;
    hjpeg->JpegOutCount = 0;

    /*Init decoding process*/
    JPEG_Init_Process(hjpeg);

    /*JPEG data processing : In/Out FIFO transfer*/
    while ((JPEG_Process(hjpeg) == JPEG_PROCESS_ONGOING))
    {
      if (Timeout != HAL_MAX_DELAY)
      {
        if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0UL))
        {

          /* Update error code */
          hjpeg->ErrorCode |= HAL_JPEG_ERROR_TIMEOUT;

          /* Process Unlocked */
          __HAL_UNLOCK(hjpeg);

          /*Change JPEG state*/
          hjpeg->State = HAL_JPEG_STATE_READY;

          return HAL_TIMEOUT;
        }
      }
    }

    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    /*Change JPEG state*/
    hjpeg->State = HAL_JPEG_STATE_READY;

  }
  else
  {
    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    return HAL_BUSY;
  }
  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Starts JPEG encoding with interrupt processing
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pDataInMCU Pointer to the Input buffer
  * @param  InDataLength size in bytes Input buffer
  * @param  pDataOut Pointer to the jpeg output data buffer
  * @param  OutDataLength size in bytes of the Output buffer
  * @retval HAL status
  */
HAL_StatusTypeDef  HAL_JPEG_Encode_IT(JPEG_HandleTypeDef *hjpeg, uint8_t *pDataInMCU, uint32_t InDataLength,
                                      uint8_t *pDataOut, uint32_t OutDataLength)
{
  /* Check the parameters */
  assert_param((InDataLength >= 4UL));
  assert_param((OutDataLength >= 4UL));

  /* Check In/out buffer allocation and size */
  if ((hjpeg == NULL) || (pDataInMCU == NULL) || (pDataOut == NULL))
  {
    return HAL_ERROR;
  }

  /* Process Locked */
  __HAL_LOCK(hjpeg);

  if (hjpeg->State != HAL_JPEG_STATE_READY)
  {
    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    return HAL_BUSY;
  }
  else
  {
    if ((hjpeg->Context & JPEG_CONTEXT_CONF_ENCODING) == JPEG_CONTEXT_CONF_ENCODING)
    {
      /*Change JPEG state*/
      hjpeg->State = HAL_JPEG_STATE_BUSY_ENCODING;

      /*Set the Context to Encode with IT*/
      hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
      hjpeg->Context |= (JPEG_CONTEXT_ENCODE | JPEG_CONTEXT_IT);

      /*Store In/out buffers pointers and size*/
      hjpeg->pJpegInBuffPtr = pDataInMCU;
      hjpeg->pJpegOutBuffPtr = pDataOut;
      hjpeg->InDataLength = InDataLength - (InDataLength % 4UL);    /*In Data length must be multiple of 4 Bytes (1 word)*/
      hjpeg->OutDataLength = OutDataLength - (OutDataLength % 4UL); /*Out Data length must be multiple of 4 Bytes (1 word)*/

      /*Reset In/out data counter */
      hjpeg->JpegInCount = 0;
      hjpeg->JpegOutCount = 0;

      /*Init decoding process*/
      JPEG_Init_Process(hjpeg);

    }
    else
    {
      /* Process Unlocked */
      __HAL_UNLOCK(hjpeg);

      return HAL_ERROR;
    }
  }
  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Starts JPEG decoding with interrupt processing
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pDataIn Pointer to the input data buffer
  * @param  InDataLength size in bytes Input buffer
  * @param  pDataOutMCU Pointer to the Output data buffer
  * @param  OutDataLength size in bytes of the Output buffer
  * @retval HAL status
  */
HAL_StatusTypeDef  HAL_JPEG_Decode_IT(JPEG_HandleTypeDef *hjpeg, uint8_t *pDataIn, uint32_t InDataLength,
                                      uint8_t *pDataOutMCU, uint32_t OutDataLength)
{
  /* Check the parameters */
  assert_param((InDataLength >= 4UL));
  assert_param((OutDataLength >= 4UL));

  /* Check In/out buffer allocation and size */
  if ((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
  {
    return HAL_ERROR;
  }

  /* Process Locked */
  __HAL_LOCK(hjpeg);

  if (hjpeg->State == HAL_JPEG_STATE_READY)
  {
    /*Change JPEG state*/
    hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;

    /*Set the Context to Decode with IT*/
    hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
    hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_IT);

    /*Store In/out buffers pointers and size*/
    hjpeg->pJpegInBuffPtr = pDataIn;
    hjpeg->pJpegOutBuffPtr = pDataOutMCU;
    hjpeg->InDataLength = InDataLength - (InDataLength % 4UL);    /*In Data length must be multiple of 4 Bytes (1 word)*/
    hjpeg->OutDataLength = OutDataLength - (OutDataLength % 4UL); /*Out Data length must be multiple of 4 Bytes (1 word)*/

    /*Reset In/out data counter */
    hjpeg->JpegInCount = 0;
    hjpeg->JpegOutCount = 0;

    /*Init decoding process*/
    JPEG_Init_Process(hjpeg);

  }
  else
  {
    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    return HAL_BUSY;
  }
  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Starts JPEG encoding with DMA processing
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pDataInMCU Pointer to the Input buffer
  * @param  InDataLength size in bytes Input buffer
  * @param  pDataOut Pointer to the jpeg output data buffer
  * @param  OutDataLength size in bytes of the Output buffer
  * @retval HAL status
  */
HAL_StatusTypeDef  HAL_JPEG_Encode_DMA(JPEG_HandleTypeDef *hjpeg, uint8_t *pDataInMCU, uint32_t InDataLength,
                                       uint8_t *pDataOut, uint32_t OutDataLength)
{
  /* Check the parameters */
  assert_param((InDataLength >= 4UL));
  assert_param((OutDataLength >= 4UL));

  /* Check In/out buffer allocation and size */
  if ((hjpeg == NULL) || (pDataInMCU == NULL) || (pDataOut == NULL))
  {
    return HAL_ERROR;
  }

  /* Process Locked */
  __HAL_LOCK(hjpeg);

  if (hjpeg->State != HAL_JPEG_STATE_READY)
  {
    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    return HAL_BUSY;
  }
  else
  {
    if ((hjpeg->Context & JPEG_CONTEXT_CONF_ENCODING) == JPEG_CONTEXT_CONF_ENCODING)
    {
      /*Change JPEG state*/
      hjpeg->State = HAL_JPEG_STATE_BUSY_ENCODING;

      /*Set the Context to Encode with DMA*/
      hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
      hjpeg->Context |= (JPEG_CONTEXT_ENCODE | JPEG_CONTEXT_DMA);

      /*Store In/out buffers pointers and size*/
      hjpeg->pJpegInBuffPtr = pDataInMCU;
      hjpeg->pJpegOutBuffPtr = pDataOut;
      hjpeg->InDataLength = InDataLength;
      hjpeg->OutDataLength = OutDataLength;

      /*Reset In/out data counter */
      hjpeg->JpegInCount = 0;
      hjpeg->JpegOutCount = 0;

      /*Init decoding process*/
      JPEG_Init_Process(hjpeg);

      /* JPEG encoding process using DMA */
      if (JPEG_DMA_StartProcess(hjpeg) != HAL_OK)
      {
        /* Update State */
        hjpeg->State = HAL_JPEG_STATE_ERROR;
        /* Process Unlocked */
        __HAL_UNLOCK(hjpeg);

        return HAL_ERROR;
      }

    }
    else
    {
      /* Process Unlocked */
      __HAL_UNLOCK(hjpeg);

      return HAL_ERROR;
    }
  }
  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Starts JPEG decoding with DMA processing
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pDataIn Pointer to the input data buffer
  * @param  InDataLength size in bytes Input buffer
  * @param  pDataOutMCU Pointer to the Output data buffer
  * @param  OutDataLength size in bytes of the Output buffer
  * @retval HAL status
  */
HAL_StatusTypeDef  HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint8_t *pDataIn, uint32_t InDataLength,
                                       uint8_t *pDataOutMCU, uint32_t OutDataLength)
{
  /* Check the parameters */
  assert_param((InDataLength >= 4UL));
  assert_param((OutDataLength >= 4UL));

  /* Check In/out buffer allocation and size */
  if ((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
  {
    return HAL_ERROR;
  }

  /* Process Locked */
  __HAL_LOCK(hjpeg);

  if (hjpeg->State == HAL_JPEG_STATE_READY)
  {
    /*Change JPEG state*/
    hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;

    /*Set the Context to Decode with DMA*/
    hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
    hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);

    /*Store In/out buffers pointers and size*/
    hjpeg->pJpegInBuffPtr = pDataIn;
    hjpeg->pJpegOutBuffPtr = pDataOutMCU;
    hjpeg->InDataLength = InDataLength;
    hjpeg->OutDataLength = OutDataLength;

    /*Reset In/out data counter */
    hjpeg->JpegInCount = 0;
    hjpeg->JpegOutCount = 0;

    /*Init decoding process*/
    JPEG_Init_Process(hjpeg);

    /* JPEG decoding process using DMA */
    if (JPEG_DMA_StartProcess(hjpeg) != HAL_OK)
    {
      /* Update State */
      hjpeg->State = HAL_JPEG_STATE_ERROR;
      /* Process Unlocked */
      __HAL_UNLOCK(hjpeg);

      return HAL_ERROR;
    }
  }
  else
  {
    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    return HAL_BUSY;
  }
  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Pause the JPEG Input/Output processing
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  XferSelection This parameter can be one of the following values :
  *                           JPEG_PAUSE_RESUME_INPUT : Pause Input processing
  *                           JPEG_PAUSE_RESUME_OUTPUT: Pause Output processing
  *                           JPEG_PAUSE_RESUME_INPUT_OUTPUT: Pause Input and Output processing
  * @retval HAL status
  */
HAL_StatusTypeDef  HAL_JPEG_Pause(JPEG_HandleTypeDef *hjpeg, uint32_t XferSelection)
{
  uint32_t mask = 0;

  assert_param(IS_JPEG_PAUSE_RESUME_STATE(XferSelection));

  if ((hjpeg->Context & JPEG_CONTEXT_METHOD_MASK) == JPEG_CONTEXT_DMA)
  {
    if ((XferSelection & JPEG_PAUSE_RESUME_INPUT) == JPEG_PAUSE_RESUME_INPUT)
    {
      hjpeg->Context |= JPEG_CONTEXT_PAUSE_INPUT;
    }
    if ((XferSelection & JPEG_PAUSE_RESUME_OUTPUT) == JPEG_PAUSE_RESUME_OUTPUT)
    {
      hjpeg->Context |= JPEG_CONTEXT_PAUSE_OUTPUT;
    }

  }
  else if ((hjpeg->Context & JPEG_CONTEXT_METHOD_MASK) == JPEG_CONTEXT_IT)
  {

    if ((XferSelection & JPEG_PAUSE_RESUME_INPUT) == JPEG_PAUSE_RESUME_INPUT)
    {
      hjpeg->Context |= JPEG_CONTEXT_PAUSE_INPUT;
      mask |= (JPEG_IT_IFT | JPEG_IT_IFNF);
    }
    if ((XferSelection & JPEG_PAUSE_RESUME_OUTPUT) == JPEG_PAUSE_RESUME_OUTPUT)
    {
      hjpeg->Context |= JPEG_CONTEXT_PAUSE_OUTPUT;
      mask |= (JPEG_IT_OFT | JPEG_IT_OFNE | JPEG_IT_EOC);
    }
    __HAL_JPEG_DISABLE_IT(hjpeg, mask);

  }
  else
  {
    /* Nothing to do */
  }

  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Resume the JPEG Input/Output processing
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  XferSelection This parameter can be one of the following values :
  *                           JPEG_PAUSE_RESUME_INPUT : Resume Input processing
  *                           JPEG_PAUSE_RESUME_OUTPUT: Resume Output processing
  *                           JPEG_PAUSE_RESUME_INPUT_OUTPUT: Resume Input and Output processing
  * @retval HAL status
  */
HAL_StatusTypeDef  HAL_JPEG_Resume(JPEG_HandleTypeDef *hjpeg, uint32_t XferSelection)
{
  uint32_t mask = 0;
  uint32_t xfrSize;

  assert_param(IS_JPEG_PAUSE_RESUME_STATE(XferSelection));

  if ((hjpeg->Context & (JPEG_CONTEXT_PAUSE_INPUT | JPEG_CONTEXT_PAUSE_OUTPUT)) == 0UL)
  {
    /* if nothing paused to resume return error*/
    return HAL_ERROR;
  }

  if ((hjpeg->Context & JPEG_CONTEXT_METHOD_MASK) == JPEG_CONTEXT_DMA)
  {

    if ((XferSelection & JPEG_PAUSE_RESUME_INPUT) == JPEG_PAUSE_RESUME_INPUT)
    {
      hjpeg->Context &= (~JPEG_CONTEXT_PAUSE_INPUT);
      /*if the MDMA In is triggred with JPEG In FIFO Threshold flag
        then MDMA In buffer size is 32 bytes

        else (MDMA In is triggred with JPEG In FIFO not full flag)
        then MDMA In buffer size is 4 bytes
        */
      xfrSize = hjpeg->hdmain->Init.BufferTransferLength;

      if (xfrSize == 0UL)
      {
        hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
        hjpeg->State = HAL_JPEG_STATE_ERROR;
        return HAL_ERROR;
      }
      /*MDMA transfer size (BNDTR) must be a multiple of MDMA buffer size (TLEN)*/
      hjpeg->InDataLength = hjpeg->InDataLength - (hjpeg->InDataLength % xfrSize);


      if (hjpeg->InDataLength > 0UL)
      {
        /* Start DMA FIFO In transfer */
        if (HAL_MDMA_Start_IT(hjpeg->hdmain, (uint32_t)hjpeg->pJpegInBuffPtr, (uint32_t)&hjpeg->Instance->DIR,
                              hjpeg->InDataLength, 1) != HAL_OK)
        {
          hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
          hjpeg->State = HAL_JPEG_STATE_ERROR;
          return HAL_ERROR;
        }
      }
    }
    if ((XferSelection & JPEG_PAUSE_RESUME_OUTPUT) == JPEG_PAUSE_RESUME_OUTPUT)
    {
      hjpeg->Context &= (~JPEG_CONTEXT_PAUSE_OUTPUT);

      if ((hjpeg->Context & JPEG_CONTEXT_ENDING_DMA) != 0UL)
      {
        JPEG_DMA_PollResidualData(hjpeg);
      }
      else
      {
        /*if the MDMA Out is triggred with JPEG Out FIFO Threshold flag
          then MDMA out buffer size is 32 bytes
          else (MDMA Out is triggred with JPEG Out FIFO not empty flag)
          then MDMA buffer size is 4 bytes
          */
        xfrSize = hjpeg->hdmaout->Init.BufferTransferLength;

        if (xfrSize == 0UL)
        {
          hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
          hjpeg->State = HAL_JPEG_STATE_ERROR;
          return HAL_ERROR;
        }
        /*MDMA transfer size (BNDTR) must be a multiple of MDMA buffer size (TLEN)*/
        hjpeg->OutDataLength = hjpeg->OutDataLength - (hjpeg->OutDataLength % xfrSize);

        /* Start DMA FIFO Out transfer */
        if (HAL_MDMA_Start_IT(hjpeg->hdmaout, (uint32_t)&hjpeg->Instance->DOR, (uint32_t)hjpeg->pJpegOutBuffPtr,
                              hjpeg->OutDataLength, 1) != HAL_OK)
        {
          hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
          hjpeg->State = HAL_JPEG_STATE_ERROR;
          return HAL_ERROR;
        }
      }

    }

  }
  else if ((hjpeg->Context & JPEG_CONTEXT_METHOD_MASK) == JPEG_CONTEXT_IT)
  {
    if ((XferSelection & JPEG_PAUSE_RESUME_INPUT) == JPEG_PAUSE_RESUME_INPUT)
    {
      hjpeg->Context &= (~JPEG_CONTEXT_PAUSE_INPUT);
      mask |= (JPEG_IT_IFT | JPEG_IT_IFNF);
    }
    if ((XferSelection & JPEG_PAUSE_RESUME_OUTPUT) == JPEG_PAUSE_RESUME_OUTPUT)
    {
      hjpeg->Context &= (~JPEG_CONTEXT_PAUSE_OUTPUT);
      mask |= (JPEG_IT_OFT | JPEG_IT_OFNE | JPEG_IT_EOC);
    }
    __HAL_JPEG_ENABLE_IT(hjpeg, mask);

  }
  else
  {
    /* Nothing to do */
  }

  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Config Encoding/Decoding Input Buffer.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module.
  * @param  pNewInputBuffer Pointer to the new input data buffer
  * @param  InDataLength Size in bytes of the new Input data buffer
  * @retval HAL status
  */
void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)
{
  hjpeg->pJpegInBuffPtr =  pNewInputBuffer;
  hjpeg->InDataLength = InDataLength;
}

/**
  * @brief  Config Encoding/Decoding Output Buffer.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module.
  * @param  pNewOutputBuffer Pointer to the new output data buffer
  * @param  OutDataLength Size in bytes of the new Output data buffer
  * @retval HAL status
  */
void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)
{
  hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;
  hjpeg->OutDataLength = OutDataLength;
}

/**
  * @brief  Aborts the JPEG Encoding/Decoding.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_JPEG_Abort(JPEG_HandleTypeDef *hjpeg)
{
  uint32_t tickstart, tmpContext;
  tmpContext = hjpeg->Context;

  /*Reset the Context operation and method*/
  hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK | JPEG_CONTEXT_ENDING_DMA);

  if ((tmpContext & JPEG_CONTEXT_METHOD_MASK) == JPEG_CONTEXT_DMA)
  {
    /* Stop the DMA In/out Xfer*/
    if (HAL_MDMA_Abort(hjpeg->hdmaout) != HAL_OK)
    {
      if (hjpeg->hdmaout->ErrorCode == HAL_MDMA_ERROR_TIMEOUT)
      {
        hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
      }
    }
    if (HAL_MDMA_Abort(hjpeg->hdmain) != HAL_OK)
    {
      if (hjpeg->hdmain->ErrorCode == HAL_MDMA_ERROR_TIMEOUT)
      {
        hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
      }
    }

  }

  /* Stop the JPEG encoding/decoding process*/
  hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;

  /* Get tick */
  tickstart = HAL_GetTick();

  /* Check if the JPEG Codec is effectively disabled */
  while (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_COF) != 0UL)
  {
    /* Check for the Timeout */
    if ((HAL_GetTick() - tickstart) > JPEG_TIMEOUT_VALUE)
    {
      /* Update error code */
      hjpeg->ErrorCode |= HAL_JPEG_ERROR_TIMEOUT;

      /* Change the DMA state */
      hjpeg->State = HAL_JPEG_STATE_ERROR;
      break;
    }
  }

  /* Disable All Interrupts */
  __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_INTERRUPT_MASK);


  /* Flush input and output FIFOs*/
  hjpeg->Instance->CR |= JPEG_CR_IFF;
  hjpeg->Instance->CR |= JPEG_CR_OFF;

  /* Clear all flags */
  __HAL_JPEG_CLEAR_FLAG(hjpeg, JPEG_FLAG_ALL);

  /* Reset JpegInCount and JpegOutCount */
  hjpeg->JpegInCount = 0;
  hjpeg->JpegOutCount = 0;

  /*Reset the Context Pause*/
  hjpeg->Context &= ~(JPEG_CONTEXT_PAUSE_INPUT | JPEG_CONTEXT_PAUSE_OUTPUT);

  /* Change the DMA state*/
  if (hjpeg->ErrorCode != HAL_JPEG_ERROR_NONE)
  {
    hjpeg->State = HAL_JPEG_STATE_ERROR;
    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);
    /* Return function status */
    return HAL_ERROR;
  }
  else
  {
    hjpeg->State = HAL_JPEG_STATE_READY;
    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);
    /* Return function status */
    return HAL_OK;
  }

}


/**
  * @}
  */

/** @defgroup JPEG_Exported_Functions_Group4 JPEG Decode/Encode callback functions
  *  @brief   JPEG process callback functions.
  *
@verbatim
  ==============================================================================
              #####  JPEG Decode and Encode callback functions  #####
  ==============================================================================
    [..]  This section provides callback functions:
      (+) HAL_JPEG_InfoReadyCallback()  : Decoding JPEG Info ready callback
      (+) HAL_JPEG_EncodeCpltCallback() : Encoding complete callback.
      (+) HAL_JPEG_DecodeCpltCallback() : Decoding complete callback.
      (+) HAL_JPEG_ErrorCallback()      : JPEG error callback.
      (+) HAL_JPEG_GetDataCallback()    : Get New Data chunk callback.
      (+) HAL_JPEG_DataReadyCallback()  : Decoded/Encoded Data ready  callback.

@endverbatim
  * @{
  */

/**
  * @brief  Decoding JPEG Info ready callback.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pInfo pointer to a JPEG_ConfTypeDef structure that contains
  *         The JPEG decoded header informations
  * @retval None
  */
__weak void HAL_JPEG_InfoReadyCallback(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hjpeg);
  UNUSED(pInfo);

  /* NOTE : This function Should not be modified, when the callback is needed,
            the HAL_JPEG_HeaderParsingCpltCallback could be implemented in the user file
   */
}

/**
  * @brief  Encoding complete callback.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
__weak void HAL_JPEG_EncodeCpltCallback(JPEG_HandleTypeDef *hjpeg)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hjpeg);

  /* NOTE : This function Should not be modified, when the callback is needed,
            the HAL_JPEG_EncodeCpltCallback could be implemented in the user file
   */
}

/**
  * @brief  Decoding complete callback.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
__weak void HAL_JPEG_DecodeCpltCallback(JPEG_HandleTypeDef *hjpeg)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hjpeg);

  /* NOTE : This function Should not be modified, when the callback is needed,
            the HAL_JPEG_EncodeCpltCallback could be implemented in the user file
   */
}

/**
  * @brief  JPEG error callback.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
__weak void HAL_JPEG_ErrorCallback(JPEG_HandleTypeDef *hjpeg)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hjpeg);

  /* NOTE : This function Should not be modified, when the callback is needed,
            the HAL_JPEG_ErrorCallback could be implemented in the user file
   */
}

/**
  * @brief  Get New Data chunk callback.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  NbDecodedData Number of consummed data in the previous chunk in bytes
  * @retval None
  */
__weak void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hjpeg);
  UNUSED(NbDecodedData);

  /* NOTE : This function Should not be modified, when the callback is needed,
            the HAL_JPEG_GetDataCallback could be implemented in the user file
   */
}

/**
  * @brief  Decoded/Encoded Data ready  callback.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  pDataOut pointer to the output data buffer
  * @param  OutDataLength number in bytes of data available in the specified output buffer
  * @retval None
  */
__weak void HAL_JPEG_DataReadyCallback(JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hjpeg);
  UNUSED(pDataOut);
  UNUSED(OutDataLength);

  /* NOTE : This function Should not be modified, when the callback is needed,
            the HAL_JPEG_DataReadyCallback could be implemented in the user file
   */
}

/**
  * @}
  */


/** @defgroup JPEG_Exported_Functions_Group5 JPEG IRQ handler management
  *  @brief   JPEG IRQ handler.
  *
@verbatim
  ==============================================================================
                ##### JPEG IRQ handler management #####
  ==============================================================================
    [..]  This section provides JPEG IRQ handler function.
      (+) HAL_JPEG_IRQHandler()  : handles JPEG interrupt request

@endverbatim
  * @{
  */

/**
  * @brief  This function handles JPEG interrupt request.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
void HAL_JPEG_IRQHandler(JPEG_HandleTypeDef *hjpeg)
{
  switch (hjpeg->State)
  {
    case HAL_JPEG_STATE_BUSY_ENCODING:
    case HAL_JPEG_STATE_BUSY_DECODING:
      /* continue JPEG data encoding/Decoding*/
      /* JPEG data processing : In/Out FIFO transfer*/
      if ((hjpeg->Context & JPEG_CONTEXT_METHOD_MASK) == JPEG_CONTEXT_IT)
      {
        (void) JPEG_Process(hjpeg);
      }
      else if ((hjpeg->Context & JPEG_CONTEXT_METHOD_MASK) == JPEG_CONTEXT_DMA)
      {
        JPEG_DMA_ContinueProcess(hjpeg);
      }
      else
      {
        /* Nothing to do */
      }
      break;

    default:
      break;
  }
}

/**
  * @}
  */

/** @defgroup JPEG_Exported_Functions_Group6 Peripheral State functions
  *  @brief   Peripheral State functions.
  *
@verbatim
  ==============================================================================
                    ##### Peripheral State and Error functions #####
  ==============================================================================
    [..]  This section provides JPEG State and Errors function.
      (+) HAL_JPEG_GetState()  : permits to get in run-time the JPEG state.
      (+) HAL_JPEG_GetError()  : Returns the JPEG error code if any.

@endverbatim
  * @{
  */

/**
  * @brief  Returns the JPEG state.
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval JPEG state
  */
HAL_JPEG_STATETypeDef HAL_JPEG_GetState(JPEG_HandleTypeDef *hjpeg)
{
  return hjpeg->State;
}

/**
  * @brief  Return the JPEG error code
  * @param  hjpeg  pointer to a JPEG_HandleTypeDef structure that contains
  *              the configuration information for the specified JPEG.
  * @retval JPEG Error Code
  */
uint32_t HAL_JPEG_GetError(JPEG_HandleTypeDef *hjpeg)
{
  return hjpeg->ErrorCode;
}

/**
  * @}
  */

/**
  * @}
  */


/** @addtogroup JPEG_Private_Functions
  * @{
  */

/**
  * @brief  Generates Huffman sizes/Codes Table from Bits/vals Table
  * @param  Bits pointer to bits table
  * @param  Huffsize pointer to sizes table
  * @param  Huffcode pointer to codes table
  * @param  LastK pointer to last Coeff (table dimmension)
  * @retval HAL status
  */
static HAL_StatusTypeDef JPEG_Bits_To_SizeCodes(uint8_t *Bits, uint8_t *Huffsize, uint32_t *Huffcode, uint32_t *LastK)
{
  uint32_t i, p, l, code, si;

  /* Figure C.1: Generation of table of Huffman code sizes */
  p = 0;
  for (l = 0; l < 16UL; l++)
  {
    i = (uint32_t)Bits[l];
    if ((p + i) > 256UL)
    {
      /* check for table overflow */
      return HAL_ERROR;
    }
    while (i != 0UL)
    {
      Huffsize[p] = (uint8_t) l + 1U;
      p++;
      i--;
    }
  }
  Huffsize[p] = 0;
  *LastK = p;

  /* Figure C.2: Generation of table of Huffman codes */
  code = 0;
  si = Huffsize[0];
  p = 0;
  while (Huffsize[p] != 0U)
  {
    while (((uint32_t) Huffsize[p]) == si)
    {
      Huffcode[p] = code;
      p++;
      code++;
    }
    /* code must fit in "size" bits (si), no code is allowed to be all ones*/
    if(si > 31UL)
    {
      return HAL_ERROR;
    }
    if (((uint32_t) code) >= (((uint32_t) 1) << si))
    {
      return HAL_ERROR;
    }
    code <<= 1;
    si++;
  }
  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Transform a Bits/Vals AC Huffman table to sizes/Codes huffman Table
  *         that can programmed to the JPEG encoder registers
  * @param  AC_BitsValsTable pointer to AC huffman bits/vals table
  * @param  AC_SizeCodesTable pointer to AC huffman Sizes/Codes table
  * @retval HAL status
  */
static HAL_StatusTypeDef JPEG_ACHuff_BitsVals_To_SizeCodes(JPEG_ACHuffTableTypeDef *AC_BitsValsTable,
                                                           JPEG_AC_HuffCodeTableTypeDef *AC_SizeCodesTable)
{
  HAL_StatusTypeDef error;
  uint8_t huffsize[257];
  uint32_t huffcode[257];
  uint32_t k;
  uint32_t l, lsb, msb;
  uint32_t lastK;

  error = JPEG_Bits_To_SizeCodes(AC_BitsValsTable->Bits, huffsize, huffcode, &lastK);
  if (error != HAL_OK)
  {
    return  error;
  }

  /* Figure C.3: Ordering procedure for encoding procedure code tables */
  k = 0;

  while (k < lastK)
  {
    l = AC_BitsValsTable->HuffVal[k];
    if (l == 0UL)
    {
      l = 160; /*l = 0x00 EOB code*/
    }
    else if (l == 0xF0UL) /* l = 0xF0 ZRL code*/
    {
      l = 161;
    }
    else
    {
      msb = (l & 0xF0UL) >> 4;
      lsb = (l & 0x0FUL);
      l = (msb * 10UL) + lsb - 1UL;
    }
    if (l >= JPEG_AC_HUFF_TABLE_SIZE)
    {
      return HAL_ERROR; /* Huffman Table overflow error*/
    }
    else
    {
      AC_SizeCodesTable->HuffmanCode[l] = huffcode[k];
      AC_SizeCodesTable->CodeLength[l] = huffsize[k] - 1U;
      k++;
    }
  }

  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Transform a Bits/Vals DC Huffman table to sizes/Codes huffman Table
  *         that can programmed to the JPEG encoder registers
  * @param  DC_BitsValsTable pointer to DC huffman bits/vals table
  * @param  DC_SizeCodesTable pointer to DC huffman Sizes/Codes table
  * @retval HAL status
  */
static HAL_StatusTypeDef JPEG_DCHuff_BitsVals_To_SizeCodes(JPEG_DCHuffTableTypeDef *DC_BitsValsTable,
                                                           JPEG_DC_HuffCodeTableTypeDef *DC_SizeCodesTable)
{
  HAL_StatusTypeDef error;

  uint32_t k;
  uint32_t l;
  uint32_t lastK;
  uint8_t huffsize[257];
  uint32_t huffcode[257];
  error = JPEG_Bits_To_SizeCodes(DC_BitsValsTable->Bits, huffsize, huffcode, &lastK);
  if (error != HAL_OK)
  {
    return  error;
  }
  /* Figure C.3: ordering procedure for encoding procedure code tables */
  k = 0;

  while (k < lastK)
  {
    l = DC_BitsValsTable->HuffVal[k];
    if (l >= JPEG_DC_HUFF_TABLE_SIZE)
    {
      return HAL_ERROR; /* Huffman Table overflow error*/
    }
    else
    {
      DC_SizeCodesTable->HuffmanCode[l] = huffcode[k];
      DC_SizeCodesTable->CodeLength[l] = huffsize[k] - 1U;
      k++;
    }
  }

  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Set the JPEG register with an DC huffman table at the given DC table address
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  HuffTableDC pointer to DC huffman table
  * @param  DCTableAddress Encoder DC huffman table address it could be HUFFENC_DC0 or HUFFENC_DC1.
  * @retval HAL status
  */
static HAL_StatusTypeDef JPEG_Set_HuffDC_Mem(JPEG_HandleTypeDef *hjpeg, JPEG_DCHuffTableTypeDef *HuffTableDC,
                                             const __IO uint32_t *DCTableAddress)
{
  HAL_StatusTypeDef error;
  JPEG_DC_HuffCodeTableTypeDef dcSizeCodesTable;
  uint32_t i, lsb, msb;
  __IO uint32_t *address, *addressDef;

  if (DCTableAddress == (hjpeg->Instance->HUFFENC_DC0))
  {
    address = (hjpeg->Instance->HUFFENC_DC0 + (JPEG_DC_HUFF_TABLE_SIZE / 2UL));
  }
  else if (DCTableAddress == (hjpeg->Instance->HUFFENC_DC1))
  {
    address = (hjpeg->Instance->HUFFENC_DC1 + (JPEG_DC_HUFF_TABLE_SIZE / 2UL));
  }
  else
  {
    return HAL_ERROR;
  }

  if (HuffTableDC != NULL)
  {
    error = JPEG_DCHuff_BitsVals_To_SizeCodes(HuffTableDC, &dcSizeCodesTable);
    if (error != HAL_OK)
    {
      return  error;
    }
    addressDef = address;
    *addressDef = 0x0FFF0FFF;
    addressDef++;
    *addressDef = 0x0FFF0FFF;

    i = JPEG_DC_HUFF_TABLE_SIZE;
    while (i > 1UL)
    {
      i--;
      address --;
      msb = ((uint32_t)(((uint32_t)dcSizeCodesTable.CodeLength[i] & 0xFU) << 8)) | ((uint32_t)dcSizeCodesTable.HuffmanCode[i] &
                                                                                   0xFFUL);
      i--;
      lsb = ((uint32_t)(((uint32_t)dcSizeCodesTable.CodeLength[i] & 0xFU) << 8)) | ((uint32_t)dcSizeCodesTable.HuffmanCode[i] &
                                                                                   0xFFUL);

      *address = lsb | (msb << 16);
    }
  }

  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Set the JPEG register with an AC huffman table at the given AC table address
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  HuffTableAC pointer to AC huffman table
  * @param  ACTableAddress Encoder AC huffman table address it could be HUFFENC_AC0 or HUFFENC_AC1.
  * @retval HAL status
  */
static HAL_StatusTypeDef JPEG_Set_HuffAC_Mem(JPEG_HandleTypeDef *hjpeg, JPEG_ACHuffTableTypeDef *HuffTableAC,
                                             const __IO uint32_t *ACTableAddress)
{
  HAL_StatusTypeDef error;
  JPEG_AC_HuffCodeTableTypeDef acSizeCodesTable;
  uint32_t i, lsb, msb;
  __IO uint32_t *address, *addressDef;

  if (ACTableAddress == (hjpeg->Instance->HUFFENC_AC0))
  {
    address = (hjpeg->Instance->HUFFENC_AC0 + (JPEG_AC_HUFF_TABLE_SIZE / 2UL));
  }
  else if (ACTableAddress == (hjpeg->Instance->HUFFENC_AC1))
  {
    address = (hjpeg->Instance->HUFFENC_AC1 + (JPEG_AC_HUFF_TABLE_SIZE / 2UL));
  }
  else
  {
    return HAL_ERROR;
  }

  if (HuffTableAC != NULL)
  {
    error = JPEG_ACHuff_BitsVals_To_SizeCodes(HuffTableAC, &acSizeCodesTable);
    if (error != HAL_OK)
    {
      return  error;
    }
    /* Default values settings: 162:167 FFFh , 168:175 FD0h_FD7h */
    /* Locations 162:175 of each AC table contain information used internally by the core */

    addressDef = address;
    for (i = 0; i < 3UL; i++)
    {
      *addressDef = 0x0FFF0FFF;
      addressDef++;
    }
    *addressDef = 0x0FD10FD0;
    addressDef++;
    *addressDef = 0x0FD30FD2;
    addressDef++;
    *addressDef = 0x0FD50FD4;
    addressDef++;
    *addressDef = 0x0FD70FD6;
    /* end of Locations 162:175  */


    i = JPEG_AC_HUFF_TABLE_SIZE;
    while (i > 1UL)
    {
      i--;
      address--;
      msb = ((uint32_t)(((uint32_t)acSizeCodesTable.CodeLength[i] & 0xFU) << 8)) | ((uint32_t)acSizeCodesTable.HuffmanCode[i] &
                                                                                   0xFFUL);
      i--;
      lsb = ((uint32_t)(((uint32_t)acSizeCodesTable.CodeLength[i] & 0xFU) << 8)) | ((uint32_t)acSizeCodesTable.HuffmanCode[i] &
                                                                                   0xFFUL);

      *address = lsb | (msb << 16);
    }
  }

  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Configure the JPEG encoder register huffman tables to used during
  *         the encdoing operation
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
static HAL_StatusTypeDef JPEG_Set_HuffEnc_Mem(JPEG_HandleTypeDef *hjpeg)
{
  HAL_StatusTypeDef error;

  JPEG_Set_Huff_DHTMem(hjpeg);
  error = JPEG_Set_HuffAC_Mem(hjpeg, (JPEG_ACHuffTableTypeDef *)(uint32_t)&JPEG_ACLUM_HuffTable,
                              (hjpeg->Instance->HUFFENC_AC0));
  if (error != HAL_OK)
  {
    return  error;
  }

  error = JPEG_Set_HuffAC_Mem(hjpeg, (JPEG_ACHuffTableTypeDef *)(uint32_t)&JPEG_ACCHROM_HuffTable,
                              (hjpeg->Instance->HUFFENC_AC1));
  if (error != HAL_OK)
  {
    return  error;
  }

  error = JPEG_Set_HuffDC_Mem(hjpeg, (JPEG_DCHuffTableTypeDef *)(uint32_t)&JPEG_DCLUM_HuffTable,
                              hjpeg->Instance->HUFFENC_DC0);
  if (error != HAL_OK)
  {
    return  error;
  }

  error = JPEG_Set_HuffDC_Mem(hjpeg, (JPEG_DCHuffTableTypeDef *)(uint32_t)&JPEG_DCCHROM_HuffTable,
                              hjpeg->Instance->HUFFENC_DC1);
  if (error != HAL_OK)
  {
    return  error;
  }
  /* Return function status */
  return HAL_OK;
}

/**
  * @brief  Configure the JPEG register huffman tables to be included in the JPEG
  *         file header (used for encoding only)
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
static void JPEG_Set_Huff_DHTMem(JPEG_HandleTypeDef *hjpeg)
{
  JPEG_ACHuffTableTypeDef *HuffTableAC0 = (JPEG_ACHuffTableTypeDef *)(uint32_t)&JPEG_ACLUM_HuffTable;
  JPEG_ACHuffTableTypeDef *HuffTableAC1 = (JPEG_ACHuffTableTypeDef *)(uint32_t)&JPEG_ACCHROM_HuffTable;
  JPEG_DCHuffTableTypeDef *HuffTableDC0 = (JPEG_DCHuffTableTypeDef *)(uint32_t)&JPEG_DCLUM_HuffTable;
  JPEG_DCHuffTableTypeDef *HuffTableDC1 = (JPEG_DCHuffTableTypeDef *)(uint32_t)&JPEG_DCCHROM_HuffTable;
  uint32_t value, index;
  __IO uint32_t *address;

  /* DC0 Huffman Table : BITS*/
  /* DC0 BITS is a 16 Bytes table i.e 4x32bits words from DHTMEM base address to DHTMEM + 3*/
  address = (hjpeg->Instance->DHTMEM + 3);
  index = 16;
  while (index > 3UL)
  {

    *address = (((uint32_t)HuffTableDC0->Bits[index - 1UL] & 0xFFUL) << 24) |
               (((uint32_t)HuffTableDC0->Bits[index - 2UL] & 0xFFUL) << 16) |
               (((uint32_t)HuffTableDC0->Bits[index - 3UL] & 0xFFUL) << 8) |
               ((uint32_t)HuffTableDC0->Bits[index - 4UL] & 0xFFUL);
    address--;
    index -= 4UL;

  }
  /* DC0 Huffman Table : Val*/
  /* DC0 VALS is a 12 Bytes table i.e 3x32bits words from DHTMEM base address +4 to DHTMEM + 6 */
  address = (hjpeg->Instance->DHTMEM + 6);
  index = 12;
  while (index > 3UL)
  {
    *address = (((uint32_t)HuffTableDC0->HuffVal[index - 1UL] & 0xFFUL) << 24) |
               (((uint32_t)HuffTableDC0->HuffVal[index - 2UL] & 0xFFUL) << 16) |
               (((uint32_t)HuffTableDC0->HuffVal[index - 3UL] & 0xFFUL) << 8) |
               ((uint32_t)HuffTableDC0->HuffVal[index - 4UL] & 0xFFUL);
    address--;
    index -= 4UL;
  }

  /* AC0 Huffman Table : BITS*/
  /* AC0 BITS is a 16 Bytes table i.e 4x32bits words from DHTMEM base address + 7 to DHTMEM + 10*/
  address = (hjpeg->Instance->DHTMEM + 10UL);
  index = 16;
  while (index > 3UL)
  {

    *address = (((uint32_t)HuffTableAC0->Bits[index - 1UL] & 0xFFUL) << 24) |
               (((uint32_t)HuffTableAC0->Bits[index - 2UL] & 0xFFUL) << 16) |
               (((uint32_t)HuffTableAC0->Bits[index - 3UL] & 0xFFUL) << 8) |
               ((uint32_t)HuffTableAC0->Bits[index - 4UL] & 0xFFUL);
    address--;
    index -= 4UL;

  }
  /* AC0 Huffman Table : Val*/
  /* AC0 VALS is a 162 Bytes table i.e 41x32bits words from DHTMEM base address + 11 to DHTMEM + 51 */
  /* only Byte 0 and Byte 1 of the last word (@ DHTMEM + 51) belong to AC0 VALS table */
  address = (hjpeg->Instance->DHTMEM + 51);
  value = *address & 0xFFFF0000U;
  value = value | (((uint32_t)HuffTableAC0->HuffVal[161] & 0xFFUL) << 8) | ((uint32_t)HuffTableAC0->HuffVal[160] & 0xFFUL);
  *address = value;

  /*continue setting 160 AC0 huffman values */
  address--; /* address = hjpeg->Instance->DHTMEM + 50*/
  index = 160;
  while (index > 3UL)
  {
    *address = (((uint32_t)HuffTableAC0->HuffVal[index - 1UL] & 0xFFUL) << 24) |
               (((uint32_t)HuffTableAC0->HuffVal[index - 2UL] & 0xFFUL) << 16) |
               (((uint32_t)HuffTableAC0->HuffVal[index - 3UL] & 0xFFUL) << 8) |
               ((uint32_t)HuffTableAC0->HuffVal[index - 4UL] & 0xFFUL);
    address--;
    index -= 4UL;
  }

  /* DC1 Huffman Table : BITS*/
  /* DC1 BITS is a 16 Bytes table i.e 4x32bits words from DHTMEM + 51 base address to DHTMEM + 55*/
  /* only Byte 2 and Byte 3 of the first word (@ DHTMEM + 51) belong to DC1 Bits table */
  address = (hjpeg->Instance->DHTMEM + 51);
  value = *address & 0x0000FFFFU;
  value = value | (((uint32_t)HuffTableDC1->Bits[1] & 0xFFUL) << 24) | (((uint32_t)HuffTableDC1->Bits[0] & 0xFFUL) << 16);
  *address = value;

  /* only Byte 0 and Byte 1 of the last word (@ DHTMEM + 55) belong to DC1 Bits table */
  address = (hjpeg->Instance->DHTMEM + 55);
  value = *address & 0xFFFF0000U;
  value = value | (((uint32_t)HuffTableDC1->Bits[15] & 0xFFUL) << 8) | ((uint32_t)HuffTableDC1->Bits[14] & 0xFFUL);
  *address = value;

  /*continue setting 12 DC1 huffman Bits from DHTMEM + 54 down to DHTMEM + 52*/
  address--;
  index = 12;
  while (index > 3UL)
  {

    *address = (((uint32_t)HuffTableDC1->Bits[index + 1UL] & 0xFFUL) << 24) |
               (((uint32_t)HuffTableDC1->Bits[index] & 0xFFUL) << 16) |
               (((uint32_t)HuffTableDC1->Bits[index - 1UL] & 0xFFUL) << 8) |
               ((uint32_t)HuffTableDC1->Bits[index - 2UL] & 0xFFUL);
    address--;
    index -= 4UL;

  }
  /* DC1 Huffman Table : Val*/
  /* DC1 VALS is a 12 Bytes table i.e 3x32bits words from DHTMEM base address +55 to DHTMEM + 58 */
  /* only Byte 2 and Byte 3 of the first word (@ DHTMEM + 55) belong to DC1 Val table */
  address = (hjpeg->Instance->DHTMEM + 55);
  value = *address & 0x0000FFFFUL;
  value = value | (((uint32_t)HuffTableDC1->HuffVal[1] & 0xFFUL) << 24) | (((uint32_t)HuffTableDC1->HuffVal[0] & 0xFFUL) <<
                                                                         16);
  *address = value;

  /* only Byte 0 and Byte 1 of the last word (@ DHTMEM + 58) belong to DC1 Val table */
  address = (hjpeg->Instance->DHTMEM + 58);
  value = *address & 0xFFFF0000UL;
  value = value | (((uint32_t)HuffTableDC1->HuffVal[11] & 0xFFUL) << 8) | ((uint32_t)HuffTableDC1->HuffVal[10] & 0xFFUL);
  *address = value;

  /*continue setting 8 DC1 huffman val from DHTMEM + 57 down to DHTMEM + 56*/
  address--;
  index = 8;
  while (index > 3UL)
  {
    *address = (((uint32_t)HuffTableDC1->HuffVal[index + 1UL] & 0xFFUL) << 24) |
               (((uint32_t)HuffTableDC1->HuffVal[index] & 0xFFUL) << 16) |
               (((uint32_t)HuffTableDC1->HuffVal[index - 1UL] & 0xFFUL) << 8) |
               ((uint32_t)HuffTableDC1->HuffVal[index - 2UL] & 0xFFUL);
    address--;
    index -= 4UL;
  }

  /* AC1 Huffman Table : BITS*/
  /* AC1 BITS is a 16 Bytes table i.e 4x32bits words from DHTMEM base address + 58 to DHTMEM + 62*/
  /* only Byte 2 and Byte 3 of the first word (@ DHTMEM + 58) belong to AC1 Bits table */
  address = (hjpeg->Instance->DHTMEM + 58);
  value = *address & 0x0000FFFFU;
  value = value | (((uint32_t)HuffTableAC1->Bits[1] & 0xFFUL) << 24) | (((uint32_t)HuffTableAC1->Bits[0] & 0xFFUL) << 16);
  *address = value;

  /* only Byte 0 and Byte 1 of the last word (@ DHTMEM + 62) belong to Bits Val table */
  address = (hjpeg->Instance->DHTMEM + 62);
  value = *address & 0xFFFF0000U;
  value = value | (((uint32_t)HuffTableAC1->Bits[15] & 0xFFUL) << 8) | ((uint32_t)HuffTableAC1->Bits[14] & 0xFFUL);
  *address = value;

  /*continue setting 12 AC1 huffman Bits from DHTMEM + 61 down to DHTMEM + 59*/
  address--;
  index = 12;
  while (index > 3UL)
  {

    *address = (((uint32_t)HuffTableAC1->Bits[index + 1UL] & 0xFFUL) << 24) |
               (((uint32_t)HuffTableAC1->Bits[index] & 0xFFUL) << 16) |
               (((uint32_t)HuffTableAC1->Bits[index - 1UL] & 0xFFUL) << 8) |
               ((uint32_t)HuffTableAC1->Bits[index - 2UL] & 0xFFUL);
    address--;
    index -= 4UL;

  }
  /* AC1 Huffman Table : Val*/
  /* AC1 VALS is a 162 Bytes table i.e 41x32bits words from DHTMEM base address + 62 to DHTMEM + 102 */
  /* only Byte 2 and Byte 3 of the first word (@ DHTMEM + 62) belong to AC1 VALS table */
  address = (hjpeg->Instance->DHTMEM + 62);
  value = *address & 0x0000FFFFUL;
  value = value | (((uint32_t)HuffTableAC1->HuffVal[1] & 0xFFUL) << 24) | (((uint32_t)HuffTableAC1->HuffVal[0] & 0xFFUL) <<
                                                                         16);
  *address = value;

  /*continue setting 160 AC1 huffman values from DHTMEM + 63 to DHTMEM+102 */
  address = (hjpeg->Instance->DHTMEM + 102);
  index = 160;
  while (index > 3UL)
  {
    *address = (((uint32_t)HuffTableAC1->HuffVal[index + 1UL] & 0xFFUL) << 24) |
               (((uint32_t)HuffTableAC1->HuffVal[index] & 0xFFUL) << 16) |
               (((uint32_t)HuffTableAC1->HuffVal[index - 1UL] & 0xFFUL) << 8) |
               ((uint32_t)HuffTableAC1->HuffVal[index - 2UL] & 0xFFUL);
    address--;
    index -= 4UL;
  }

}

/**
  * @brief  Configure the JPEG registers with a given quantization table
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  QTable pointer to an array of 64 bytes giving the quantization table
  * @param  QTableAddress destination quantization address in the JPEG peripheral
  *         it could be QMEM0, QMEM1, QMEM2 or QMEM3
  * @retval 0 if no error, 1 if error
  */
static uint32_t JPEG_Set_Quantization_Mem(JPEG_HandleTypeDef *hjpeg, uint8_t *QTable,
                                                    __IO uint32_t *QTableAddress)
{
  uint32_t i, j, quantRow, quantVal, ScaleFactor;
  __IO uint32_t *tableAddress;

  tableAddress = QTableAddress;

  if ((hjpeg->Conf.ImageQuality >= 50UL) && (hjpeg->Conf.ImageQuality <= 100UL))
  {
    ScaleFactor = 200UL - (hjpeg->Conf.ImageQuality * 2UL);
  }
  else if (hjpeg->Conf.ImageQuality > 0UL)
  {
    ScaleFactor = ((uint32_t) 5000) / ((uint32_t) hjpeg->Conf.ImageQuality);
  }
  else
  {
    return 1UL;
  }

  /*Quantization_table = (Standard_quanization_table * ScaleFactor + 50) / 100*/
  i = 0;
  while (i < (JPEG_QUANT_TABLE_SIZE - 3UL))
  {
    quantRow = 0;
    for (j = 0; j < 4UL; j++)
    {
      /* Note that the quantization coefficients must be specified in the table in zigzag order */
      quantVal = ((((uint32_t) QTable[JPEG_ZIGZAG_ORDER[i + j]]) * ScaleFactor) + 50UL) / 100UL;

      if (quantVal == 0UL)
      {
        quantVal = 1UL;
      }
      else if (quantVal > 255UL)
      {
        quantVal = 255UL;
      }
      else
      {
        /* Nothing to do, keep same value of quantVal */
      }

      quantRow |= ((quantVal & 0xFFUL) << (8UL * j));
    }

    i += 4UL;
    *tableAddress = quantRow;
    tableAddress ++;
  }

  /* Return function status */
  return 0UL;
}

/**
  * @brief  Configure the JPEG registers for YCbCr color space
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
static void JPEG_SetColorYCBCR(JPEG_HandleTypeDef *hjpeg)
{
  uint32_t ySamplingH;
  uint32_t ySamplingV;
  uint32_t yblockNb;

  /*Set Number of color components to 3*/
  hjpeg->Instance->CONFR1 &=  ~JPEG_CONFR1_NF;
  hjpeg->Instance->CONFR1 |=  JPEG_CONFR1_NF_1;

  /* compute MCU block size and Y, Cb ,Cr sampling factors*/
  if (hjpeg->Conf.ChromaSubsampling == JPEG_420_SUBSAMPLING)
  {
    ySamplingH  = JPEG_CONFR4_HSF_1;   /* Hs = 2*/
    ySamplingV  = JPEG_CONFR4_VSF_1;   /* Vs = 2*/

    yblockNb  = 0x30; /* 4 blocks of 8x8*/
  }
  else if (hjpeg->Conf.ChromaSubsampling == JPEG_422_SUBSAMPLING)
  {
    ySamplingH  = JPEG_CONFR4_HSF_1;   /* Hs = 2*/
    ySamplingV  = JPEG_CONFR4_VSF_0;   /* Vs = 1*/

    yblockNb  = 0x10; /* 2 blocks of 8x8*/
  }
  else /*JPEG_444_SUBSAMPLING and default*/
  {
    ySamplingH  = JPEG_CONFR4_HSF_0;   /* Hs = 1*/
    ySamplingV  = JPEG_CONFR4_VSF_0;   /* Vs = 1*/

    yblockNb  = 0; /* 1 block of 8x8*/
  }

  hjpeg->Instance->CONFR1 &= ~(JPEG_CONFR1_NF | JPEG_CONFR1_NS);
  hjpeg->Instance->CONFR1 |= (JPEG_CONFR1_NF_1 | JPEG_CONFR1_NS_1);

  /*Reset CONFR4 register*/
  hjpeg->Instance->CONFR4 =  0;
  /*Set Horizental and Vertical  sampling factor , number of blocks , Quantization table and Huffman AC/DC tables for component 0*/
  hjpeg->Instance->CONFR4 |= (ySamplingH | ySamplingV | (yblockNb & JPEG_CONFR4_NB));

  /*Reset CONFR5 register*/
  hjpeg->Instance->CONFR5 =  0;
  /*Set Horizental and Vertical  sampling factor , number of blocks , Quantization table and Huffman AC/DC tables for component 1*/
  hjpeg->Instance->CONFR5 |= (JPEG_CONFR5_HSF_0 | JPEG_CONFR5_VSF_0 | JPEG_CONFR5_QT_0 | JPEG_CONFR5_HA | JPEG_CONFR5_HD);

  /*Reset CONFR6 register*/
  hjpeg->Instance->CONFR6 =  0;
  /*Set Horizental and Vertical  sampling factor and number of blocks for component 2*/
  /* In YCBCR , by default, both chrominance components (component 1 and component 2) use the same Quantization table (table 1) */
  /* In YCBCR , both chrominance components (component 1 and component 2) use the same Huffman tables (table 1) */
  hjpeg->Instance->CONFR6 |= (JPEG_CONFR6_HSF_0 | JPEG_CONFR6_VSF_0 | JPEG_CONFR6_QT_0 | JPEG_CONFR6_HA | JPEG_CONFR6_HD);

}

/**
  * @brief  Configure the JPEG registers for GrayScale color space
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
static void JPEG_SetColorGrayScale(JPEG_HandleTypeDef *hjpeg)
{
  /*Set Number of color components to 1*/
  hjpeg->Instance->CONFR1 &= ~(JPEG_CONFR1_NF | JPEG_CONFR1_NS);

  /*in GrayScale use 1 single Quantization table (Table 0)*/
  /*in GrayScale use only one couple of AC/DC huffman table (table 0)*/

  /*Reset CONFR4 register*/
  hjpeg->Instance->CONFR4 =  0;
  /*Set Horizental and Vertical  sampling factor , number of blocks , Quantization table and Huffman AC/DC tables for component 0*/
  hjpeg->Instance->CONFR4 |=  JPEG_CONFR4_HSF_0 | JPEG_CONFR4_VSF_0 ;
}

/**
  * @brief  Configure the JPEG registers for CMYK color space
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
static void JPEG_SetColorCMYK(JPEG_HandleTypeDef *hjpeg)
{
  uint32_t ySamplingH;
  uint32_t ySamplingV;
  uint32_t yblockNb;

  /*Set Number of color components to 4*/
  hjpeg->Instance->CONFR1 |= (JPEG_CONFR1_NF | JPEG_CONFR1_NS);

  /* compute MCU block size and Y, Cb ,Cr sampling factors*/
  if (hjpeg->Conf.ChromaSubsampling == JPEG_420_SUBSAMPLING)
  {
    ySamplingH  = JPEG_CONFR4_HSF_1;   /* Hs = 2*/
    ySamplingV  = JPEG_CONFR4_VSF_1;   /* Vs = 2*/

    yblockNb  = 0x30; /* 4 blocks of 8x8*/
  }
  else if (hjpeg->Conf.ChromaSubsampling == JPEG_422_SUBSAMPLING)
  {
    ySamplingH  = JPEG_CONFR4_HSF_1;   /* Hs = 2*/
    ySamplingV  = JPEG_CONFR4_VSF_0;   /* Vs = 1*/

    yblockNb  = 0x10; /* 2 blocks of 8x8*/
  }
  else /*JPEG_444_SUBSAMPLING and default*/
  {
    ySamplingH  = JPEG_CONFR4_HSF_0;   /* Hs = 1*/
    ySamplingV  = JPEG_CONFR4_VSF_0;   /* Vs = 1*/

    yblockNb  = 0; /* 1 block of 8x8*/
  }

  /*Reset CONFR4 register*/
  hjpeg->Instance->CONFR4 =  0;
  /*Set Horizental and Vertical  sampling factor , number of blocks , Quantization table and Huffman AC/DC tables for component 0*/
  hjpeg->Instance->CONFR4 |= (ySamplingH | ySamplingV | (yblockNb & JPEG_CONFR4_NB));

  /*Reset CONFR5 register*/
  hjpeg->Instance->CONFR5 =  0;
  /*Set Horizental and Vertical  sampling factor , number of blocks , Quantization table and Huffman AC/DC tables for component 1*/
  hjpeg->Instance->CONFR5 |= (JPEG_CONFR5_HSF_0 | JPEG_CONFR5_VSF_0);

  /*Reset CONFR6 register*/
  hjpeg->Instance->CONFR6 =  0;
  /*Set Horizental and Vertical  sampling factor , number of blocks , Quantization table and Huffman AC/DC tables for component 2*/
  hjpeg->Instance->CONFR6 |= (JPEG_CONFR6_HSF_0 | JPEG_CONFR6_VSF_0);

  /*Reset CONFR7 register*/
  hjpeg->Instance->CONFR7 =  0;
  /*Set Horizental and Vertical  sampling factor , number of blocks , Quantization table and Huffman AC/DC tables for component 3*/
  hjpeg->Instance->CONFR7 |= (JPEG_CONFR7_HSF_0 | JPEG_CONFR7_VSF_0);
}

/**
  * @brief  Init the JPEG encoding/decoding process in case of Polling or Interrupt and DMA
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None
  */
static void JPEG_Init_Process(JPEG_HandleTypeDef *hjpeg)
{
  /*Reset pause*/
  hjpeg->Context &= (~(JPEG_CONTEXT_PAUSE_INPUT | JPEG_CONTEXT_PAUSE_OUTPUT));

  if ((hjpeg->Context & JPEG_CONTEXT_OPERATION_MASK) == JPEG_CONTEXT_DECODE)
  {
    /*Set JPEG Codec to Decoding mode */
    hjpeg->Instance->CONFR1 |= JPEG_CONFR1_DE;
  }
  else /* JPEG_CONTEXT_ENCODE */
  {
    /*Set JPEG Codec to Encoding mode */
    hjpeg->Instance->CONFR1 &= ~JPEG_CONFR1_DE;
  }

  /*Stop JPEG processing */
  hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;

  /* Disable All Interrupts */
  __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_INTERRUPT_MASK);

  /* Flush input and output FIFOs*/
  hjpeg->Instance->CR |= JPEG_CR_IFF;
  hjpeg->Instance->CR |= JPEG_CR_OFF;

  /* Clear all flags */
  __HAL_JPEG_CLEAR_FLAG(hjpeg, JPEG_FLAG_ALL);

  /*Start Encoding/Decoding*/
  hjpeg->Instance->CONFR0 |=  JPEG_CONFR0_START;

  if ((hjpeg->Context & JPEG_CONTEXT_METHOD_MASK) == JPEG_CONTEXT_IT)
  {
    /*Enable IN/OUT, end of Conversation, and end of header parsing interruptions*/
    __HAL_JPEG_ENABLE_IT(hjpeg, JPEG_IT_IFT | JPEG_IT_IFNF | JPEG_IT_OFT | JPEG_IT_OFNE | JPEG_IT_EOC | JPEG_IT_HPD);
  }
  else if ((hjpeg->Context & JPEG_CONTEXT_METHOD_MASK) == JPEG_CONTEXT_DMA)
  {
    /*Enable End Of Conversation, and End Of Header parsing interruptions*/
    __HAL_JPEG_ENABLE_IT(hjpeg, JPEG_IT_EOC | JPEG_IT_HPD);

  }
  else
  {
    /* Nothing to do */
  }
}

/**
  * @brief  JPEG encoding/decoding process in case of Polling or Interrupt
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval JPEG_PROCESS_DONE if the process has ends else JPEG_PROCESS_ONGOING
  */
static uint32_t JPEG_Process(JPEG_HandleTypeDef *hjpeg)
{
  uint32_t tmpContext;

  /*End of header processing flag rised*/
  if ((hjpeg->Context & JPEG_CONTEXT_OPERATION_MASK) == JPEG_CONTEXT_DECODE)
  {
    if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_HPDF) != 0UL)
    {
      /*Call Header parsing complet callback */
      (void) HAL_JPEG_GetInfo(hjpeg, &hjpeg->Conf);
      /* Reset the ImageQuality */
      hjpeg->Conf.ImageQuality = 0;
      /* Note : the image quality is only available at the end of the decoding operation */
      /* at the current stage the calculated image quality is not correct so reset it */

      /*Call Info Ready callback */
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->InfoReadyCallback(hjpeg, &hjpeg->Conf);
#else
      HAL_JPEG_InfoReadyCallback(hjpeg, &hjpeg->Conf);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

      __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_IT_HPD);

      /* Clear header processing done flag */
      __HAL_JPEG_CLEAR_FLAG(hjpeg, JPEG_FLAG_HPDF);
    }
  }

  /*Input FIFO status handling*/
  if ((hjpeg->Context &  JPEG_CONTEXT_PAUSE_INPUT) == 0UL)
  {
    if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_IFTF) != 0UL)
    {
      /*Input FIFO threshold flag rised*/
      /*JPEG_FIFO_TH_SIZE words can be written in */
      JPEG_ReadInputData(hjpeg, JPEG_FIFO_TH_SIZE);
    }
    else if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_IFNFF) != 0UL)
    {
      /*Input FIFO Not Full flag rised*/
      /*32-bit value can be written in */
      JPEG_ReadInputData(hjpeg, 1);
    }
    else
    {
      /* Nothing to do */
    }
  }


  /*Output FIFO flag handling*/
  if ((hjpeg->Context &  JPEG_CONTEXT_PAUSE_OUTPUT) == 0UL)
  {
    if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_OFTF) != 0UL)
    {
      /*Output FIFO threshold flag rised*/
      /*JPEG_FIFO_TH_SIZE words can be read out */
      JPEG_StoreOutputData(hjpeg, JPEG_FIFO_TH_SIZE);
    }
    else if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_OFNEF) != 0UL)
    {
      /*Output FIFO Not Empty flag rised*/
      /*32-bit value can be read out */
      JPEG_StoreOutputData(hjpeg, 1);
    }
    else
    {
      /* Nothing to do */
    }
  }

  /*End of Conversion handling :i.e EOC flag is high and OFTF low and OFNEF low*/
  if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_EOCF | JPEG_FLAG_OFTF | JPEG_FLAG_OFNEF) == JPEG_FLAG_EOCF)
  {
    /*Stop Encoding/Decoding*/
    hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;

    if ((hjpeg->Context & JPEG_CONTEXT_METHOD_MASK) == JPEG_CONTEXT_IT)
    {
      /* Disable All Interrupts */
      __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_INTERRUPT_MASK);
    }

    /* Clear all flags */
    __HAL_JPEG_CLEAR_FLAG(hjpeg, JPEG_FLAG_ALL);

    /*Call End of conversion callback */
    if (hjpeg->JpegOutCount > 0UL)
    {
      /*Output Buffer is not empty, call DecodedDataReadyCallback*/
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#else
      HAL_JPEG_DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

      hjpeg->JpegOutCount = 0;
    }

    /*Reset Context Operation*/
    tmpContext = hjpeg->Context;
    /*Clear all context fields execpt JPEG_CONTEXT_CONF_ENCODING and JPEG_CONTEXT_CUSTOM_TABLES*/
    hjpeg->Context &= (JPEG_CONTEXT_CONF_ENCODING | JPEG_CONTEXT_CUSTOM_TABLES);

    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    /* Change the JPEG state */
    hjpeg->State = HAL_JPEG_STATE_READY;

    /*Call End of Encoding/Decoding callback */
    if ((tmpContext & JPEG_CONTEXT_OPERATION_MASK) == JPEG_CONTEXT_DECODE)
    {
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->DecodeCpltCallback(hjpeg);
#else
      HAL_JPEG_DecodeCpltCallback(hjpeg);
#endif /*USE_HAL_JPEG_REGISTER_CALLBACKS*/
    }
    else /* JPEG_CONTEXT_ENCODE */
    {
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->EncodeCpltCallback(hjpeg);
#else
      HAL_JPEG_EncodeCpltCallback(hjpeg);
#endif
    }

    return JPEG_PROCESS_DONE;
  }


  return JPEG_PROCESS_ONGOING;
}

/**
  * @brief  Store some output data from the JPEG peripheral to the output buffer.
  *         This function is used when the JPEG peripheral has new data to output
  *         in case of Polling or Interrupt process
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  nbOutputWords Number of output words (of 32 bits) ready from the JPEG peripheral
  * @retval None
  */
static void JPEG_StoreOutputData(JPEG_HandleTypeDef *hjpeg, uint32_t nbOutputWords)
{
  uint32_t index, nBwords, nbBytes, dataword;

  if (hjpeg->OutDataLength >= (hjpeg->JpegOutCount + (nbOutputWords * 4UL)))
  {
    for (index = 0; index < nbOutputWords; index++)
    {
      /*Transfer 32 bits from the JPEG output FIFO*/
      dataword = hjpeg->Instance->DOR;
      hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount] = (uint8_t)(dataword & 0x000000FFUL);
      hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount + 1UL] = (uint8_t)((dataword & 0x0000FF00UL) >> 8);
      hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount + 2UL] = (uint8_t)((dataword & 0x00FF0000UL) >> 16);
      hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount + 3UL] = (uint8_t)((dataword & 0xFF000000UL) >> 24);
      hjpeg->JpegOutCount += 4UL;
    }
    if (hjpeg->OutDataLength == hjpeg->JpegOutCount)
    {
      /*Output Buffer is full, call DecodedDataReadyCallback*/
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#else
      HAL_JPEG_DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#endif /*USE_HAL_JPEG_REGISTER_CALLBACKS*/
      hjpeg->JpegOutCount = 0;
    }
  }
  else if (hjpeg->OutDataLength > hjpeg->JpegOutCount)
  {
    nBwords = (hjpeg->OutDataLength - hjpeg->JpegOutCount) / 4UL;
    for (index = 0; index < nBwords; index++)
    {
      /*Transfer 32 bits from the JPEG output FIFO*/
      dataword = hjpeg->Instance->DOR;
      hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount] = (uint8_t)(dataword & 0x000000FFUL);
      hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount + 1UL] = (uint8_t)((dataword & 0x0000FF00UL) >> 8);
      hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount + 2UL] = (uint8_t)((dataword & 0x00FF0000UL) >> 16);
      hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount + 3UL] = (uint8_t)((dataword & 0xFF000000UL) >> 24);
      hjpeg->JpegOutCount += 4UL;
    }
    if (hjpeg->OutDataLength == hjpeg->JpegOutCount)
    {
      /*Output Buffer is full, call DecodedDataReadyCallback*/
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#else
      HAL_JPEG_DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */
      hjpeg->JpegOutCount = 0;
    }
    else
    {
      nbBytes = hjpeg->OutDataLength - hjpeg->JpegOutCount;
      dataword = hjpeg->Instance->DOR;
      for (index = 0; index < nbBytes; index++)
      {
        hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount] = (uint8_t)((dataword >> (8UL * (index & 0x3UL))) & 0xFFUL);
        hjpeg->JpegOutCount++;
      }
      /*Output Buffer is full, call DecodedDataReadyCallback*/
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#else
      HAL_JPEG_DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

      hjpeg->JpegOutCount = 0;

      nbBytes = 4UL - nbBytes;
      for (index = nbBytes; index < 4UL; index++)
      {
        hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount] = (uint8_t)((dataword >> (8UL * index)) & 0xFFUL);
        hjpeg->JpegOutCount++;
      }
    }
  }
  else
  {
    /* Nothing to do */
  }
}

/**
  * @brief  Read some input Data from the input buffer.
  *         This function is used when the JPEG peripheral needs new data
  *         in case of Polling or Interrupt process
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @param  nbRequestWords Number of input words (of 32 bits) that the JPE peripheral request
  * @retval None
  */
static void JPEG_ReadInputData(JPEG_HandleTypeDef *hjpeg, uint32_t nbRequestWords)
{
  uint32_t nbBytes = 0, nBwords, index, Dataword, inputCount;

  if ((hjpeg->InDataLength == 0UL) || (nbRequestWords == 0UL))
  {
    /* No more Input data : nothing to do*/
    (void) HAL_JPEG_Pause(hjpeg, JPEG_PAUSE_RESUME_INPUT);
  }
  else if (hjpeg->InDataLength > hjpeg->JpegInCount)
  {
    nbBytes = hjpeg->InDataLength - hjpeg->JpegInCount;
  }
  else if (hjpeg->InDataLength == hjpeg->JpegInCount)
  {
    /*Call HAL_JPEG_GetDataCallback to get new data */
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
    hjpeg->GetDataCallback(hjpeg, hjpeg->JpegInCount);
#else
    HAL_JPEG_GetDataCallback(hjpeg, hjpeg->JpegInCount);
#endif /*USE_HAL_JPEG_REGISTER_CALLBACKS*/

    if (hjpeg->InDataLength > 4UL)
    {
      hjpeg->InDataLength = hjpeg->InDataLength - (hjpeg->InDataLength % 4UL);
    }
    hjpeg->JpegInCount = 0;
    nbBytes = hjpeg->InDataLength;
  }
  else
  {
    /* Nothing to do */
  }
  if (((hjpeg->Context &  JPEG_CONTEXT_PAUSE_INPUT) == 0UL) && (nbBytes > 0UL))
  {
    nBwords = nbBytes / 4UL;
    if (nBwords >= nbRequestWords)
    {
      for (index = 0; index < nbRequestWords; index++)
      {
        inputCount = hjpeg->JpegInCount;
        hjpeg->Instance->DIR = (((uint32_t)(hjpeg->pJpegInBuffPtr[inputCount])) | \
                                (((uint32_t)(hjpeg->pJpegInBuffPtr[inputCount + 1UL])) << 8) | \
                                (((uint32_t)(hjpeg->pJpegInBuffPtr[inputCount + 2UL])) << 16) | \
                                (((uint32_t)(hjpeg->pJpegInBuffPtr[inputCount + 3UL])) << 24));

        hjpeg->JpegInCount += 4UL;
      }
    }
    else /*nBwords < nbRequestWords*/
    {
      if (nBwords > 0UL)
      {
        for (index = 0; index < nBwords; index++)
        {
          inputCount = hjpeg->JpegInCount;
          hjpeg->Instance->DIR = (((uint32_t)(hjpeg->pJpegInBuffPtr[inputCount])) | \
                                  (((uint32_t)(hjpeg->pJpegInBuffPtr[inputCount + 1UL])) << 8) | \
                                  (((uint32_t)(hjpeg->pJpegInBuffPtr[inputCount + 2UL])) << 16) | \
                                  (((uint32_t)(hjpeg->pJpegInBuffPtr[inputCount + 3UL])) << 24));

          hjpeg->JpegInCount += 4UL;
        }
      }
      else
      {
        /* end of file*/
        Dataword = 0;
        for (index = 0; index < nbBytes; index++)
        {
          Dataword |= (uint32_t)hjpeg->pJpegInBuffPtr[hjpeg->JpegInCount] << (8UL * (index & 0x03UL));
          hjpeg->JpegInCount++;
        }
        hjpeg->Instance->DIR = Dataword;
      }
    }
  }
}

/**
  * @brief  Start the JPEG DMA process (encoding/decoding)
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval JPEG_PROCESS_DONE if process ends else JPEG_PROCESS_ONGOING
  */
static HAL_StatusTypeDef JPEG_DMA_StartProcess(JPEG_HandleTypeDef *hjpeg)
{
  uint32_t inXfrSize, outXfrSize;

  /*if the MDMA In is triggred with JPEG In FIFO Threshold flag
      then MDMA In buffer size is 32 bytes
    else (MDMA In is triggred with JPEG In FIFO not full flag)
      then MDMA In buffer size is 4 bytes
    */
  inXfrSize = hjpeg->hdmain->Init.BufferTransferLength;

  /*if the MDMA Out is triggred with JPEG Out FIFO Threshold flag
      then MDMA out buffer size is 32 bytes
    else (MDMA Out is triggred with JPEG Out FIFO not empty flag)
      then MDMA buffer size is 4 bytes
    */
  outXfrSize = hjpeg->hdmaout->Init.BufferTransferLength;

  if ((hjpeg->InDataLength < inXfrSize) || (hjpeg->OutDataLength < outXfrSize))
  {
    return HAL_ERROR;
  }
  /* Set the JPEG MDMA In transfer complete callback */
  hjpeg->hdmain->XferCpltCallback = JPEG_MDMAInCpltCallback;
  /* Set the MDMA In error callback */
  hjpeg->hdmain->XferErrorCallback = JPEG_MDMAErrorCallback;

  /* Set the JPEG MDMA Out transfer complete callback */
  hjpeg->hdmaout->XferCpltCallback = JPEG_MDMAOutCpltCallback;
  /* Set the MDMA In error callback */
  hjpeg->hdmaout->XferErrorCallback = JPEG_MDMAErrorCallback;
  /* Set the MDMA Out Abort callback */
  hjpeg->hdmaout->XferAbortCallback = JPEG_MDMAOutAbortCallback;

  if ((inXfrSize == 0UL) || (outXfrSize == 0UL))
  {
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
    return HAL_ERROR;
  }
  /*MDMA transfer size (BNDTR) must be a multiple of MDMA buffer size (TLEN)*/
  hjpeg->InDataLength = hjpeg->InDataLength - (hjpeg->InDataLength % inXfrSize);

  /*MDMA transfer size (BNDTR) must be a multiple of MDMA buffer size (TLEN)*/
  hjpeg->OutDataLength = hjpeg->OutDataLength - (hjpeg->OutDataLength % outXfrSize);


  /* Start MDMA FIFO Out transfer */
  if (HAL_MDMA_Start_IT(hjpeg->hdmaout, (uint32_t)&hjpeg->Instance->DOR, (uint32_t)hjpeg->pJpegOutBuffPtr,
                        hjpeg->OutDataLength, 1) != HAL_OK)
  {
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
    return HAL_ERROR;
  }
  /* Start DMA FIFO In transfer */
  if (HAL_MDMA_Start_IT(hjpeg->hdmain, (uint32_t)hjpeg->pJpegInBuffPtr, (uint32_t)&hjpeg->Instance->DIR,
                        hjpeg->InDataLength, 1) != HAL_OK)
  {
    hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
    return HAL_ERROR;
  }

  return HAL_OK;
}

/**
  * @brief  Continue the current JPEG DMA process (encoding/decoding)
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval JPEG_PROCESS_DONE if process ends else JPEG_PROCESS_ONGOING
  */
static void JPEG_DMA_ContinueProcess(JPEG_HandleTypeDef *hjpeg)
{
  /*End of header processing flag rises*/
  if ((hjpeg->Context & JPEG_CONTEXT_OPERATION_MASK) == JPEG_CONTEXT_DECODE)
  {
    if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_HPDF) != 0UL)
    {
      /*Call Header parsing complete callback */
      (void) HAL_JPEG_GetInfo(hjpeg, &hjpeg->Conf);

      /* Reset the ImageQuality */
      hjpeg->Conf.ImageQuality = 0;
      /* Note : the image quality is only available at the end of the decoding operation */
      /* at the current stage the calculated image quality is not correct so reset it */

      /*Call Info Ready callback */
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->InfoReadyCallback(hjpeg, &hjpeg->Conf);
#else
      HAL_JPEG_InfoReadyCallback(hjpeg, &hjpeg->Conf);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

      __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_IT_HPD);

      /* Clear header processing done flag */
      __HAL_JPEG_CLEAR_FLAG(hjpeg, JPEG_FLAG_HPDF);
    }
  }

  /*End of Conversion handling*/
  if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_EOCF) != 0UL)
  {

    hjpeg->Context |= JPEG_CONTEXT_ENDING_DMA;

    /*Stop Encoding/Decoding*/
    hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;

    __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_INTERRUPT_MASK);

    /* Clear all flags */
    __HAL_JPEG_CLEAR_FLAG(hjpeg, JPEG_FLAG_ALL);

    if (hjpeg->hdmain->State == HAL_MDMA_STATE_BUSY)
    {
      /* Stop the MDMA In Xfer*/
      (void) HAL_MDMA_Abort_IT(hjpeg->hdmain);
    }

    if (hjpeg->hdmaout->State == HAL_MDMA_STATE_BUSY)
    {
      /* Stop the MDMA out Xfer*/
      (void) HAL_MDMA_Abort_IT(hjpeg->hdmaout);
    }
    else
    {
      JPEG_DMA_EndProcess(hjpeg);
    }
  }


}

/**
  * @brief  Finalize the current JPEG DMA process (encoding/decoding)
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval JPEG_PROCESS_DONE
  */
static void JPEG_DMA_EndProcess(JPEG_HandleTypeDef *hjpeg)
{
  uint32_t tmpContext;
  hjpeg->JpegOutCount = hjpeg->OutDataLength - (hjpeg->hdmaout->Instance->CBNDTR & MDMA_CBNDTR_BNDT);

  /*if Output Buffer is full, call HAL_JPEG_DataReadyCallback*/
  if (hjpeg->JpegOutCount == hjpeg->OutDataLength)
  {
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
    hjpeg->DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#else
    HAL_JPEG_DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

    hjpeg->JpegOutCount = 0;
  }

  /*Check if remaining data in the output FIFO*/
  if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_OFNEF) == 0UL)
  {
    if (hjpeg->JpegOutCount > 0UL)
    {
      /*Output Buffer is not empty, call DecodedDataReadyCallback*/
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#else
      HAL_JPEG_DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

      hjpeg->JpegOutCount = 0;
    }

    /*Stop Encoding/Decoding*/
    hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;

    tmpContext = hjpeg->Context;
    /*Clear all context fileds execpt JPEG_CONTEXT_CONF_ENCODING and JPEG_CONTEXT_CUSTOM_TABLES*/
    hjpeg->Context &= (JPEG_CONTEXT_CONF_ENCODING | JPEG_CONTEXT_CUSTOM_TABLES);

    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    /* Change the JPEG state */
    hjpeg->State = HAL_JPEG_STATE_READY;

    /*Call End of Encoding/Decoding callback */
    if ((tmpContext & JPEG_CONTEXT_OPERATION_MASK) == JPEG_CONTEXT_DECODE)
    {
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->DecodeCpltCallback(hjpeg);
#else
      HAL_JPEG_DecodeCpltCallback(hjpeg);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */
    }
    else /* JPEG_CONTEXT_ENCODE */
    {
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->EncodeCpltCallback(hjpeg);
#else
      HAL_JPEG_EncodeCpltCallback(hjpeg);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */
    }
  }
  else if ((hjpeg->Context &  JPEG_CONTEXT_PAUSE_OUTPUT) == 0UL)
  {
    JPEG_DMA_PollResidualData(hjpeg);
  }
  else
  {
    /* Nothing to do */
  }

}

/**
  * @brief  Poll residual output data when DMA process (encoding/decoding)
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval None.
  */
static void JPEG_DMA_PollResidualData(JPEG_HandleTypeDef *hjpeg)
{
  uint32_t tmpContext, count, dataOut;

  for (count = JPEG_FIFO_SIZE; count > 0UL; count--)
  {
    if ((hjpeg->Context &  JPEG_CONTEXT_PAUSE_OUTPUT) == 0UL)
    {
      if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_OFNEF) != 0UL)
      {
        dataOut = hjpeg->Instance->DOR;
        hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount] = (uint8_t)(dataOut & 0x000000FFUL);
        hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount + 1UL] = (uint8_t)((dataOut & 0x0000FF00UL) >> 8);
        hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount + 2UL] = (uint8_t)((dataOut & 0x00FF0000UL) >> 16);
        hjpeg->pJpegOutBuffPtr[hjpeg->JpegOutCount + 3UL] = (uint8_t)((dataOut & 0xFF000000UL) >> 24);
        hjpeg->JpegOutCount += 4UL;

        if (hjpeg->JpegOutCount == hjpeg->OutDataLength)
        {
          /*Output Buffer is full, call HAL_JPEG_DataReadyCallback*/
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
          hjpeg->DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#else
          HAL_JPEG_DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

          hjpeg->JpegOutCount = 0;
        }

      }
    }
  }

  tmpContext = hjpeg->Context;

  if ((__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_OFNEF) == 0UL) || ((tmpContext & JPEG_CONTEXT_PAUSE_OUTPUT) == 0UL))
  {
    /*Stop Encoding/Decoding*/
    hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;

    if (hjpeg->JpegOutCount > 0UL)
    {
      /*Output Buffer is not empty, call DecodedDataReadyCallback*/
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#else
      HAL_JPEG_DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

      hjpeg->JpegOutCount = 0;
    }

    tmpContext = hjpeg->Context;
    /*Clear all context fileds execpt JPEG_CONTEXT_CONF_ENCODING and JPEG_CONTEXT_CUSTOM_TABLES*/
    hjpeg->Context &= (JPEG_CONTEXT_CONF_ENCODING | JPEG_CONTEXT_CUSTOM_TABLES);

    /* Process Unlocked */
    __HAL_UNLOCK(hjpeg);

    /* Change the JPEG state */
    hjpeg->State = HAL_JPEG_STATE_READY;

    /*Call End of Encoding/Decoding callback */
    if ((tmpContext & JPEG_CONTEXT_OPERATION_MASK) == JPEG_CONTEXT_DECODE)
    {
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->DecodeCpltCallback(hjpeg);
#else
      HAL_JPEG_DecodeCpltCallback(hjpeg);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */
    }
    else /* JPEG_CONTEXT_ENCODE */
    {
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->EncodeCpltCallback(hjpeg);
#else
      HAL_JPEG_EncodeCpltCallback(hjpeg);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */
    }
  }
}

/**
  * @brief  MDMA input transfer complete callback
  * @param  hmdma pointer to a MDMA_HandleTypeDef structure.
  * @retval None
  */
static void JPEG_MDMAInCpltCallback(MDMA_HandleTypeDef *hmdma)
{
  uint32_t inXfrSize;

  JPEG_HandleTypeDef *hjpeg = (JPEG_HandleTypeDef *)((MDMA_HandleTypeDef *)hmdma)->Parent;

  /* Disable The JPEG IT so the MDMA Input Callback can not be interrupted by the JPEG EOC IT or JPEG HPD IT */
  __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_INTERRUPT_MASK);

  /* Check if context method is DMA and we are not in ending DMA stage */
  if ((hjpeg->Context & (JPEG_CONTEXT_METHOD_MASK | JPEG_CONTEXT_ENDING_DMA)) == JPEG_CONTEXT_DMA)
  {

    /*if the MDMA In is triggred with JPEG In FIFO Threshold flag
      then MDMA In buffer size is 32 bytes
      else (MDMA In is triggred with JPEG In FIFO not full flag)
      then MDMA In buffer size is 4 bytes
      */
    inXfrSize = hjpeg->hdmain->Init.BufferTransferLength;

    hjpeg->JpegInCount = hjpeg->InDataLength - (hmdma->Instance->CBNDTR & MDMA_CBNDTR_BNDT);

    /*Call HAL_JPEG_GetDataCallback to get new data */
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
    hjpeg->GetDataCallback(hjpeg, hjpeg->JpegInCount);
#else
    HAL_JPEG_GetDataCallback(hjpeg, hjpeg->JpegInCount);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */


    if (hjpeg->InDataLength >= inXfrSize)
    {
      if (inXfrSize == 0UL)
      {
        hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
        hjpeg->State = HAL_JPEG_STATE_ERROR;
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
        hjpeg->ErrorCallback(hjpeg);
#else
        HAL_JPEG_ErrorCallback(hjpeg);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */
        return;
      }
      /*JPEG Input MDMA transfer data number must be multiple of MDMA buffer size
        as the destination is a 32 bits register */
      hjpeg->InDataLength = hjpeg->InDataLength - (hjpeg->InDataLength % inXfrSize);

    }
    else if (hjpeg->InDataLength > 0UL)
    {
      /* Transfer the remaining Data, must be multiple of source data size (byte) and destination data size (word) */
      if ((hjpeg->InDataLength % 4UL) != 0UL)
      {
        hjpeg->InDataLength = ((hjpeg->InDataLength / 4UL) + 1UL) * 4UL;
      }
    }
    else
    {
      /* Nothing to do */
    }

    if (((hjpeg->Context &  JPEG_CONTEXT_PAUSE_INPUT) == 0UL) && (hjpeg->InDataLength > 0UL))
    {
      /* Start MDMA FIFO In transfer */
      if (HAL_MDMA_Start_IT(hjpeg->hdmain, (uint32_t)hjpeg->pJpegInBuffPtr, (uint32_t)&hjpeg->Instance->DIR,
                            hjpeg->InDataLength, 1) != HAL_OK)
      {
        hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
        hjpeg->State = HAL_JPEG_STATE_ERROR;
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
        hjpeg->ErrorCallback(hjpeg);
#else
        HAL_JPEG_ErrorCallback(hjpeg);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */
        return;
      }
    }

    /* JPEG Conversion still on going : Enable the JPEG IT */
    __HAL_JPEG_ENABLE_IT(hjpeg, JPEG_IT_EOC | JPEG_IT_HPD);
  }
}

/**
  * @brief  MDMA output transfer complete callback
  * @param  hmdma pointer to a MDMA_HandleTypeDef structure.
  * @retval None
  */
static void JPEG_MDMAOutCpltCallback(MDMA_HandleTypeDef *hmdma)
{
  JPEG_HandleTypeDef *hjpeg = (JPEG_HandleTypeDef *)((MDMA_HandleTypeDef *)hmdma)->Parent;


  /* Disable The JPEG IT so the MDMA Output Callback can not be interrupted by the JPEG EOC IT or JPEG HPD IT */
  __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_INTERRUPT_MASK);

  if ((hjpeg->Context & (JPEG_CONTEXT_METHOD_MASK | JPEG_CONTEXT_ENDING_DMA)) ==
      JPEG_CONTEXT_DMA) /* Check if context method is DMA and we are not in ending DMA stage */
  {
    if (__HAL_JPEG_GET_FLAG(hjpeg, JPEG_FLAG_EOCF) == 0UL)
    {
      hjpeg->JpegOutCount = hjpeg->OutDataLength - (hmdma->Instance->CBNDTR & MDMA_CBNDTR_BNDT);

      /*Output Buffer is full, call HAL_JPEG_DataReadyCallback*/
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
      hjpeg->DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#else
      HAL_JPEG_DataReadyCallback(hjpeg, hjpeg->pJpegOutBuffPtr, hjpeg->JpegOutCount);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */

      if ((hjpeg->Context &  JPEG_CONTEXT_PAUSE_OUTPUT) == 0UL)
      {
        /* Start MDMA FIFO Out transfer */
        if (HAL_MDMA_Start_IT(hjpeg->hdmaout, (uint32_t)&hjpeg->Instance->DOR, (uint32_t)hjpeg->pJpegOutBuffPtr,
                              hjpeg->OutDataLength, 1) != HAL_OK)
        {
          hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;
          hjpeg->State = HAL_JPEG_STATE_ERROR;
#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
          hjpeg->ErrorCallback(hjpeg);
#else
          HAL_JPEG_ErrorCallback(hjpeg);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */
          return;
        }
      }
    }

    /* JPEG Conversion still on going : Enable the JPEG IT */
    __HAL_JPEG_ENABLE_IT(hjpeg, JPEG_IT_EOC | JPEG_IT_HPD);
  }

}

/**
  * @brief  MDMA Transfer error callback
  * @param  hmdma pointer to a MDMA_HandleTypeDef structure.
  * @retval None
  */
static void JPEG_MDMAErrorCallback(MDMA_HandleTypeDef *hmdma)
{
  JPEG_HandleTypeDef *hjpeg = (JPEG_HandleTypeDef *)((MDMA_HandleTypeDef *)hmdma)->Parent;

  /*Stop Encoding/Decoding*/
  hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;

  /* Disable All Interrupts */
  __HAL_JPEG_DISABLE_IT(hjpeg, JPEG_INTERRUPT_MASK);

  hjpeg->State = HAL_JPEG_STATE_READY;
  hjpeg->ErrorCode |= HAL_JPEG_ERROR_DMA;

#if (USE_HAL_JPEG_REGISTER_CALLBACKS == 1)
  hjpeg->ErrorCallback(hjpeg);
#else
  HAL_JPEG_ErrorCallback(hjpeg);
#endif /* USE_HAL_JPEG_REGISTER_CALLBACKS */
}

/**
  * @brief  MDMA output Abort callback
  * @param  hmdma pointer to a MDMA_HandleTypeDef structure.
  * @retval None
  */
static void JPEG_MDMAOutAbortCallback(MDMA_HandleTypeDef *hmdma)
{
  JPEG_HandleTypeDef *hjpeg = (JPEG_HandleTypeDef *)((MDMA_HandleTypeDef *)hmdma)->Parent;

  if ((hjpeg->Context & JPEG_CONTEXT_ENDING_DMA) != 0UL)
  {
    JPEG_DMA_EndProcess(hjpeg);
  }
}


/**
  * @brief  Calculate the decoded image quality (from 1 to 100)
  * @param  hjpeg pointer to a JPEG_HandleTypeDef structure that contains
  *         the configuration information for JPEG module
  * @retval JPEG image quality from 1 to 100.
  */
static uint32_t JPEG_GetQuality(JPEG_HandleTypeDef *hjpeg)
{
  uint32_t quality = 0;
  uint32_t quantRow, quantVal, scale, i, j;
  __IO uint32_t *tableAddress = hjpeg->Instance->QMEM0;

  i = 0;
  while (i < (JPEG_QUANT_TABLE_SIZE - 3UL))
  {
    quantRow = *tableAddress;
    for (j = 0; j < 4UL; j++)
    {
      quantVal = (quantRow >> (8UL * j)) & 0xFFUL;
      if (quantVal == 1UL)
      {
        /* if Quantization value = 1 then quality is 100%*/
        quality += 100UL;
      }
      else
      {
        /* Note that the quantization coefficients must be specified in the table in zigzag order */
        scale = (quantVal * 100UL) / ((uint32_t) hjpeg->QuantTable0[JPEG_ZIGZAG_ORDER[i + j]]);

        if (scale <= 100UL)
        {
          quality += (200UL - scale) / 2UL;
        }
        else
        {
          quality += 5000UL / scale;
        }
      }
    }

    i += 4UL;
    tableAddress ++;
  }

  return (quality / 64UL);
}
/**
  * @}
  */

#endif /* JPEG */
#endif /* HAL_JPEG_MODULE_ENABLED */
/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
