/*******************************************************************************
*
*     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
*     SOLELY forUSE IN DEVELOPING PROGRAMS AND SOLUTIONS FOR
*     XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION
*     AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION
*     OR STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS
*     IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
*     AND YOU ARE RESPONSIBLE forOBTAINING ANY RIGHTS YOU MAY REQUIRE
*     forYOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
*     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
*     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
*     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
*     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*     forA PARTICULAR PURPOSE.
*     
*     (c) Copyright 2004 Xilinx, Inc.
*     All rights reserved.
*
******************************************************************************/

#include "globaltypes.h"
#include "xrom_version.h"
#include "xuartns550_l.h"
#include "xrom_main.h"
#include "xrom_input.h"
#include "xrom_tests.h"
#include "xrom_ps2.h"
#include "xparameters.h"

#define HEADER_STRING    "XROM for Virtex-4 ML401\r\n"
#define UART_CLOCK      XPAR_XUARTNS550_CLOCK_HZ
#define UART_1_BASEADDR XPAR_OPB_UART16550_0_BASEADDR

  static unsigned int baudRates[] =
  {
    300,
    600,
    1200,
    2400,
    4800,
    9600,
    19200,
    38400,
    57600,
    115200
  };

#define DEFAULTBAUDRATE      5
#define MAXBAUDRATES      (sizeof(baudRates) / sizeof(unsigned int))

unsigned int UartBaseAdr;
unsigned int UartBaud;
static unsigned int NewUartBaseAdr;
static unsigned int NewUartBaud;

MenuProc printMenu;
InputProc handleInput;
bool doPrintMenu;

typedef struct MenuStackEntry
{
  MenuProc menu;
  InputProc input;
} MenuStackEntry;

struct MenuStackEntry MenuStack[5];
int menuStackPtr = 0;

void PushMenu(MenuProc menu, InputProc input)
{
  /*  assert(menuStackPtr < 5); */
  MenuStack[menuStackPtr].menu = menu;
  MenuStack[menuStackPtr].input = input;
  menuStackPtr++;
}

void PopMenu(MenuProc *menu, InputProc *input)
{
  /*  assert(menuStackPtr > 0); */
  menuStackPtr--;
  *menu = MenuStack[menuStackPtr].menu;
  *input = MenuStack[menuStackPtr].input;
}

static void XromMenu(void)
{
#ifndef SPEED_UP
  xil_printf("\r\n%s", HR);
  xil_printf("%s %s",HEADER_STRING, VERSION_STRING);
  xil_printf("%s\r\n", HR);
#endif

  xil_printf("  1. Tests\r\n");
#ifndef V2PDK
  xil_printf("  2. Communication settings\r\n");
#endif
}

void ComMenu()
{
  xil_printf("\r\nMain.Communication Settings\r\n");
  xil_printf("  1. Select UART: UART");
  
  if (NewUartBaseAdr == UART_1_BASEADDR)
    xil_printf("1");
  else
    xil_printf("2");

  xil_printf("\r\n  2. Select baud rate: %d\r\n", baudRates[NewUartBaud]);
  xil_printf("  0. Set and Exit to Main Menu\r\n");
}

void ComInput(char ch)
{
  switch(ch)
  {
  case '1':
    doPrintMenu = true;
    break;
  case '2':
    NewUartBaud = (NewUartBaud + 1) % MAXBAUDRATES;
    doPrintMenu = true;
    break;
  case '0':
    UartBaseAdr = NewUartBaseAdr;
    UartBaud = NewUartBaud;
    XUartNs550_SetBaud(UartBaseAdr, UART_CLOCK, baudRates[UartBaud]);
    XUartNs550_mSetLineControlReg(UartBaseAdr, XUN_LCR_8_DATA_BITS);
    PopMenu(&printMenu, &handleInput);
    doPrintMenu = true;
    break;
  case 0x1b:
    NewUartBaseAdr = UartBaseAdr;
    NewUartBaud = UartBaud;
    PopMenu(&printMenu, &handleInput);
    doPrintMenu = true;
    break;
  default:
    doPrintMenu = true;
    break;
  }
}


static void XromInput(char ch)
{
  switch(ch)
  {
  case '1':
    printMenu = TestsMenu;
    handleInput = TestsInput;
    PushMenu(XromMenu, XromInput);
    doPrintMenu = true;
    break;
#ifndef V2PDK
  case '2':
    printMenu = ComMenu;
    handleInput = ComInput;
    PushMenu(ComMenu, ComInput);
    doPrintMenu = true;
    break;
#endif
  default:
    doPrintMenu = true;
    break;
  }
}

void XromUartInit(){

  UartBaseAdr = UART_1_BASEADDR;
  UartBaud = DEFAULTBAUDRATE;
  NewUartBaseAdr = UartBaseAdr;
  NewUartBaud = UartBaud;
  XUartNs550_SetBaud(UartBaseAdr, UART_CLOCK, baudRates[UartBaud]);
  XUartNs550_mSetLineControlReg(UartBaseAdr, XUN_LCR_8_DATA_BITS);
}

int main()
{
	usleep(1000);

	//Turn UART ON
	XromUartInit();

	//Turn LCD ON
	XromLCDInit();
	XromLCDOn();

	usleep(1000);

	XromLCDClear();
	XromLCDPrintString("ML401 Diag/Test");
	XromLCDSetLine(2);
	XromLCDPrintChar(0x7E);
	XromLCDPrintString("Use Serial Port");

  printMenu = XromMenu;
  handleInput = XromInput;
  doPrintMenu = true;

  for(;;)
  {
    if(doPrintMenu)
    {
      printMenu();
      doPrintMenu = false;
    }

    InputGetMenu();
  }

  return 0;
}
