
/*  bmp.c */

#include "bmp.h"
#include "ff.h"			                                                /* Declarations of FatFs API */
#include "diskio.h"
#include "app.h"

#if 0

#define Image_bytes_len 25536 //
uint16_t file_buff[Image_bytes_len];                                            //--AZ????Ĵ洢_ 4ͼ?????Ķ???buffer
uint16_t Buff_save_BMP[Image_bytes_len];                                        //--AZ????Ĵ洢_ 4ͼ?????Ķ???buffer



static FATFS g_fileSystem; /* File system object */
static FIL g_fileObject;   /* File object */
const TCHAR driverNumberBuffer[3U] = {SDDISK + '0', ':', '/'};
FRESULT error;

extern uint32_t keyValuePre, keyValue;

#if 0
int APP_FAT_Init(void)
{
    if (f_mount(&g_fileSystem, driverNumberBuffer, 0U))                         //--AZ 1.ʹ?FATFS????????f_mountע???????????<???   (????????????????SD??/SPI FLASH /NAND FLASH)
    {
        PRINTF("Mount volume failed.\r\n");
        return -1;
    }
    #if (FF_FS_RPATH >= 2U)
        error = f_chdrive((char const *)&driverNumberBuffer[0U]);
        if (error)
        {
            PRINTF("Change drive failed.\r\n");
            return -1;
        }
    #endif
}

#endif

/*!
 * Input : Y_start , BMP file path
 */
