//#DOC Main, program entry and main loop
#include "main.h"
#include <otSerial.h>
#include <otTimer.h>
#include <otFPGA.h>
#include <otI2cBus.h>
#include <otRTC.h>
#include <otPrintf.h>
#include <otTextUI.h>
#include <otString.h>
#include <otMCP23017.h>

S32     sn = 1, yy, mm, dd;
U8      h, m, s;
char    code[11];
U8      perc = 0;


const SDRAM_DATA char * mnuStart =
    " SHARKDUINO+        "
    " ------------------ "
    " Text User Interface"
    "   What you see is  "
    "   Is what you get  "
    "  ON TEXT LCD 20x4  "
    " ------------------ "
    "|   Rev.   1.0.0   |"
    "|     May 2021     |"
    "|  (C) 2020-2021   |"
    "| OFFICINA  TURINI |"
    "|    All Rights    |"
    "|     Reserved     |"
    "| ---------------- |"
    "| SN:   ########## |"  // # Mark for numeric field
    "| Code: $$$$$$$$$$ |"  // $ Mark for string field
    "| Option: $$$$$$$$ |"  // $ Mark a menu field
    "| Level:  $$$$$$$$ |"  // $ Mark of a progress bar
    "| Date: ####/##/## |"  // # Mark 3 different variables
    "| Time:   ##:##:## |"  // # Mark 3 different variables
    "| $$$$$$$$$$$$$$$$ |"  // $ Mark for context help. Is rotating
    " ------------------ ";
   
const SDRAM_DATA char   * mnuStartHelp = "***** DOWN ARROW SCROLL DOWN, UP ARROW SCROLL UP, F4 EDIT ALL FIELD ***** ";

const SDRAM_DATA char * mnuOptions[] = {    
    "MENU 1",
    "MENU 2",
    "MENU 3",
    "MENU 4",
    "MENU 5",
    "MENU 6",
    "MENU 7",
    "MENU 8",
    "MENU 9",
    };

otTextUI    ui;
otMCP23017  port;   // Keyboard port

void portInit()
{
    port.init(1);
    
    port.pinMode(0, AS_OUTPUT);
    port.pinMode(1, AS_OUTPUT);
    port.pinMode(2, AS_OUTPUT);
    port.pinMode(3, AS_OUTPUT);
    
    port.pinMode(8, AS_INPUT);
    port.pinMode(9, AS_INPUT);
    port.pinMode(10, AS_INPUT);
    port.pinMode(11, AS_INPUT);
    port.pinMode(12, AS_INPUT);
    port.pinMode(13, AS_INPUT);
    
    port.pinPullUp(8, true);
    port.pinPullUp(9, true);
    port.pinPullUp(10, true);
    port.pinPullUp(11, true);
    port.pinPullUp(12, true);
    port.pinPullUp(13, true);
    
    port.write(0x000F);
}

U16 scanKeyboard(bool release)
{
    U16     b, d;

    for(U16 c = 0; c < 4; c++)
    {
        port.pinWrite(c, false);
        DelayUs(10);
        b = port.read(false) & 0x3F;

        if(b != 0x003F)
        {
            DelayMs(10);
            d = port.read(false) & 0x3F;
            if(d != b) continue;
            b |= (c << 6);
            goto exit;
        }
        port.pinWrite(c, true);
    }
    b = 0;
exit:
    port.write(0x000F);
    if(release)
        while(scanKeyboard(false)) DelayMs(10);
    return b;
}

