//#DOC Main, program entry and main loop
#include "main.h"
#include <otSerial.h>
#include <otMalloc.h>
#include <otPrintf.h>
#include <otLepton3.h>
#include <otSpi.h>
#include <otFPGA.h>
#include <otTimer.h>
#include <otImage.h>
#include <otString.h>
#include <otGraphics.h>
#include <otTFMini.h>

#include "palette.h"

#define X_OFFSET 0
#define Y_OFFSET 0

otLepton3   ir;
otImage     display;    // Image for display
otImage     image;      // Image store and processing library
otGraphics  tft;        // Display library
otTFMini    lidar;

U16         * irBuffer;
const U16   * pal[5];

void DisplayLeptonModel()
{
    LEP_CHAR8   oemPartString[32];

    // Get the OEM FLIR Systems Part Number (IDD section 4.6.4)
    if(ir.getOemFlirPartNumber((LEP_OEM_PART_NUMBER_T_PTR) oemPartString) == LEP_OK)
    {
        printf("Part number: %s  ==> ", oemPartString);
        // Part numbers from FLIR Lepton Engineering Datasheet, section 1.5 Key Specifications
        if(_strstr(oemPartString, "500-0659-01") != NULL)
        {
            printf("Lepton 2 Shuttered\n");
        }
        else    
            if(_strstr(oemPartString, "500-0763-01") != NULL)
            {
                printf("Lepton 2.5 Shuttered (Radiometric)\n");
            }
            else
                if(_strstr(oemPartString, "500-0726-01") != NULL)
                {
                    printf("Lepton 3 Shuttered\n");
                }
                else
                    if(_strstr(oemPartString, "500-0771-01") != NULL)
                    {
                        printf("Lepton 3.5 Shuttered (Radiometric)\n");
                    }
                    else
                        printf("Unknown\n");
    }
}


// Show the hottest point of the image
void Cursor(U16 x, U16 y, U16 color)
{
    U16     xs, ys, xd, yd;

    x *= 2;
    y *= 2;

    if(x >= 5) xs = x - 5; else xs = 0;
    if(y >= 5) ys = y - 5; else ys = 0;
    if(x <= 314) xd = x + 5; else xd = 319;
    if(y <= 234) yd = y + 5; else yd = 239;

    tft.drawLine(xs, y, xd, y, color);
    tft.drawLine(x, ys, x, yd, color);
}

// Image display
FAST_CODE_1 void Display()
{
//  LEP_SYS_FPA_TEMPERATURE_KELVIN_T fpaKx100;
    U16     _min = 65535, _max = 0;
    U16     xloc[2], yloc[2];
    U16     * ptr = (U16 *) image.data();
    U32     i;
    char    buf[80];

    // Find min/max in the image
    for(i = 0; i < 19200; i++)
    {
        if(ptr[i] > _max) { _max = ptr[i]; yloc[1] = i / 160; xloc[1] = i % 160; }
        if(ptr[i] < _min) { _min = ptr[i]; yloc[0] = i / 160; xloc[0] = i % 160; }
    }
    // Get FPA temperature as Kelvin
//  ir.getSysFpaTemperatureKelvin(&fpaKx100);
//  F32     t = (fpaKx100 - 27315) / 100.0;
    // Get AUX temperature as Kelvin
//  F32     a = (F32) ir.temperature(false);
    // Convert min/max as temperature
    F32     MN = (_min - 27315) / 100.0;
    F32     MX = (_max - 27315) / 100.0;
    U16     d = lidar.getDistance();

    // Convert grab image to 8 bit for display
    image.shrink(display, (U32) _min + 1, (F32) (_max - _min) / 256.0f);

    // Enable SPI channel for display
    SpiSet(SA_LCD);
    // Show the image with a zoom of 2x
    tft.showImagePalZx2(0, 0, 320, 240, (const U8 *) display.data(), pal[1]);
    // Show the hot point with a cursor
    Cursor(xloc[1], yloc[1], RGB565_BLACK);
    Cursor(xloc[0], yloc[0], RGB565_WHITE);
    // Display min/max on display
    sprintf(buf, "%3.1fC %3.1fC %ucm", MN, MX, d);
    tft.setCursor(0, 220); tft.writeString(buf);
    // Change SPI channel to Lepton
    SpiSet(SA_Y6);
    /*
    // Print on console some statistics
    printf("Image statistics    : Min = %05d @ %2d:%2d -> %.1f C\n", _min, xloc[0], yloc[0], MN);
    printf("Image statistics    : Max = %05d @ %2d:%2d -> %.1f C\n", _max, xloc[1], yloc[1], MX);
    printf("LWIR AUX Temperature: %.2f K : %.1f C.\n", a, a - 273.15f);
    printf("LWIR FPA Temperature: %.2f K : %.1f C.\n", t, t - 273.15f);
    */
}