uint32_t Num_of_BMP;
BITMAP_INFO_HEADER infoHead;
BMP_ERR_TypeDef APP_LCD_ShowBMP( uint16_t Start_y, const char *bmpPathPtr )
{
    FRESULT fresult;
    FIL file_obj;
    uint32_t br;
    uint16_t pixel = 0;                                                         //--16 bits pixel
    RGBQUAD tempQuad;
    const uint8_t OPPSET_POS = 0;                                              //--Make sure 4 bytes align OR NOT ?
    const uint16_t BMP_BUFF_SIZE = 10000;                                      //--no speccific buffer size
    int32_t i,X_AZ,Y_AZ,bmpBuffPtr_index_Num,I_WHILE_FOR ;

    Num_of_BMP = 0;

    X_AZ =0;
    Y_AZ = Start_y;                                                             //--the original bottom line number


    /* --Step1  Open file*/
    if (f_open(&file_obj,bmpPathPtr,FA_OPEN_EXISTING | FA_READ) != FR_OK)
    {
        return eErrTypeBMP_OPEN_FILE;
    }
    /* --Step2  Read fileHead  */
    BITMAP_FILE_HEADER fileHead;
    fresult = f_read(&file_obj,&fileHead,sizeof(BITMAP_FILE_HEADER),&br);
    if (fresult != FR_OK)
    {
        f_close(&file_obj);
        return eErrTypeBMP_OPEN_FILE;
    }
    /* --Step 2-1 verify "BM" */
    if (fileHead.bfType != 0x4D42)
    {
        f_close(&file_obj);
        return eErrTypeBMP_FILE_HEAD;
    }


    /* --Step3 Read infoHead , and need move offset bytes ?*/

//    BITMAP_INFO_HEADER infoHead;
    if (f_read(&file_obj,&infoHead,sizeof(BITMAP_INFO_HEADER),&br) != FR_OK)
    {
        f_close(&file_obj);
        return eErrTypeBMP_OPEN_FILE;
    }


    /* --?? infoHead.biWidth should be 4 times */
    /*--Step3-1 virtualWidth = infoHead.biWidth = pixels */
    const uint32_t MULTIPLE = 4;
    uint32_t originBiWidth = infoHead.biWidth;                                  //-- 600 pixels
    uint8_t rowRemain = infoHead.biWidth % MULTIPLE;
    if (rowRemain != 0)
    {
        uint32_t div = infoHead.biWidth / MULTIPLE;
        infoHead.biWidth = (div + 1) * MULTIPLE;
    }
    uint32_t virtualWidth = 0;
    switch ( infoHead.biBitCount )
    {
        case 8:
            virtualWidth = infoHead.biWidth;
            break;

                                                                                //this code not decode 16 /24/32 Bits .
        default:
            f_close(&file_obj);

            return eErrTypeBMP_NOT_SUPPORT;
    }
    /* --Step3-3  verify the biHeight and biWidth are legal value*/
    if ((infoHead.biHeight==0) || (infoHead.biWidth==0))
    {
        f_close(&file_obj);
        return eErrTypeBMP_NONE;
    }


    /* --Step3-4-1  palette : Does the palette really existexist: bfOffBits = FILE_HEADER + INFO_HEADER + RGBQUAD*/
    bool isIncludePalette = true;
    if (fileHead.bfOffBits == sizeof(BITMAP_FILE_HEADER) + sizeof(BITMAP_INFO_HEADER))
    {
        isIncludePalette = false;
    }
    /* --Step3-4-2 calloc for  palette , remember free finally*/
    RGBQUAD *palettePtr = NULL;                                                 //-- RGBQUAD type Pointer palette (4 bytes)
    uint32_t paletteNums = 0;
    if (isIncludePalette == true)
    {
        paletteNums = fileHead.bfOffBits - sizeof(BITMAP_FILE_HEADER) - sizeof(BITMAP_INFO_HEADER); //--like this: (1078 - 14 - 40 = 1024)
        palettePtr = (RGBQUAD *)calloc(1,paletteNums);                          //--palettePtr point to <Forced conversion to (RGBQUAD *)>
        if (palettePtr == NULL)
        {
            f_close(&file_obj);
            return eErrTypeBMP_MALLOC;
        }
    }

    /* ---------Step3-4-3 Obtain palette data */
    if (isIncludePalette == true)
    {
        if (f_read(&file_obj,palettePtr,paletteNums,&br) != FR_OK)              //--f_read  paletteNums bytes data as palette data , then use palettePtr to show them one by one
        {
            f_close(&file_obj);
            if (isIncludePalette == true)
            {
                free(palettePtr);
            }
            return eErrTypeBMP_OPEN_FILE;
        }
    }



    /*--Step4  show BMP data after offsit*/

    uint8_t *bmpBuffPtr = (uint8_t *)&file_buff;                                //--bmpBuffPtr use to save BMP data
    uint32_t maxBuffSize = BMP_BUFF_SIZE - OPPSET_POS;
    uint32_t maxReadLenth = maxBuffSize;
    if (maxBuffSize % virtualWidth != 0)
    {
        uint32_t div = maxBuffSize / virtualWidth;                              //--               Like ?? 3998/601 = 6
        maxReadLenth = div * virtualWidth;                                      //--               Like ?? maxReadLenth =  6*601 = 3606
    }


    /*--Note:read BMP data sector by sevtor ??use f_lseek() to point new palette*/
    uint32_t offset = fileHead.bfOffBits - OPPSET_POS;
//    while (1)                                                                  //--Or a for ()   ,all can be work
//    {

    f_lseek(&file_obj,offset);                                                  //--We need Junmp and point to BM data buffer , because we have to read news BMP data    OR every time we read
    for(I_WHILE_FOR = 0; I_WHILE_FOR<20;I_WHILE_FOR++)
    {


        fresult = f_read(&file_obj,bmpBuffPtr,maxReadLenth+OPPSET_POS,&br);     //--f_read maxReadLenth+OPPSET_POS bytes data as BMP data save in bmpBuffPtr , it's just index
           br -= OPPSET_POS;                                                    //--update br value( the real bytes read from file)
           offset += br;                                                        //--update offset ?

                if (fresult != FR_OK)
                {
                    f_close(&file_obj);
                    if (isIncludePalette == true)
                    {
                        free(palettePtr);
                    }
                    return eErrTypeBMP_OPEN_FILE;
                }
                if (br == 0)                                                    //--if no BMP data be read , break
                {
                    break;                                                    //--20180918 Adision Ignore
                }

        //memmove(bmpBuffPtr,bmpBuffPtr+OPPSET_POS,maxReadLenth);                 //--like ( USART0_NS->FIFOWR = *(bmpBuffPtr++); )Find palettePtr [] by using indes saved on BMP data


        //--begain read

              for (bmpBuffPtr_index_Num = 0; bmpBuffPtr_index_Num < br; bmpBuffPtr_index_Num++)           //--for the read br bytes data
                {
/*
*/
//--???Ŀǰ???x??16 bits ???  x =   (I_WHILE_FOR )* + bmpBuffPtr_index_Num


                    tempQuad = *(RGBQUAD *)(palettePtr + *(uint8_t *)(bmpBuffPtr + bmpBuffPtr_index_Num));//--RGBQUAD = 4bytes , using bmpBuffPtr's data as index to find the real RGB value
                    pixel = (( tempQuad.rgbRed &0xF8)<<8)|(( tempQuad.rgbGreen &0xFC)<<3)|(( tempQuad.rgbBlue &0xF8)>>3);//--(5 + 6 + 5 = 18 bits : 24->18 RGB value)
Buff_save_BMP[Num_of_BMP] = pixel;                                              //--save the data;
Num_of_BMP++;
/*--Show pixel dot by dot*/
#if 0
                     if(X_AZ == originBiWidth)                                  //--like 600th date :this line not finish yet  , Y shoule wait finish and -1
                     {
                      lcd_draw_point(X_AZ, Y_AZ, pixel);
                       Y_AZ--;
                       X_AZ = 0;
                     }
                     else
                     {
                        lcd_draw_point(X_AZ, Y_AZ, pixel);
                     }
                     X_AZ++;
#endif



                }

    }

    f_close(&file_obj);
    if (isIncludePalette == true)
    {
        free(palettePtr);                                                       //--?????ڴ?
    }

    return eErrTypeBMP_NONE;
}

