/*
 * IO.c
 *
 * Input/Output routines including time display functions
 *
 *  Created on: Jan 23, 2014
 *      Author: RCG
 */

#include "main.h"
#include "board_util.h"
#include "system.h"
#include "sleep.h"
#include "user_io.h"
#include "microsd.h"
#include "uartstdio.h"	// Use local version with larger RX buffer
#include "serial.h"

#include "inttypes.h"

extern int dbg_flag;

/*
 * uprintf has been modified to handle config parm for cr vs cr-lf line termination
 */
void newline_test(void)            // defd in user_io.c
{
    // Testing for newline.   In user_io.c, set breakpoint at    va_start (args, format);

    sys_data.app_cfg[APPCFG_SER_LINETERM_MODE] = 0;  // Temporary for dev, dev cr-lf as the mode
    uprintf("\r\nHowdy Captain"); // Works

    sys_data.app_cfg[APPCFG_SER_LINETERM_MODE] = 0;
    uprintf("\rHowdy Captain");

    sys_data.app_cfg[APPCFG_SER_LINETERM_MODE] = 1;  // Temporary for dev, dev cr-lf as the mode
    uprintf("\r\nHowdy Captain"); // Works

    sys_data.app_cfg[APPCFG_SER_LINETERM_MODE] = 1;
    uprintf("\rHowdy Captain");
//---

    sys_data.app_cfg[APPCFG_SER_LINETERM_MODE] = 0;  // Temporary for dev, dev cr-lf as the mode
    uprintf("Howdy Captain\r\n"); //Works: Howdy Captain\r\n

    sys_data.app_cfg[APPCFG_SER_LINETERM_MODE] = 0;
    uprintf("Howdy Captain\r");  //Works: Howdy Captain\r\n

    //TODO, test big string 255 chars

    sys_data.app_cfg[APPCFG_SER_LINETERM_MODE] = 1;  // Temporary for dev, dev cr-lf as the mode
    uprintf("Howdy Captain\r\n"); // Works: Howdy Captain\r

    sys_data.app_cfg[APPCFG_SER_LINETERM_MODE] = 1;
    uprintf("Howdy Captain\r");   // Works: Howdy Captain\r


}

/*
 * shorthand call for print newline
 *
 * DOS & Windows: \r\n 0D0A (hex), 13,10 (decimal)
 * Unix & Mac OS X: \n, 0A, 10
 * Macintosh (OS 9): \r, 0D, 13
 *
 */
void prn_nl(void)
{
    print_newline(sys_data.app_cfg[APPCFG_SER_LINETERM_MODE]);
}

uint32_t sprn_nl(char *bufPtr, uint32_t bufIndx)
{
    return sprintf_newline(bufPtr, bufIndx, sys_data.app_cfg[APPCFG_SER_LINETERM_MODE]);
}

uint32_t sprintf_newline(char *bufPtr, uint32_t bufIndx, int mode)
{
    // cr-lf
    if(mode == 0)
    {
        //uprintf("\r\n");  // 0x0d 0x0a
        *(bufPtr+bufIndx) = 0x0d;     //CR \r
        bufIndx++;
        *(bufPtr+bufIndx) = 0x0a;     //LF \n
        *(bufPtr+bufIndx+1) = 0x00;     //null term
        bufIndx = 2;
    }
    else if(mode == 1)  // lf  default for CF2 ISUS files
    {
        //uprintf("\n");
        *(bufPtr+bufIndx) = 0x0d;     //CR \r
        *(bufPtr+bufIndx+1) = 0x00;     //null term
        bufIndx = 1;
    }
    else if(mode == 2) // lf  default for CF2 ISUS files
    {
        //uprintf("\n");
        *(bufPtr+bufIndx) = 0x0a;     //LF \n
        *(bufPtr+bufIndx+1) = 0x00;     //null term
        bufIndx = 1;
    }
    else
    {
        // if wonky mode value, default for MSC1 compat
        *(bufPtr+bufIndx) = 0x0a;     //LF \n
        *(bufPtr+bufIndx+1) = 0x00;     //null term
        bufIndx = 1;
    }

    return(bufIndx);
}
// print_newline(prn_nl();)
void print_newline(int mode)
{

    // cr-lf default for CF2 ISUS
    if(mode == 0)
    {
        //uprintf("\r\n");  // 0x0d 0x0a
        UARTputc(0x0d);     //CR /r
        UARTputc(0x0a);     //LF /n
    }
    else if(mode == 1)  // cr
    {
        UARTputc(0x0d);   // CR 0x0d "\r"
    }
    else if(mode == 2)      // lf
    {
        UARTputc(0x0a);   // LF 0x0a "\n"
    }
    else
    {
        //APFTODO, report error?  default behavior for MSC3
        UARTputc(0x0d);     //CR /r
        UARTputc(0x0a);     //LF /n
    }

}

