/*
 * Copyright 2023 MindMotion Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "board_init.h"
#include "ff.h"
#include "tjpgd.h"


/*
 * Macros.
 */


/*
 * Variables.
 */

     FATFS app_fs;
      DIR  app_fs_dir;
      FIL  app_fs_file;
   FILINFO app_fs_fileinfo;
      char app_fs_filepath[16]; /* max len of full file path. */
const char app_fs_dirpath[] = "1:/";

/*
 * Declerations.
 */
bool app_fs_display_jpg_file(char * filepath);

/*
 * Functions.
 */
int main(void)
{
    BOARD_Init();
    printf("imgae_fatfs_tjpgdec_basic.\r\n");

    /* setup lcd. */
    LCD_Init_Type lcd_init;
    lcd_init.DisplayMode = LCD_DisplayMode_Portrait; //LCD_DisplayMode_Portrait, LCD_DisplayMode_Landspace
    LCD_Init(&lcd_init);

    printf("press any key to continue ...\r\n");
    getchar();

    /* mount sd card. */
    if (FR_OK == f_mount(&app_fs, app_fs_dirpath, 1))
    {
        printf("init sd card ok.\r\n");
    }
    else
    {
        printf("cannot mount sd card!\r\n");
        return false;
    }

    while (1)
    {
        /* travel the root dir of file system from sd card. */
        if (FR_OK == f_opendir(&app_fs_dir, app_fs_dirpath) )
        {
            while ( FR_OK == f_readdir(&app_fs_dir, &app_fs_fileinfo) )
            {
                /* skip the dirpath. */
                if (0 != (app_fs_fileinfo.fattrib & AM_DIR) ) /* find a dir. */
                {
                    continue;
                }

                /* recycle when reaching to the end of the filelist. */
                if (app_fs_fileinfo.fname[0] == '\0')
                {
                    printf("loop done.\r\n");
                    break;
                }

                /* match the .wav file. */
                if (   (strstr(app_fs_fileinfo.fname, ".jpg"))
                    || (strstr(app_fs_fileinfo.fname, ".JPG")) )
                {
                    getchar();
                    memset(app_fs_filepath, 0, strlen(app_fs_filepath));
                    sprintf(app_fs_filepath, "%s%s", app_fs_dirpath, app_fs_fileinfo.fname);
                    printf("displaying %s ... ", app_fs_filepath);

                    /* play the wav file. */
                    if ( !app_fs_display_jpg_file(app_fs_filepath) )
                    {
                        printf("app_fs_display_jpg_file() fail.\r\n");
                    }
                    else
                    {
                        printf("app_fs_display_jpg_file() done.\r\n");
                    }

                }
            }
        }
    }
}

/* Bytes per pixel of image output */
#define N_BPP (3 - JD_FORMAT)

/* Session identifier for input/output functions (name, members and usage are as user defined) */
typedef struct {
    FIL *fp;               /* Input stream */
    uint8_t *fbuf;          /* Output frame buffer */
    unsigned int wfbuf;     /* Width of the frame buffer [pix] */
} IODEV;


/*------------------------------*/
/* User defined input funciton  */
/*------------------------------*/

size_t in_func (    /* Returns number of bytes read (zero on error) */
    JDEC* jd,       /* Decompression object */
    uint8_t* buff,  /* Pointer to the read buffer (null to remove data) */
    size_t nbyte    /* Number of bytes to read/remove */
)
{
    IODEV *dev = (IODEV*)jd->device;   /* Session identifier (5th argument of jd_prepare function) */
    UINT br;

    if (buff) /* Read data from imput stream */
    {
        //return fread(dev->fp, buff, 1, nbyte, dev->fp);
        return (FR_OK == f_read(dev->fp, buff, nbyte, &br)) ? br : 0;
    }
    else /* Remove data from input stream */
    {
        //return f_seek(dev->fp, nbyte, SEEK_CUR) ? 0 : nbyte;
        return (FR_OK == f_lseek(dev->fp, f_tell(dev->fp) + nbyte)) ? nbyte : 0;
    }
}


/*------------------------------*/
/* User defined output funciton */
/*------------------------------*/

int out_func (      /* Returns 1 to continue, 0 to abort */
    JDEC* jd,       /* Decompression object */
    void* bitmap,   /* Bitmap data to be output */
    JRECT* rect     /* Rectangular region of output image */
)
{
    /* Progress indicator */
    if (rect->left == 0)
    {
        printf("\r%lu%%", (rect->top << jd->scale) * 100UL / jd->height);
    }

    LCD_FillWindow(rect->left, rect->top, rect->right, rect->bottom, (uint16_t *)bitmap);

    return 1;    /* Continue to decompress */
}

#define APP_TJPGDEC_WORK_BUFF_SIZE 3500
uint8_t app_tjpgdec_work_buff[APP_TJPGDEC_WORK_BUFF_SIZE];

/* display a jpg file with its full filepath. */
bool app_fs_display_jpg_file(char * filepath)
{
    JRESULT res;      /* Result code of TJpgDec API */
    JDEC jdec;        /* Decompression object */
    //void *work;       /* Pointer to the work area */
    //size_t sz_work = 3500; /* Size of work area */
    IODEV devid;      /* Session identifier */
    FRESULT fres;

    /* Initialize input stream */
    devid.fp = &app_fs_file;
    fres = f_open(devid.fp, filepath, FA_READ);
    if (fres != FR_OK)
    {
        return -1;
    }

    /* Prepare to decompress */
    //work = (void*)malloc(sz_work);
    //res = jd_prepare(&jdec, in_func, work, sz_work, &devid);
    res = jd_prepare(&jdec, in_func, app_tjpgdec_work_buff, APP_TJPGDEC_WORK_BUFF_SIZE, &devid);
    if (res == JDR_OK)
    {
        /* It is ready to dcompress and image info is available here */
        //printf("Image size is %u x %u.\n%u bytes of work ares is used.\n", jdec.width, jdec.height, sz_work - jdec.sz_pool);

        /* Initialize output device */
        //devid.fbuf = (uint8_t*)malloc(N_BPP * jdec.width * jdec.height); /* Create frame buffer for output image */
        //devid.wfbuf = jdec.width;

        res = jd_decomp(&jdec, out_func, 0);   /* Start to decompress with 1/1 scaling */
        if (res == JDR_OK)
        {
            /* Decompression succeeded. You have the decompressed image in the frame buffer here. */
            printf("\rDecompression succeeded.\n");

        } else {
            printf("jd_decomp() failed (rc=%d)\n", res);
        }

        //free(devid.fbuf);    /* Discard frame buffer */

    }
    else
    {
        printf("jd_prepare() failed (rc=%d)\n", res);
    }

    //free(work);             /* Discard work area */
    f_close(devid.fp);       /* Close the JPEG file */
    return true;
}

/* EOF. */
