////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002 Xilinx, Inc.  All rights reserved.
//
// Xilinx, Inc.
// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A 
// COURTESY TO YOU.  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 
// FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR 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 FOR A PARTICULAR PURPOSE.
// 
//////////////////////////////////////////////////////////////////////////////

/*      shell.c
 *      Command line shell capable of listing and launching other application threads.
 */

#include "xmk.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <os_config.h>
#include <sys/process.h>
#include <pthread.h>

#define PROGS_LOADED 7

typedef struct prog_info_s {
    void* start_addr;
    unsigned char type;                 /* 0 - thread, 1 - process */
} prog_info_t;

void clear() ;
static char * progs_loaded[PROGS_LOADED] = {
     "0: MEMORY : Linked list example using buffer memory allocation" ,
     "1: SEM    : Semaphores example",
     "2: PRODCON: Producer consumer example using message queues", 
     "3: TIMER  : Timer example, illustrating software timers",
     "4: TICTAC : TicTacToe thread with dynamically assigned large stack",
     "5: MUTEX  : Mutex lock demo",
     "6: PRIO   : Priority queue demo"
};

extern void* llist_main (void *);
extern void* sem_main (void *);
extern void* prodcon_main (void *);
extern void* timertest_main (void *);
extern void* tictac_main (void *);
extern void* clock_main (void *);
extern void* standby_main (void *);
extern void *mutex_main (void *);
extern void *prio_main (void *);

static prog_info_t proginfo [PROGS_LOADED] = { {llist_main, 0},
                                               {sem_main, 0},
                                               {prodcon_main, 0},
                                               {timertest_main, 0},
                                               {tictac_main, 0},
                                               {mutex_main, 0},
                                               {prio_main, 0}
};

#define TICTAC_STACK_SIZE 3000

static char cmd[100];
static pid_t spid;
static pthread_t tid;
static pthread_attr_t attr;
static p_stat shell_ps;
static char tictac_stack[TICTAC_STACK_SIZE] __attribute__ ((aligned(8))); 
static struct sched_param spar;
extern volatile int hrs, mins, secs, tot_secs;
static int targ;

void start_clock ()
{
    int ret;
    
    pthread_attr_init (&attr);                                                          /* Need to launch a thread */
    spar.sched_priority = 0;
    pthread_attr_setschedparam(&attr,&spar);

    ret = pthread_create (&tid, &attr, (void*)clock_main, NULL);

    if (ret != 0) {
        xil_printf ("-- ERROR (%d) launching clock thread. Clock services unavailable...\r\n", ret);
    }

}

void start_standby ()
{
    int ret;
    
    pthread_attr_init (&attr);                                                          /* Need to launch a thread */
    spar.sched_priority = 0;
    pthread_attr_setschedparam(&attr,&spar);

    targ = 10000;                                                                       /* Standby for 10 seconds */
    ret = pthread_create (&tid, &attr, (void*)standby_main, &targ);
    if (ret != 0) {
        xil_printf ("-- ERROR (%d) launching standby thread. Unable to enter standby mode...\n", ret);
        return;
    }
    
    ret = pthread_join (tid, NULL);
}

void* shell_main( void *dummy)
{
    int opt;
    char *str, c, savec;
    int delay, i, ret;


    print ("SHELL: Starting clock...\r\n");
    start_clock ();

    print("\r\n\r\n") ;	
    clear ();
    savec = 0;
    while (1) {
	print ("shell>");
	str = &(cmd[0]);                                                                        /* Get input line */

        c = inbyte ();
            
        if (savec) {
            if (c != savec && (c == '\r' || c == '\n'))
                c = inbyte ();                                                                  /* Eat up a character here */
        } 
        
	while (c != '\r' && c != '\n') {
	    if (c == '\b') {
		if (str != &(cmd[0]))
		    str--;
	    } else {
		*str = c ;
		str++ ;
	    }
	    outbyte(c) ;
	    c = inbyte() ;
	}

        savec = c;
	*str = '\0' ;

	outbyte('\r');
        outbyte('\n');

                                                                                                /* Process the command......*/
	if( cmd[0] == '\0' )
	    continue ; 
	else if ( cmd[0] == 'r' && cmd[1] == 'u' && cmd[2] == 'n' && cmd[3] == ' ') {
            c = cmd[4];
            opt = c - '0';
            if (opt < 0 || opt >= PROGS_LOADED) {
                print ("Unrecognized command. Type 'help' to see available commands.\r\n");
                continue;
            }
            pthread_attr_init (&attr);                                                      /* Need to launch a thread */
            if (opt == 4) {                                                                 /* Special attention to tictac thread */
                pthread_attr_setstack (&attr, tictac_stack, TICTAC_STACK_SIZE);
            }
            ret = pthread_create (&tid, &attr, (void*)proginfo[opt].start_addr, NULL);
            if (ret != 0) {
                xil_printf ("-- ERROR (%d) launching thread. Program not run.\r\n", ret);
            }
            else { 
                print ("-- shell going into wait-mode to join with launched program.\r\n");
                ret = pthread_join (tid, NULL);
            }	    
        } else if (!strcmp (cmd, "standby")) {
            start_standby ();
        } else if( !strcmp(cmd, "clear") ) {
	    clear();
	} 
	else if( !strcmp(cmd, "list") ) {
	    print("\r\nList of programs loaded in this example system\r\n") ;
	    for (i = 0; i < PROGS_LOADED; i++) {
		print(progs_loaded[i]); 
		print("\r\n");
	    }
            print ("\r\n");
	} else if (!strcmp(cmd, "time") ) {
            xil_printf ("Time is: %02d:%02d:%02d.\r\n", hrs, mins, secs);
        } else if (cmd[0] == 't' && cmd[1] == 'i' && cmd[2] == 'm' && cmd[3] == 'e'){
            str = (cmd+5);
            ret =  ((*str++)-'0')*1000;
            ret += ((*str++)-'0')*100;
            ret += ((*str++)-'0')*10;
            ret += ((*str)-'0');
            clock_set_time (ret);
        } else if (!strcmp(cmd, "help") ) {
	    print("\r\nList of commands\r\n");
	    print("run <program_num>: Run a program. For e.g. \"run 0\" loads the first program.\r\n");
            print("time ?HHMM?      : Set/Display the current time.\r\n");
            print("standby          : Suspend all tasks for 10 seconds. Idle task executes.\r\n");
	    print("clear            : Clear the screen\r\n");
	    print("list             : List the programs loaded for this example system\r\n");
	    print("help             : This help screen\r\n");
	    print("exit             : Exit this shell\r\n\r\n");
	} 
	else if (!strcmp(cmd, "exit")) {
	    print("Exiting shell\r\nGood Bye !\r\n");
	    pthread_exit(0);
	}
	else 
            print ("Unrecognized command. Type 'help' to see available commands.\r\n");
    }
    return 0 ;
}

void clear()
{
    int i = 0 ;
    for(; i < 80; i++ ) {
	outbyte('\r') ; outbyte('\n') ;
    }
}


int main ()
{

    xilkernel_main ();
}