/*
 * Print out the passed in prompt and offer user
 * a yes or no choice.
 * Returns YES (1), or NO (0).
 */
int yesOrNoMenuChoice(char *prompt, int default_response)
{
	char input;

	// Print prompt
	uprintf("%s", prompt);

	input = get_key();

	if(input == 'Y' || input == 'y') return YES;
	else if(input == 'N' || input == 'n') return NO;
	else return default_response;
}

/*
 * Print out the passed in prompt and offer user
 * a yes or no choice.
 * Returns YES (1), or NO (0).
 */
int yesOrNoMenuChoiceEcho(char *prompt, int default_response)
{
    char input;

    // Print prompt
    uprintf("%s", prompt);

    input = get_key();

    if(input == 'Y' || input == 'y')
    {
        uprintf("Y"); prn_nl();
        return YES;
    }
    else if(input == 'N' || input == 'n')
    {
        uprintf("N"); prn_nl();
        return NO;
    }
    else
    {
        return default_response;
    }
}

/*
 * Print out the passed in prompt and offer user
 * a yes or no choice.  Repeat until they give a valid
 * yes or no response.
 * Enforce a TIME LIMIT (seconds).  IF NO VALID INPUT AFTER THE TIME LIMIT,
 * RETURNS TIMELIMITPASSED (-1).
 * Otherwise, returns YES (1), or NO (0).
 */
/*
int yesOrNoMenuChoiceTimeLimit(char *prompt, int timeLimit)
{
	char userInput[16];
	int charCount;
	uint32_t startTicks;
	uint32_t elapsedTicks;

	//print their prompt
	uprintf("%s", prompt);

	//Loop until they give a valid response or time is up
	startTicks = read_hib_rtcc();
	while(1)
	{
		//if user has enters a CR, store and check the string
		if(UARTPeek('\r') >= 0)
		{
			//store user input in inputBuffer.  charCount stores # of chars sent
			charCount = UARTgets(userInput, sizeof(userInput));

			//they should have only entered one character (Y or N)
			if(charCount == 1)
			{
				if(userInput[0] == 'Y' || userInput[0] == 'y')
				{
					return YES;
				}

				else if(userInput[0] == 'N' || userInput[0] == 'n')
				{
					return NO;
				}
			}

			//They didn't give a valid response.  Prompt them for a better response, and start the loop over.
			uprintf("Did not receive a valid response.  Enter Y or N.\r\n");
			uprintf("%s", prompt);
		}

		//else, update seconds passed, if timeLimit seconds pass, return -1
		else
		{
			elapsedTicks = read_hib_rtcc() - startTicks;
			if( (elapsedTicks > timeLimit))
			{
				return TIMELIMITPASSED;
			}
		}
	}
}
*/

/*
 * Fills in the passed in userInputBuffer with input (via UARTgets).
 * Peek for a return carriage before calling UARTgets so that
 * delete/backspace still works.
 * Returns the count of characters that were stored, not including
 * null.
 */
int getUserInput(char *userInputBuffer, int userInputBufferSize)
{
	int charCount;

	while(1)
	{
	    wdog_pet();
		//only store a string, if user has entered CR
		if(UARTPeek('\r') >= 0)   // APFTODO  || UARTPeek('\n') >= 0) )
		{
			//store user input in userInputBuffer.  charCount stores # of chars sent
			charCount = UARTgets(userInputBuffer, userInputBufferSize);
			break;
		}
	}

	return charCount;
}




/*
 * Fills in the passed in userInputBuffer with input (via UARTgets).
 * Peek for a return carriage before calling UARTgets so that
 * delete/backspace still works.
 * Returns the count of characters that were stored, not including
 * null.
 * Enforce a TIME LIMIT (seconds).  IF NO VALID INPUT AFTER THE TIME LIMIT,
 * RETURNS TIMELIMITPASSED (-1).
 */