void setup()
{
    UartEnableSignals(UART0);
    UartSetBaud(UART0, 115200);
    _initMalloc();
    setStdout(4096, UART0);     // printf output is now directed on UART0
   
    FpgaInit();
    FpgaHiddenPort(HP_EXT_I2C, true);
   
    // Init the timer for time measure
    TimerSetAsCounter(TIMER0);
    TimerEnable(TIMER0, true);
   
    // Create an image buffer
    image.create(160, 120, 1, otImage::IMG_U16);
    display.create(160, 120, 1, otImage::IMG_U8);

    // Load some palettes
    pal[0] = gray;
    pal[1] = coldFire;
    pal[2] = coldFireLog;
    pal[3] = volcanoLin;
    pal[4] = volcanoLog;

    // Init display
    tft.init();
    tft.setRotation(otGraphics::IR_90);
    tft.setTextColor(RGB565_YELLOW, RGB565_BLACK);
    tft.setTextSize(2);
    tft.fillRect(0, 0, 320, 240, RGB565_BLACK);
   
    lidar.init(UART1);
    DelayMs(1000);
   
    if(ir.openPort(SA_Y6, 100, 12, TIMER0) != LEP_OK)
    {
        printf("Lepton 3 open failed\n");
        IDLE;
    }
    else
    {
        if(ir.setRadTLinearAutoResolution(LEP_RAD_ENABLE) == LEP_OK)
        {
            if(ir.setOemVideoOutputFormat(LEP_VIDEO_OUTPUT_FORMAT_RAW14) == LEP_OK)
            {
                // Enable VSYNC on the GPIO3 output (you should be able to see this using an oscilloscope)
                // (IDD section 4.6.15 OEM GPIO Mode Select)
                if(ir.setOemGpioMode(LEP_OEM_GPIO_MODE_VSYNC) == LEP_OK)
                {
                    DisplayLeptonModel();
                }
                else printf("Set GPIO failed\n");
            }
            else printf("Get Video Format failed\n");
        }
        else printf("Set RAD Linear AutoResolution Enable failed\n");
    }
    ir.startGrab((U16 *) image.data());
}

void loop()
{

    U32     loopCounter = 0;
    F64     mnT, mxT, ctT;
    LEP_SYS_FPA_TEMPERATURE_KELVIN_T fpaKx100;
    while(1)
    {
        if(ir.isGrabDone())
        {
            //ir.temperatureRange(mnT, mxT, ctT);
            //printf("[%4u] Min = %5.1lfC :: Max = %5.1lfC :: Center = %5.1lfC :: ET = %u us\n", loopCounter++, mnT, mxT, ctT, ir.elapsedTime());

            Display();
            ir.startGrab((U16 *) image.data());
        }
/*      else
            if(ir.getSysFpaTemperatureKelvin(&fpaKx100) == LEP_OK)
            {
                F32 fpaC = (fpaKx100 - 27315) / 100.0;  // Convert to Celsius
                printf("[%4u] FPA = %5.1fC\n", loopCounter++, fpaC);
                DelayMs(100);
            }*/
    }
}