void setup()
{
    UartEnableSignals(UART0);
    UartSetBaud(UART0, 115200);

    setStdout(4096, UART0); // printf output is now directed on UART0
    
    FpgaInit();
    FpgaHiddenPort(HP_EXT_I2C, true);
    
    I2cBusReset();
    I2cBusFrequency(400, 30);
    
    TimerSetAsCounter(TIMER0);
    TimerEnable(TIMER0, true);
    
    RtcOn();
    
    // This test has been written in this date
    RtcSetDate(2021, 5, 16);
    RtcSetTime(0, 0, 0);
    
    portInit();
    
    ui.init(scanKeyboard);
    
    // Keyboard scan codes
    ui.setScancode(otTextUI::KEY_RET, 0x37);
    ui.setScancode(otTextUI::KEY_ESCAPE, 0x3D);
    ui.setScancode(otTextUI::KEY_BACKSPACE, 0x6F);
    ui.setScancode(otTextUI::KEY_DEL, 0x5F);
    ui.setScancode(otTextUI::KEY_LEFT, 0xFB);
    ui.setScancode(otTextUI::KEY_RIGHT, 0xEF);
    ui.setScancode(otTextUI::KEY_UP, 0xDF);
    ui.setScancode(otTextUI::KEY_DOWN, 0xF7);
    ui.setScancode(otTextUI::KEY_F1, 0x3E);
    ui.setScancode(otTextUI::KEY_F2, 0x2F);
    ui.setScancode(otTextUI::KEY_F3, 0x1F);
    ui.setScancode(otTextUI::KEY_F4, 0x3B);
    ui.setScancode(otTextUI::KEY_PLUS_MINUS, 0xB7);
    ui.setScancode(otTextUI::KEY_MUL_DIV, 0x77);
    ui.setScancode(otTextUI::KEY_0, 0xAF);
    ui.setScancode(otTextUI::KEY_1, 0x9F);
    ui.setScancode(otTextUI::KEY_2, 0xBB);
    ui.setScancode(otTextUI::KEY_3, 0x7B);
    ui.setScancode(otTextUI::KEY_4, 0xFE);
    ui.setScancode(otTextUI::KEY_5, 0xBE);
    ui.setScancode(otTextUI::KEY_6, 0x7E);
    ui.setScancode(otTextUI::KEY_7, 0xFD);
    ui.setScancode(otTextUI::KEY_8, 0xBD);
    ui.setScancode(otTextUI::KEY_9, 0x7D);
    
    // Init var code
    _strcpy(code, "----------");
    
    // Panel description as you see in source code
    ui.panel(mnuStart, mnuStartHelp, 16);
    // Specifiy which variables are used into panel. Must in the same sequence, from top to bottom
    //      and from left to right
    ui.panelVariables(11, &sn, code, mnuOptions, ui.progressOpen(8), &yy, &mm, &dd, &h, &m, &s, ui.help());
    // Specify which variables can be editable
    ui.panelVarAttribute(otTextUI::A_NUMBER, 1, &sn);
    ui.panelVarAttribute(otTextUI::A_TEXT, 1, code);
    ui.panelVarAttribute(otTextUI::A_MENU, 1, mnuOptions);
    // Specify the menu length and who select
    ui.panelMenuSetup(mnuOptions, 9, 0);
    // Use this function to change default variable type
    ui.panelVarChangeType(otTextUI::V_U8, 3, &h, &m, &s);
    // Set progress range
    ui.progressRange(0, 100);
    
    // Show the panel
    ui.panelUpdate(otTextUI::U_REFRESH);
    
    ElapsedTimeStart(TIMER0);
}

void loop()
{
    // Get a key when available
    U16     k = ui.getKey(false);

    // Actions
    switch(k)
    {
        // Scroll the panel up
        case otTextUI::KEY_UP:
            ui.panelUpdate(otTextUI::U_DEC);
            break;
        // Scroll the panel down
        case otTextUI::KEY_DOWN:
            ui.panelUpdate(otTextUI::U_INC);
            break;
        // Edit panel fields
        case otTextUI::KEY_F4:
            ui.edit();
            break;
    }

    // Rotate context help and update variables every 250 ms
    if(ElapsedTimeCheck(250, TIMER0))
    {
        // Get RTC
        RtcGetTime(&h, &m, &s);
        RtcGetDate(&yy, &mm, &dd);

        // Rotate context help
        ui.stringsRotate();
        // Update progress bar
        ui.progressValue(perc);
        // Display
        ui.panelUpdate(otTextUI::U_REFRESH);
        
        perc++;
        if(perc == 100) perc = 0;
        
        ElapsedTimeStart(TIMER0);
    }
}