int getUserInputTimeLimit(char *userInputBuffer, int userInputBufferSize, int timeLimit)
{
	int charCount;
	uint32_t startTicks;
	uint32_t elapsedTicks;

	//Loop until they give a valid response or time is up
	startTicks = read_hib_rtcc();
	while(1)
	{
		//if user enters a CR, store and check the string, data is in ISR rx buffer, UARTgets is called if latest buffer entry is <CR>
		if(UARTPeek('\r') >= 0)
		{
			//store user input in inputBuffer.  charCount stores # of chars sent
			charCount = UARTgets(userInputBuffer, userInputBufferSize);
			return charCount;
		}

		//else, update seconds passed, if timeLimit seconds pass, return -1
		else
		{
			elapsedTicks = read_hib_rtcc() - startTicks;
            if( (elapsedTicks > timeLimit))
            {
                return TIMELIMITPASSED;
            }
		}
	}

}

/****************************************************************
 * Print the current time according to the RTC.
 ****************************************************************/
void printCurrentTime(void)
{
	char timeStamp[TIMESTAMPLENGTH];
	uint32_t ticks;
	struct tm *time_struct;

	//get the time from the from the RTC so we can print it
	ticks = read_hib_rtcc();

	time_struct = localtime((const time_t*)&ticks);
	strftime(timeStamp, sizeof(timeStamp),"%m/%d/%y %H:%M:%S", time_struct);
	uprintf("%s", timeStamp);
	//prn_nl();   Do not print cr-lf in this fxn
}

/****************************************************************
 * Print the current epoch msec time according to the RTC.
 ****************************************************************/
void printCurrentEpochTime(void)
{
    char timeStamp[TIMESTAMPLENGTH];
    uint32_t posixtime_ms, ticks;
    struct tm *time_struct;

    prn_nl();
    //get the time from the from the RTC so we can print it
    posixtime_ms = read_hib_rtcc();
    ticks = posixtime_ms;

    posixtime_ms -= (2208963732);       // hacked offset  https://www.epoch101.com/  subtract what rtc is displaying in teraterm
    posixtime_ms *= 1000LL;         // make it msec
    sprintf(timeStamp, "%13" PRIu32, posixtime_ms);

    uprintf("%s", timeStamp);

    uprintf("   ");

    //debug
    time_struct = localtime((const time_t*)&ticks);
    strftime(timeStamp, sizeof(timeStamp),"%m/%d/%y %H:%M:%S", time_struct);
    uprintf("%s", timeStamp);
    prn_nl();
}

/*
 * Print the time according to the passed in time_t value (this is
 * not necessarily the RTC's current time, just any time_t).
 * (Prints that time followed by a new line.)
 */

void print_time_t_Time(time_t time)
{
	char timeStamp[TIMESTAMPLENGTH];
	struct tm *time_struct;

	time_struct = localtime((const time_t*)&time);
	strftime(timeStamp, sizeof(timeStamp),"%m/%d/%y %H:%M:%S", time_struct);
	uprintf("%s", timeStamp); prn_nl();
}



/*
 * getDateAndTime
 * Queries the user for a date and time in 24 hour format.
 * Returns: Unix calendar time (time_t) in seconds
 */