//extern void __LCD_WRITE_BYTE(uint8_t txDat);
int APP_Show_BMP_UsingBuffer(uint16_t * Buffer)
{
#if 1
	uint32_t i,j, wCount = infoHead.biWidth,wCount_Height = infoHead.biHeight;

	//wCount *= infoHead.biHeight;


        for(j=280; j > (208-wCount_Height);j--)                                //--?ô???
        {
          for (i = 0; i < wCount; i ++) {                                      //--??? 1 ?
            lcd_draw_point(i,j,*(Buffer++));
          }
        }

#endif
}

#endif

uint8_t gAppBmpDisplayData[2 * LCD_HEIGHT * LCD_WIDTH]; /* display buff for LCD. */

BMP_ERR App_BmpDumpFromFile(char * filename, uint16_t * height, uint16_t * width, uint8_t * displaydata8b)
{
    FIL fileObj;
    BITMAP_FILE_HEADER bmpFileHeader;
    BITMAP_INFO_HEADER bmpInfoHeader;
    uint32_t br; /* the count of available bytes in file read opeation. */
    //uint32_t idx;
    uint8_t rgb[3];
    FRESULT res;
    uint16_t x, y, y1;

    /* STEP 1: Open file and read the header. */
    // if ( FR_OK != f_open(&fileObj, filename, FA_OPEN_EXISTING | FA_READ) )
    //if ( FR_OK != f_open(&fileObj, filename,  FA_READ) )
    res = f_open(&fileObj, filename, FA_OPEN_EXISTING | FA_READ);
    if ( FR_OK != res)
    {
        return eErrTypeBMP_OPEN_FILE; /* can not open the bmp file. */
    }
    if ( FR_OK != f_read(&fileObj, &bmpFileHeader, sizeof(BITMAP_FILE_HEADER), &br) )
    {
        f_close(&fileObj);
        return eErrTypeBMP_OPEN_FILE; /* can not read the bmp header. */
    }

    if (bmpFileHeader.bfType != 0x4D42) /* verify "BM" file type. */
    {
        f_close(&fileObj); /* unsupported image type. */
        return eErrTypeBMP_FILE_HEAD;
    }

    /* STEP 2: Read the BMP info header. */
    if ( FR_OK != f_read(&fileObj, &bmpInfoHeader, sizeof(BITMAP_INFO_HEADER), &br) )
    {
        f_close(&fileObj);
        return eErrTypeBMP_OPEN_FILE;
    }

    bmpInfoHeader.biWidth = (bmpInfoHeader.biWidth + 3) & (0xFFFFFFFC); /* uint32_t, 4 bytes aligned. */

    if (    (24 != bmpInfoHeader.biBitCount) /* only support 8-bit image type in this version's code. would support more later. */
         || (240 != bmpInfoHeader.biWidth)  /* only support 240 width. */
       )
    {
        f_close(&fileObj);
        return eErrTypeBMP_NOT_SUPPORT;
    }

#if 0
    for (idx = 0u; idx < bmpInfoHeader.biWidth * bmpInfoHeader.biHeight; idx++)
    {
        uint16_t rgb16 = 0u;
        f_read(&fileObj, rgb, 3u, &br); /* Read color. */
        rgb16 = (    ( (rgb[0] & 0xF8) << 8u)
                   | ( (rgb[1] & 0xFC) << 3u)
                   | ( (rgb[2] & 0xF8) >> 3u)  );//--(5 + 6 + 5 = 18 bits : 24->18 RGB value)
        /* gAppBmpDisplayData */


        lcd_draw_point(idx % LCD_WIDTH, idx / LCD_WIDTH, rgb16);
    }
#endif

    *height = bmpInfoHeader.biHeight;
    *width  = bmpInfoHeader.biWidth;

    for (y = 0; y < bmpInfoHeader.biHeight; y++)
    {
        y1 = (bmpInfoHeader.biHeight - y - 1); /* 上下行反转 */
        for (x = 0; x < bmpInfoHeader.biWidth; x++) /* bmpInfoHeader.biWidth = 240u */
        {
            uint16_t rgb16 = 0u;
            f_read(&fileObj, rgb, 3u, &br); /* Read color. */
            rgb16 = (    ( (rgb[0] & 0xF8) << 8u)
                       | ( (rgb[1] & 0xFC) << 3u)
                       | ( (rgb[2] & 0xF8) >> 3u)  );//--(5 + 6 + 5 = 18 bits : 24->18 RGB value)
            displaydata8b[((y1 * bmpInfoHeader.biWidth) + x)*2 ]    = (uint8_t)(0xFF & (rgb16 >> 8u));
            displaydata8b[((y1 * bmpInfoHeader.biWidth) + x)*2 + 1] = (uint8_t)(rgb16 & 0xFF);
        }
    }


    return eErrTypeBMP_NONE;
}

void App_DisplayBmp2Lcd(uint16_t height, uint16_t width, uint8_t * displaydata)
{

}






















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