time_t getDateAndTime()
{
	char monthString[3];
	char dayString[3];
	char yearString[3];
	char hourString[3];
	char minuteString[3];
	char secondString[3];

	char *p;  //helper variable

	//variables for keeping track of user text input:
	char timeInput[23];
	int charCount;

	int month;
	int day;
	int year;
	int hour;
	int minute;
	int second;

	int validInput = 1; //helper boolean

	//time variables:
	time_t rawtime;
	struct tm * timeStruct;

	// Loop until given a valid time string
	while(1)
	{
		prn_nl(); prn_nl(); uprintf("Enter time [");
		printCurrentTime();
		uprintf("]: ");

		validInput = 1;

		//store user input in inputBuffer.  charCount stores # of chars sent
		charCount = getUserInput(timeInput, sizeof(timeInput));

		//make sure the user has at least entered the 17 chars of MM/DD...
		if( charCount == 17)
		{
			//now check for appropriate punctuation chars
			if(timeInput[2] == '/' && timeInput[5] == '/' && isspace(timeInput[8]) && timeInput[11] == ':' && timeInput[14] == ':')
			{
				//break up the string into it's individual pieces (month, day...):
				strncpy(monthString, &timeInput[0], 2 );
				monthString[2] = '\0';

				strncpy(dayString, &timeInput[3], 2 );
				dayString[2] = '\0';

				strncpy(yearString, &timeInput[6], 2 );
				yearString[2] = '\0';

				strncpy(hourString, &timeInput[9], 2 );
				hourString[2] = '\0';

				strncpy(minuteString, &timeInput[12], 2 );
				minuteString[2] = '\0';

				strncpy(secondString, &timeInput[15], 2 );
				secondString[2] = '\0';


				//Make sure all the strings convert to an int:
				errno = 0;
				p = monthString;
				month = (int)strtol( monthString, &p, 10);
				if( (errno != 0) || (monthString == p) || (*p != 0))
				{
					// conversion failed (EINVAL, ERANGE)
					// conversion failed (no characters consumed)
					// conversion failed (trailing data)
					validInput = 0;
				}

				errno = 0;
				p = dayString;
				day = (int)strtol( dayString, &p, 10);
				if( (errno != 0) || (dayString == p) || (*p != 0))
				{
					validInput = 0;
				}

				errno = 0;
				p = yearString;
				year = (int)strtol( yearString, &p, 10);
				if( (errno != 0) || (yearString == p) || (*p != 0))
				{
					validInput = 0;
				}

				errno = 0;
				p = hourString;
				hour = (int)strtol( hourString, &p, 10);
				if( (errno != 0) || (hourString == p) || (*p != 0))
				{
					validInput = 0;
				}

				errno = 0;
				p = minuteString;
				minute = (int)strtol( minuteString, &p, 10);
				if( (errno != 0) || (minuteString == p) || (*p != 0))
				{
					validInput = 0;
				}

				errno = 0;
				p = secondString;
				second = (int)strtol( secondString, &p, 10);
				if( (errno != 0) || (secondString == p) || (*p != 0))
				{
					validInput = 0;
				}


				//if all the fields are indeed integers...
				if(validInput)
				{
					if( second >= 0 && minute >= 0 && hour >= 0 && month >= 1 && day >= 1 && year >= 0)
					{
						if( second <= 61 && minute <= 59 && hour <= 23 && day <= 31 && month <= 12)
						{
							//fill in time.h's tm struct initially (timeStruct just points to time.h's struct)
							time(&rawtime);
							timeStruct = localtime(&rawtime);

							//modify as user desired
							timeStruct->tm_sec = second;
							timeStruct->tm_min = minute;
							timeStruct->tm_hour = hour;
							timeStruct->tm_mday = day;
							timeStruct->tm_mon = month - 1;
							timeStruct->tm_year = (year + 2000) - 1900;

							//GMT HAS NO DAYLIGHT SAVINGS
							timeStruct->tm_isdst = 0;


							//remake the struct
							rawtime = mktime(timeStruct);

							//print out the time the user entered
							//prn_nl(); prn_nl(); uprintf( "Time is: %s", asctime(timeStruct));

							return rawtime;
						}
					}
				}
			}
		}
		else if(charCount == 0)
		{
		    return 0;
		}
		else
		{
		    uprintf("Enter a valid time string as MM/DD/YY HH:MM:SS"); prn_nl(); prn_nl(); prn_nl(); 
		}
	}

}


/*
 * u_printf()
 * Prints text to console with floating point support.
 * 255 characters maximum.
 * Returns number of characters written if less than 255 (lookup vsnprintf())
 */
int uprintf(const char *format, ...)
{
   va_list args;
   int chars_written;
   static char buff[256];
   char tempCh[2];
   unsigned int indx;

   va_start (args, format);
   chars_written = vsnprintf(buff, 256, format, args);
   va_end (args);

   if(sys_data.app_cfg[APPCFG_SER_LINETERM_MODE] == 0)  //cr-lf 0x0d 0x0a "/r/n"
   {
       //mode=0: end of line is cr-lf aka 0x0d 0x0a
       if(chars_written > 2)   // make sure the string is large enough
       {

           //Case A: "This is the story\r" -> "this is the story\r\n"
           tempCh[0] = buff[chars_written-2];
           tempCh[1] = buff[chars_written-1];

           //CASE 0  string is not terminated with cr or cr-lf, no action needed.
           //CASE 1  string is terminated with cr-lf, no action needed
           //CASE 2  string is terminated with cr, add lf
           if(tempCh[1] == 0x0d)
           {
               if(chars_written < 255)
               {
                   buff[chars_written] = 0x0a;  //add linefeed
                   chars_written++;
                   //buff[chars_written] = 0x00;  // make sure null terminate, EXCEPT it might overflow, UARTwrite does not need null terminate
               }
               else
               {
                   //ERROR, how to handle?  Perhaps insert ERR in printed String.  THOM TODO

               }
           }

           //Case B,  "/rThis is the story"  -> "/r/nThis is the story"
           tempCh[0] = buff[0];  //cr  /r  0x0d
           tempCh[1] = buff[1];  // not 0x0a
           //CASE 0  string is not terminated with cr or cr-lf, no action needed.
           //CASE 1  string is terminated with cr-lf, no action needed
           //CASE 2  string is terminated with cr, add lf
           if((tempCh[0] == 0x0d) && (tempCh[1] != 0x0a))
           {
               //copy the rest of the string onto the lf
               // tempCh[0] is the first character in the string (see above)
               if(chars_written < 254)
               {
                   indx = chars_written-1;
                   //buff[chars_written+1] = 0x00;   //null terminate (not needed due to UARTwrite
                   while(indx>0)
                   {
                       buff[indx+1] = buff[indx];
                       indx--;
                   }
                   buff[1] = 0x0a;
                   chars_written++;
               }
           }

       }

   }
   if(sys_data.app_cfg[APPCFG_SER_LINETERM_MODE] == 1)
   {
       //mode=0: end of line is cr-lf aka 0x0d 0x0a
       //mode=1: end of line is cr aka 0x0a (was 0x0d)
       if(chars_written > 2)   // make sure the string is large enough
       {

           // Case A: "This is the story\r\n" -> "This is the story\r"
           tempCh[0] = buff[chars_written-2];
           tempCh[1] = buff[chars_written-1];

           //CASE 0  string is not terminated with cr or cr-lf, no action needed.
           //CASE 1  string is terminated with cr-lf, change string to cr terminated (remove lf)
           //CASE 2  string is terminated with cr, no action needed
           if(tempCh[1] == 0x0a)
           {
               buff[chars_written-1] = 0x00;
               chars_written--;
           }

           //Case B,  "/r/nThis is the story"  -> "/rThis is the story"
           tempCh[0] = buff[0];  //cr  /r  0x0d
           tempCh[1] = buff[1];  //lf  /n  0x0a
           //CASE 0  string is not prepended with cr or cr-lf, no action needed.
           //CASE 1  string is prepended with cr-lf, copy string buff[x] = buff[x+1]
           //CASE 2  string is prepended with cr, no action
           if((tempCh[0] == 0x0d) && (tempCh[1] == 0x0a))
           {
               //copy the rest of the string onto the lf
               // tempCh[0] is the first character in the string (see above)
               if(chars_written < 254)
               {
                   indx = 1;
                   while(indx < chars_written)
                   {
                       buff[indx] = buff[indx+1];
                       indx++;
                   }
                   chars_written--;
                   buff[chars_written] = 0x00;  // Not needed as null is copied in loop above, but why not be sure
               }
           }

       }
   }

   //UARTwrite(buff, strlen(buff));
   UARTwrite(buff, chars_written);   // Thom 21 Aug 2024, remove strlen need in case of edge condition (254 byte string with cr term, mode=0)

   //uprintf("%s", buff);

   return chars_written;
}



/*
 * u_printf()
 * Prints text to console with floating point support.
 * 255 characters maximum.
 * Returns number of characters written if less than 255 (lookup vsnprintf())
 */
int dbg_printf(const char *format, ...)
{
   va_list args;
   int chars_written;
   static char buff[256];

   if(dbg_flag == 0)
       return 0;

   va_start (args, format);
   chars_written = vsnprintf(buff, 256, format, args);
   va_end (args);

   UARTwrite(buff, strlen(buff));

   return chars_written;
}

/*
 * kbhit()
 * Returns true if user hits a key
 */
bool kbhit(void)
{
	if( UARTRxBytesAvail() )
	{
		UARTFlushRx();      // THOM, why flush???  This gets rid of the key
		return true;
	}
	else return false;
}

/*
 * get_key()
 * Gets a keystroke from the console.
 * Waits for carriage return before returning with key hit.
 * Allows user to edit key hit.
 * RCG 5/14
 */
char get_key(void)
{
	char buff[8];

	while(1)
	{
	    wdog_pet();
		// Loop till user hits <CR>
	    // ISR is processing input and with UARTEchoSet(true), backspace is handled in ISR
		if(UARTPeek('\r') >= 0)
		{
			UARTgets(buff, 5);
			break;
		}

	}

	return buff[0];	// Return the key hit
}

// get key with timeout
#ifdef NOCODE
{
    int charCount;
    uint32_t startTicks;
    uint32_t elapsedTicks;

    //Loop until they give a valid response or time is up
    startTicks = read_hib_rtcc();
    while(1)
    {
        //if user enters a CR, store and check the string, data is in ISR rx buffer, UARTgets is called if latest buffer entry is <CR>
        if(UARTPeek('\r') >= 0)
        {
            //store user input in inputBuffer.  charCount stores # of chars sent
            charCount = UARTgets(userInputBuffer, userInputBufferSize);
            return charCount;
        }

        //else, update seconds passed, if timeLimit seconds pass, return -1
        else
        {
            elapsedTicks = read_hib_rtcc() - startTicks;
            if( (elapsedTicks > timeLimit))
            {
                return TIMELIMITPASSED;
            }
        }
    }

}
#endif


//int get_command_m2m(uint32_t timeout)
uint8_t get_key_m2m(void)
{
    uint8_t     rxBuf[8];
    uint8_t     retVal;

    // old get_key returns first character, even when a string of characters are entered, after a <CR>   Backspace is handled
    // new get_key_m2m handles ascii same as old get_key

#ifdef NOCODE
    int startTicks = read_hib_rtcc();
#endif
    //uprintf(" get_key_m2m ");       //DBG
    while(1)
    {
        // Loop till user hits <CR>
        if(UARTPeek('\r') >= 0)     // 0x0d
        {
            //uprintf(" get_key_m2m PEEK ");       //DBG
            UARTgets((char*)rxBuf, 5);
            return rxBuf[0]; // Return the key hit
            //break;
        }

#define M2M_CHAR        0xAA
//#define M2M_CHAR        0x55        //  0xAA for machine, 0x55 for typing
        if(UARTPeek(M2M_CHAR) >= 0)
        {
            UARTEchoSet(false);     // Turn off echo, this also disables ISR processing of backspace char

            while(1)
            {
                //uprintf("\r\nhandle m2m comm\r\n");
                //wait_consoleTx();

                // return 0 if nothing, 1 if finished with command, rxByte
                retVal = handle_m2m_comm();      // defd in serial.c, returns 1 if done with m2m command

                if(retVal == 1)
                {
                    UARTEchoSet(true);
                    return(retVal);
                }

#ifdef NOCODE
                elapsedTicks = read_hib_rtcc() - startTicks;
                if( (elapsedTicks > timeLimit))
                {
                    return TIMELIMITPASSED;
                }
#endif

            }
#ifdef WARNING_ABATEMENT_UNREACHABLE
            break;
#endif
        }

    }

#ifdef WARNING_ABATEMENT_UNREACHABLE
    return rxBuf[0]; // Return the key hit
#endif
}



/******************************************************************
 *  getchar_timed()
 *
 *  Get a character from the console. Return -1 if no character
 *  after timeout value in seconds.
 *****************************************************************/
int getchar_timed(int timeout)
{
    const unsigned long t0 = Timer_10ms();   // Reset timer to zero
    timeout*= 100;      // Convert to 10 ms counts

    while( ! is_timer_10ms_expired(t0, timeout) )
    {
        if( UARTRxBytesAvail() )
        {
            return UARTgetc();
        }
    }

    return -1;  // Timeout
}




/******************************************************************
 *  getChar()
 *
 *  assumes UARTRxBytesAvail() was called and a char is ready to be read
 *  blocks waiting for char if non available in rx buf
 *****************************************************************/
int getChar(void)
{
    return UARTgetc();
}


/*
 * if a char is available, return it.
 */
char rx_console_byte(void)
{
    char buff[5];

    while(1)
    {
        // Loop till user hits <CR>
        if(UARTPeek('\r') >= 0)
        {
            UARTgets(buff, 5);
            break;
        }
    }

    return buff[0]; // Return the key hit
}
