/************************************************************************/
/* Copyright 2015-2016 MBARI                                            */
/************************************************************************/
/* Summary  : Oasis5 Debug menu routine                                 */
/* Filename : o5debug.c                                                 */
/* Author   : Robert Herlien (rah)                                      */
/* Project  : Oasis5                                                    */
/* Revision: 1.0                                                        */
/* Created  : 02/11/2016 from mvdebug.c (FOCE)                          */
/*                                                                          */
/* MBARI provides this documentation and code "as is", with no warranty,    */
/* express or implied, of its quality or consistency. It is provided without*/
/* support and without obligation on the part of the Monterey Bay Aquarium  */
/* Research Institute to assist in its use, correction, modification, or    */
/* enhancement. This information should not be published or distributed to  */
/* third parties without specific written permission from MBARI.            */
/*                                                                          */
/************************************************************************/
/* Modification History:                                                */
/* 11feb2016 rah - created from mvdebug.c FOCE project                  */
/************************************************************************/

#include "o5debug.h"
#include "serial.h"
#include "dig_io.h"
#include "adc.h"
#include "rtc.h"
#include "sys_timer.h"

#include <GenericTypeDefs.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>


typedef struct                  /****************************************/
{                               /* Struct to hold commands              */
    char  *name;                /* Command name                         */
    int   (*func)();            /* Function to execute                  */
    int   nparms;               /* Number of parms (0 or 1 only for now)*/
    UINT  parmMin;              /* Max value of parm (0 to parmMax)     */
    UINT  parmMax;              /* Max value of parm (0 to parmMax)     */
} CommandStruct;                /****************************************/

typedef struct                  /****************************************/
{                               /* Analog channel descriptors           */
    char  *name;                /* Channel name                         */
    char  *units;               /* Name of engineering units            */
    double mult;                /* Multiplier                           */
    double offset;              /* Offset                               */
} AnalogDesc;                   /****************************************/


/********************************/
/*      Forward Declarations    */
/********************************/

int     printDebugMenu(int port);
CommandStruct *getCommand(int port, UINT *parmp);
int     getline(int port, char *buf, int buflen);
int     pwrRelayOn(int port, UINT relay);
int     pwrRelayOff(int port, UINT relay);
int     enableSerial(int port, UINT serPort);
int     disableSerial(int port, UINT serPort);
int     writeSerial(int port, UINT serPort);
int     writeTestSerial(int port, UINT serPort);
int     readSerial(int port, UINT serPort);
int     loopbackSerial(int port, UINT serPort);
void    printAnalogChan(int port, UINT chan, UINT16 cnt);
int     analogRead(int port, UINT analogPort);
int     analogAllRead(int port);
int     analogParms(int port);
int     analogNumAvg(int port, UINT numAvg);
int     analogAvgMs(int port, UINT avgMs);
int     analogStartup(int port, UINT startupCentisec);
int     pwrStatus(int port);
int     exitProg(void);
int     testCmd(int port, UINT parm);
int     envPwr(int port, UINT parm);
int     gfLowCmd(int port);
int     gfHighCmd(int port);
int     gfOffCmd(int port);
int     readRTC(int port);
int     setTime(int port);
int     readRTCReg(int port, UINT reg);
int     writeRTCReg(int port, UINT reg);
int     checkUsTmr(int port, UINT parm);
int     checkMsTmr(int port, UINT parm);


/********************************/
/*      Module Local Data       */
/********************************/

static char     inputBuf[256];
static char     msgBuf[256];

static int      dbgSerPort = SER_CONSOLE;
static int      debugLevel = 0;
static UINT     adcNumAvg = 1;
static UINT     adcAvgMs = 10;
static UINT     adcStartupMs = 10;

static CommandStruct cmdTbl[] = {
    {"on", pwrRelayOn, 1, 1, 4},
    {"off", pwrRelayOff, 1, 1, 4},
    {"en", enableSerial, 1, 1, 4},
    {"dis", disableSerial, 1, 1, 4},
    {"wr", writeSerial, 1, 1, 4},
    {"wt", writeTestSerial, 1, 1, 4},
    {"rd", readSerial, 1, 1, 4},
    {"lb", loopbackSerial, 1, 1, 4},
    {"aa", analogAllRead, 0, 0, 0},
    {"ar", analogRead, 1, ADC_CHAN_MIN, ADC_CHAN_MAX},
    {"an", analogNumAvg, 1, 1, 99},
    {"am", analogAvgMs, 1, 1, 99},
    {"as", analogStartup, 1, 1, 99},
    {"ap", analogParms, 0, 0, 0},
    {"gfl", gfLowCmd, 0, 0, 0}, 
    {"gfh", gfHighCmd, 0, 0, 0}, 
    {"gfoff", gfOffCmd, 0, 0, 0}, 
    {"p", pwrStatus, 0, 0, 0}, 
    {"ep", envPwr, 1, 0, 1}, 
    {"rr", readRTCReg, 1, 0, 19}, 
    {"rw", writeRTCReg, 1, 0, 19}, 
    {"rtc", readRTC, 0, 0, 0}, 
    {"time", setTime, 0, 0, 0}, 
    {"us", checkUsTmr, 1, 1, 99}, 
    {"ms", checkMsTmr, 1, 1, 99}, 
    {"h", printDebugMenu, 0, 0, 0},
    {"?", printDebugMenu, 0, 0, 0},
    {"x", exitProg, 0, 0, 0},
    {"q", exitProg, 0, 0, 0},
    {"test", testCmd, 1, 1, 250}
};


static AnalogDesc analogDesc[] = {
    {"PRESSURE",   "psiA",    14.5038, -0.2901},
    {"BATT_VOLTS", "Volts",   8.00, 0.0},
    {"GF_VOLTS",   "Volts",   1.00, 0.0},
    {"TEMP",       "deg C",   160., -67.84},
    {"HUMIDITY",   "%rh",     31.4465, -23.8208}
};


/************************************************************************/
/* Function    : debugMenu                                              */
/* Purpose     : Debug menu main entry point                            */
/* Inputs      : Serial port to use                                     */
/* Outputs     : None                                                   */
/************************************************************************/
void debugMenu(int port)
{
    UINT                cmdParm;
    CommandStruct       *cmdp;

    dbgSerPort = port;
    printDebugMenu(port);

    while (TRUE)
    {
        cmdParm = 0;
        if ((cmdp = getCommand(port, &cmdParm)) != NULL)
        {
            serPutString(port, "\r\n");
            if ((*cmdp->func)(port, cmdParm) == EXIT)
            {
                serPutString(port, "\r\nReturning to main echo loop\r\n");
                return;
            }
        }
    }

} /* debugMenu() */


/************************************************************************/
/* Function    : printDebugMenu                                         */
/* Purpose     : Print the menu                                         */
/* Inputs      : Serial port                                            */
/* Outputs     : None                                                   */
/************************************************************************/
int printDebugMenu(int port)
{
    serPutString(port, "\r\nDEBUG MENU - Type a command:\r\n\n");
    serPutString(port, "h for this help message\r\n");
    serPutString(port, "x to go back to main program\r\n\n");

    serPutString(port, "on[1-4] to turn on a power/serial relay\r\n");
    serPutString(port, "off[1-4] to turn off a power/serial relay\r\n");
    serPutString(port, "p to read power vector\r\n");
    serPutString(port, "en[1-4] to enable serial driver\r\n");
    serPutString(port, "dis[1-4] to disable serial driver\r\n");
    serPutString(port, "wr[1-4] to write to a serial port\r\n");
    serPutString(port, "wt[1-4] to write test strings to a serial port\r\n");
    serPutString(port, "rd[1-4] to read from a serial port\r\n");
    serPutString(port, "lb[1-4] to loopback test a serial port\r\n");

    serPutString(port, "ar[6-10] to read an analog port\r\n");
    serPutString(port, "aa to read all analog ports\r\n");
    serPutString(port, "ap to read analog parameters\r\n");
    serPutString(port, "an[1-99] to set analog numAvg (number samples to average)\r\n");
    serPutString(port, "am[1-99] to set analog avgMs (ms between samples)\r\n");
    serPutString(port, "as[1-99] to set analog startup time (.01 sec)\r\n");
    serPutString(port, "gfl to set GF_LOW bit\r\n");
    serPutString(port, "gfh to set GF_HIGH bit\r\n");
    serPutString(port, "gfoff to clear GF_xxx bits\r\n");
    serPutString(port, "ep[0-1] to turn off/on Env power\r\n");

    serPutString(port, "rtc to read RTC registers\r\n");
    serPutString(port, "time to set time/date into RTC\r\n");
    serPutString(port, "rr to read one RTC register\r\n");
    serPutString(port, "rw to write one RTC register\r\n");
#if 0
    serPutString(port, "d[0-9] to set debug output level\r\n");
#endif

    return(OK);

} /* printDebugMenu() */


/********************************************************/
/*  Support routines for getCommand()                   */
/********************************************************/
static int getDec(char *s, UINT *num)
{
    UINT  val;
    int   rtn;

    rtn = val = 0;

    while (isdigit(*s))
    {
        val *= 10;
        val += (*s - '0');
        rtn = 1;
        s++;
    }

    if (rtn)
        *num = val;
    return(rtn);
}

/* findCommand()    */
static CommandStruct  *findCommand(UINT *parmp)
{
    int         i, nameSize, rtn;
    UINT        parm;
    CommandStruct *csp;

    for (i = 0, csp = cmdTbl; i < NumberOf(cmdTbl); i++, csp++)
    {
        nameSize = strlen(csp->name);

        if (strncasecmp(inputBuf, csp->name, nameSize) == 0)
        {
            if (csp->nparms == 0)
                return(csp);

            if (((rtn = getDec(&inputBuf[nameSize], &parm)) >= 1) && (parmp != NULL))
                *parmp = parm;
            
            return(csp);
        }
    }
    return(NULL);
}

/* checkParm()      */
static CommandStruct  *checkParm(int port, CommandStruct *csp, UINT *parmp)
{
    if (csp->nparms == 0)
        return(csp);
    if (parmp == NULL)
        return(NULL);
    if ((*parmp >= csp->parmMin) && (*parmp <= csp->parmMax))
        return(csp);

    sprintf(msgBuf, "\r\nBad parameter: %u\r\n", *parmp);
    serPutString(port, msgBuf);
    return(NULL);
}

/* decDigits()      */
static UINT decDigits(UINT n)
{
    UINT digits=1;

    while (n >= 10)
    {
        digits++;
        n /= 10;
    }

    return(digits);
}


/************************************************************************/
/* Function    : getCommand                                             */
/* Purpose     : Get a command                                          */
/* Inputs      : Serial port, ptr to place to put parm                  */
/* Outputs     : Ptr to command to execute                              */
/************************************************************************/
CommandStruct  *getCommand(int port, UINT *parmp)
{
    int         nchars, nameSize, digits;
    char        *p;
    CommandStruct *csp;

    serPutString(port, "\r\nEnter a command:  ");
    memset(inputBuf, 0, sizeof(inputBuf));
    nchars = 0;
    p = inputBuf;

    while( nchars < sizeof(inputBuf) - 1 )
        if (serGetByte(port, (unsigned char *)p))
        {
            serPutByte(port, *p);

            if ((*p == '\n') || (*p == '\r'))
            {
                *p = '\0';
                if ((csp = findCommand(parmp)) == NULL)
                    return(NULL);
                return(checkParm(port, csp, parmp));
            }

            nchars++;
            p++;
            *p = '\0';

            if ((csp = findCommand(parmp)) != NULL)
            {
                if (csp->nparms == 0)
                    return(csp);

                nameSize = strlen(csp->name);
                digits = decDigits(csp->parmMax);

                if (nchars >= nameSize + digits)
                    return(checkParm(port, csp, parmp));
                
                if ((csp->parmMax < 20) && (nchars >= nameSize+1) && (*parmp >= 2))
                    return(checkParm(port, csp, parmp));
            }
        }

    return(NULL);
}

/********************************************************/
/* Debug get/set/print routines for general use         */
/********************************************************/

/************************************************************************/
/* Function    : dbgPrint                                               */
/* Purpose     : Print formatted output to default serial port          */
/* Inputs      : Format string, parameters                              */
/* Outputs     : Return value from snprintf                             */
/************************************************************************/
int     dbgPrint(const char *format, ...)
{
  va_list       ap;
  int           rtn;

  if (debugLevel <= 0)
      return(0);

  va_start(ap, format);
  rtn = vsnprintf(msgBuf, sizeof(msgBuf), format, ap);
  serPutString(dbgSerPort, msgBuf);
  va_end(ap);
  return(rtn);

} /* dbgPrint() */


/****************************************/
/* Helper functions                     */
/****************************************/

/************************************************************************/
/* Function    : getline                                                */
/* Purpose     : Get one line of user input                             */
/* Inputs      : Serial port number, buffer pointer, buf length         */
/* Outputs     : Length of returned line                                */
/************************************************************************/
int getline(int port, char *buf, int buflen)
{
    int         len;
    BYTE        b;

    for (len = 0; len < buflen-1; )
    {
        if (serGetByte(port, &b))
        {
            serPutByte(port, b);
            buf[len++] = b;

            if (b == '\r')
            {
                serPutByte(0, (BYTE)'\n');
                buf[len] = '\0';
                return(len);
            }
        }
    }

    buf[buflen] = '\0';
    return(buflen);
}


/********************************************************/
/* Functions to implement menu commands                 */
/********************************************************/

/************************************************************************/
/* Function    : exitProg                                               */
/* Purpose     : Command function to exit the program                   */
/* Inputs      : None used                                              */
/* Outputs     : EXIT return code                                       */
/************************************************************************/
int exitProg(void)
{
    return(EXIT);
}

/************************************************************************/
/* Function    : pwrRelayOn                                             */
/* Purpose     : Command function to turn on a FOCE power relay         */
/* Inputs      : Serial port, Relay Number                              */
/* Outputs     : Return code                                            */
/************************************************************************/
int pwrRelayOn(int port, UINT relay)
{
    sprintf(msgBuf, "Turning on relay %u\r\n", relay);
    serPutString(port, msgBuf);
    digPwrOn(relay);
    return(OK);
}


/************************************************************************/
/* Function    : pwrRelayOff                                            */
/* Purpose     : Command function to turn off a FOCE power relay        */
/* Inputs      : Serial port, Relay Number                              */
/* Outputs     : Return code                                            */
/************************************************************************/
int pwrRelayOff(int port, UINT relay)
{
    sprintf(msgBuf, "Turning off relay %u\r\n", relay);
    serPutString(port, msgBuf);
    digPwrOff(relay);
    return(OK);
}


/************************************************************************/
/* Function    : enableSerial                                           */
/* Purpose     : Command function to enable a serial port               */
/* Inputs      : User serial port, serial port to enable                */
/* Outputs     : Return code                                            */
/************************************************************************/
int enableSerial(int port, UINT serPort)
{
    sprintf(msgBuf, "Enabling serial port %u\r\n", serPort);
    serPutString(port, msgBuf);
    digSerEnable(serPort);
    return(OK);
}


/************************************************************************/
/* Function    : disableSerial                                          */
/* Purpose     : Command function to disable a serial port              */
/* Inputs      : User serial port, serial port to disable               */
/* Outputs     : Return code                                            */
/************************************************************************/
int disableSerial(int port, UINT serPort)
{
    sprintf(msgBuf, "Disabling serial port %u\r\n", serPort);
    serPutString(port, msgBuf);
    digSerDisable(serPort);
    return(OK);
}


/************************************************************************/
/* Function    : writeSerial                                            */
/* Purpose     : Command function to write to a serial port             */
/* Inputs      : User serial port, serial port to write to              */
/* Outputs     : Return code                                            */
/************************************************************************/
int     writeSerial(int port, UINT serPort)
{
    unsigned char       b;

    sprintf(msgBuf, "Writing to serial port %d\r\n^D to exit\r\n", serPort);
    serPutString(port, msgBuf);

    while(TRUE)
    {
        if (serGetByte(port, &b))
        {
            if (b == 0x4)
                return(OK);
            while (!serPutByte(serPort, b))
                ;
        }
    }

    return(OK);
}


/************************************************************************/
/* Function    : writeTestSerial                                        */
/* Purpose     : Command function to write test strings to a serial port*/
/* Inputs      : User serial port, serial port to write to              */
/* Outputs     : Return code                                            */
/************************************************************************/
int     writeTestSerial(int port, UINT serPort)
{
    int         i;

    sprintf(msgBuf, "Writing 10 test messages to serial port %d\r\n", serPort);
    serPutString(port, msgBuf);

    for (i = 0; i < 10; i++)
    {
        sprintf(msgBuf, "This is test message %d for serial port %d\r\n",
                i, serPort);
        serPutString(serPort, msgBuf);
    }

    return(OK);
}


/************************************************************************/
/* Function    : readSerial                                             */
/* Purpose     : Command function to read from a serial port            */
/* Inputs      : User serial port, serial port to read from             */
/* Outputs     : Return code                                            */
/************************************************************************/
int     readSerial(int port, UINT serPort)
{
    unsigned char       b;

    sprintf(msgBuf, "Reading from serial port %d\r\nType ^D on port %d to exit\r\n",
            serPort, serPort);
    serPutString(port, msgBuf);

    while(TRUE)
    {
        if (serGetByte(serPort, &b))
        {
            if (b == 0x4)
                return(OK);
            while (!serPutByte(port, b))
                ;
        }
    }

    return(OK);
}


/************************************************************************/
/* Function    : loopbackSerial                                         */
/* Purpose     : Command function to perform loopback test on serial port*/
/* Inputs      : User serial port, serial port to read from             */
/* Outputs     : Return code                                            */
/************************************************************************/
int     loopbackSerial(int port, UINT serPort)
{
    unsigned char       b;

    sprintf(msgBuf, "Loopback test for serial port %d\r\nType ^D on port %d to exit\r\n",
            serPort, serPort);
    serPutString(port, msgBuf);

    while(TRUE)
    {
        if (serGetByte(serPort, &b))
        {
            if (b == 0x4)
                return(OK);
            while (!serPutByte(serPort, b))
                ;
        }
    }

    return(OK);
}


/************************************************************************/
/* Function    : printAnalogChan                                        */
/* Purpose     : Print one analog channel                               */
/* Inputs      : Serial port, analog channel number, A/D counts         */
/* Outputs     : None                                                   */
/************************************************************************/
void    printAnalogChan(int port, UINT chan, UINT16 cnt)
{
    AnalogDesc  *adp = &analogDesc[chan-ADC_CHAN_MIN];
    double      volt = ((double)cnt * 3.3 / 1024.0);

    sprintf(msgBuf, "Ch %2d  %-12s %5u cnts %6.3f ADC volts %6.3f %s\r\n",
            chan, adp->name, cnt, volt,
            volt * adp->mult + adp->offset, adp->units);

    serPutString(port, msgBuf);
}


/************************************************************************/
/* Function    : analogRead                                             */
/* Purpose     : Command function to read analog channel                */
/* Inputs      : Serial port, analog channel number                     */
/* Outputs     : Return code                                            */
/************************************************************************/
int     analogRead(int port, UINT chan)
{
    UINT16      i;
    UINT32      accum;

    adcSetupSingle(chan);
    tmrDelayMs(adcStartupMs);
    accum = 0;

    for (i = 0; i < adcNumAvg; i++)
    {
        accum += adcConvertSingle();
        tmrDelayMs(adcAvgMs);
    }

    adcStop();

    printAnalogChan(port, chan, (UINT16)(((accum + (adcNumAvg/2))/adcNumAvg) & 0x3ff));

    return(OK);
}

/************************************************************************/
/* Function    : analogAllRead                                          */
/* Purpose     : Command function to read all 5 analog channels         */
/* Inputs      : Serial port                                            */
/* Outputs     : Return code                                            */
/************************************************************************/
int     analogAllRead(int port)
{
    UINT        i, j;
    UINT32      accum[ADC_CHANS];

    adcSetupMult(ADC_CHAN_MIN, ADC_CHANS);
    tmrDelayMs(adcStartupMs);
    memset(accum, 0, sizeof(accum));

    for (i = 0; i < adcNumAvg; i++)
    {
        adcConvertMult();
        for (j = 0; j < ADC_CHANS; j++)
            accum[j] += adcGetResult(j);
        tmrDelayMs(adcAvgMs);
    }

    adcStop();

    for (j = 0; j < ADC_CHANS; j++)
        printAnalogChan(port, j + ADC_CHAN_MIN, 
                        (UINT16)(((accum[j] + (adcNumAvg/2))/adcNumAvg) & 0x3ff));
    
    return(OK);
}


/************************************************************************/
/* Function    : analogNumAvg                                           */
/* Purpose     : Command function to set numAvg                         */
/* Inputs      : MVConvHandle, parm                                     */
/* Outputs     : OK                                                     */
/************************************************************************/
int     analogNumAvg(int port, UINT numAvg)
{
    adcNumAvg = numAvg;
    sprintf(msgBuf, "Set numAvg to %u\r\n", numAvg);
    serPutString(port, msgBuf);

    return(OK);
}

/************************************************************************/
/* Function    : analogAvgMs                                            */
/* Purpose     : Command function to set avgMs                          */
/* Inputs      : MVConvHandle, parm                                     */
/* Outputs     : OK                                                     */
/************************************************************************/
int     analogAvgMs(int port, UINT avgMs)
{
    adcAvgMs = avgMs;
    sprintf(msgBuf, "Set avgMs to %u\r\n", avgMs);
    serPutString(port, msgBuf);

    return(OK);
}

/************************************************************************/
/* Function    : analogStartup                                          */
/* Purpose     : Command function to set ADC startup time, in .01s      */
/* Inputs      : MVConvHandle, parm                                     */
/* Outputs     : OK                                                     */
/************************************************************************/
int  analogStartup(int port, UINT startupCentisec)
{
    adcStartupMs = 10 * startupCentisec;
    sprintf(msgBuf, "Set ADC startup time to %u ms\r\n", adcStartupMs);
    serPutString(port, msgBuf);

    return(OK);
}

/************************************************************************/
/* Function    : analogParms                                            */
/* Purpose     : Command function to print analog parms                 */
/* Inputs      : Serial port                                            */
/* Outputs     : Return code                                            */
/************************************************************************/
int     analogParms(int port)
{
    sprintf(msgBuf, "numAvg = %u, avgMs = %u, startupMs = %u\r\n",
            adcNumAvg, adcAvgMs, adcStartupMs);
    serPutString(port, msgBuf);

    return(OK);
}

/************************************************************************/
/* Function    : pwrStatus                                              */
/* Purpose     : Command function to get power status vector            */
/* Inputs      : Serial port                                            */
/* Outputs     : OK                                                     */
/************************************************************************/
int     pwrStatus(int port)
{
    sprintf(msgBuf, "Power Vector = 0x%x\r\n", digPwrGet());
    serPutString(port, msgBuf);

    return(OK);
}


/************************************************************************/
/* Function    : envPwr                                                 */
/* Purpose     : Command function to turn on/off env power              */
/* Inputs      : Serial port, parm                                      */
/* Outputs     : OK                                                     */
/************************************************************************/
int     envPwr(int port, UINT parm)
{
    if (parm)
        digEnvEnable();
    else
        digEnvDisable();

    sprintf(msgBuf, "Turning EnvEnable %s \r\n", parm ? "ON" : "OFF");
    serPutString(port, msgBuf);

    return(OK);
}

/************************************************************************/
/* Function    : gfLowCmd                                               */
/* Purpose     : Command function to set GF ckt to measure LOW side     */
/* Inputs      : Serial port                                            */
/* Outputs     : OK                                                     */
/************************************************************************/
int     gfLowCmd(int port)
{
    digGFLowOn();
    digGFHighOff();
    serPutString(port, "Setting GF circuit to measure LOW side\r\n");
    return(OK);
}

/************************************************************************/
/* Function    : gfHighCmd                                               */
/* Purpose     : Command function to set GF ckt to measure HIGH side    */
/* Inputs      : Serial port                                            */
/* Outputs     : OK                                                     */
/************************************************************************/
int     gfHighCmd(int port)
{
    digGFLowOff();
    digGFHighOn();
    serPutString(port, "Setting GF circuit to measure HIGH side\r\n");
    return(OK);
}

/************************************************************************/
/* Function    : gfOffCmd                                               */
/* Purpose     : Command function to turn off GF ckt                    */
/* Inputs      : Serial port                                            */
/* Outputs     : OK                                                     */
/************************************************************************/
int     gfOffCmd(int port)
{
    digGFLowOff();
    digGFHighOff();
    serPutString(port, "Turning off GF circuit\r\n");
    return(OK);
}


/************************************************************************/
/* Function    : toBCD                                                  */
/* Purpose     : Convert binary Byte to BCD                             */
/* Input       : Input byte                                             */
/* Outputs     : BCD Result                                             */
/* Comments    : Works for input range of 00-99                         */
/*               Multiples of 100 get stripped, e.g. 167 converts to 0x67*/
/************************************************************************/
static UINT16 toBCD(UINT16 inw)
{
    return((((inw/10)%10) << 4) | (inw%10));
}

/************************************************************************/
/* Function    : fromBCD                                                */
/* Purpose     : Convert from BCD to binary                             */
/* Input       : BCD byte                                               */
/* Outputs     : Result                                                 */
/************************************************************************/
static UINT16 fromBCD(UINT16 bcd)
{
    return(10*((bcd >> 4) & 0xf) + (bcd & 0xf));
}

/************************************************************************/
/* Function    : readRTC                                                */
/* Purpose     : Command function to read RTC registers                 */
/* Inputs      : Serial port                                            */
/* Outputs     : OK                                                     */
/************************************************************************/
int     readRTC(int port)
{
    int         i, rtn;
    BYTE        regs[16];

    if ((rtn = rtcReadMultRegs(RTC_SEC, 16, regs)) != SUCCESS)
    {
        sprintf(msgBuf, "Error reading RTC regs, errno = %d\r\n", rtn);
        serPutString(port, msgBuf);
    }

    for (i = 0; i < 16; i++)
    {
        sprintf(msgBuf, "%02x ", (UINT)(regs[i] & 0xff));
        serPutString(port, msgBuf);
    }

    sprintf(msgBuf, "\r\n\n%02d:%02d:%02d  %04u/%02d/%02d\r\n",
            (int)fromBCD((UINT16)regs[RTC_HOUR]), 
            (int)fromBCD((UINT16)regs[RTC_MIN]), 
            (int)fromBCD((UINT16)regs[RTC_SEC]), 
            (int)fromBCD((UINT16)regs[RTC_YEAR]) + 2000, 
            (int)fromBCD((UINT16)(regs[RTC_MON] & 0x1f)),
            (int)fromBCD((UINT16)regs[RTC_MDAY]));

    serPutString(port, msgBuf);

    return(OK);
}

/************************************************************************/
/* Function    : setTime                                                */
/* Purpose     : Command function to set time/date into RTC             */
/* Inputs      : Serial port                                            */
/* Outputs     : OK                                                     */
/************************************************************************/
int     setTime(int port)
{
    UINT        n, rtn, year, mon, day, hr, min, sec;
    BYTE        regs[8];

    serPutString(port, "Enter new time/date as either:\r\n");
    serPutString(port, "\tyyyy/mm/dd hh:mm:ss    or\r\n");
    serPutString(port, "\thh:mm:ss    or\r\n");
    serPutString(port, "\thh:mm\r\n");

    if (getline(port, inputBuf, sizeof(inputBuf)) < 5)
        return(OK);

    n = sscanf(inputBuf, " %u/%u/%u %u:%u:%u", &year, &mon, &day, &hr, &min, &sec);
    if ((n == 5) || (n >= 6))
    {
        if (n == 5)
            sec = 0;
        else
            regs[0] = (BYTE)toBCD(sec % 60);
        regs[1] = (BYTE)toBCD(min % 60);
        regs[2] = (BYTE)toBCD(hr % 24);
        regs[3] = 1;
        regs[4] = (BYTE)toBCD(day % 31);
        regs[5] = (BYTE)toBCD(mon % 12);
        regs[6] = (BYTE)toBCD(year % 100);

        if ((rtn = rtcWriteMultRegs(RTC_SEC, 7, regs)) != SUCCESS)
        {
            sprintf(msgBuf, "Error writing 7 RTC regs, errno = %d\r\n", rtn);
            serPutString(port, msgBuf);
        }

        return(OK);
    }

    n = sscanf(inputBuf, " %u:%u:%u", &hr, &min, &sec);
    if ((n == 2) || (n >= 3))
    {
        if (n == 2)
            sec = 0;
        else
            regs[0] = (BYTE)toBCD(sec % 60);
        regs[1] = (BYTE)toBCD(min % 60);
        regs[2] = (BYTE)toBCD(hr % 24);

        if ((rtn = rtcWriteMultRegs(RTC_SEC, 3, regs)) != SUCCESS)
        {
            sprintf(msgBuf, "Error writing 3 RTC regs, errno = %d\r\n", rtn);
            serPutString(port, msgBuf);
        }

        return(OK);
    }

    return(OK);
}

/************************************************************************/
/* Function    : readRTCReg                                             */
/* Purpose     : Command function to read one RTC register              */
/* Inputs      : Serial port, reg number                                */
/* Outputs     : OK                                                     */
/************************************************************************/
int     readRTCReg(int port, UINT reg)
{
    BYTE        rdat;
    Errno       rtn;

    if ((rtn = rtcReadReg(reg, &rdat)) != SUCCESS)
        sprintf(msgBuf, "Error reading RTC Reg %u, errno %d\r\n",
                reg, rtn);
    else
        sprintf(msgBuf, "RTC register %u = 0x%x\r\n",
                reg, (UINT16)rdat);

    serPutString(port, msgBuf);
    
    return(OK);
}

/************************************************************************/
/* Function    : writeRTCReg                                            */
/* Purpose     : Command function to write one RTC register             */
/* Inputs      : Serial port, reg number                                */
/* Outputs     : OK                                                     */
/************************************************************************/
int     writeRTCReg(int port, UINT reg)
{
    BYTE        wdat;
    Errno       rtn;

    sprintf(msgBuf, "Enter value, in hex, to write to register %u:  ", reg);
    serPutString(port, msgBuf);

    if (getline(port, inputBuf, sizeof(inputBuf)) < 1)
        return(OK);

    wdat = strtoul(inputBuf, NULL, 16) & 0xff;

    sprintf(msgBuf, "Writing 0x%x to register %u\r\n", wdat, reg);
    serPutString(port, msgBuf);

    rtn = rtcWriteReg(reg, wdat);

    sprintf(msgBuf, "Return code was %d\r\n", rtn);
    serPutString(port, msgBuf);

    return(OK);
}

/************************************************************************/
/* Function    : testCmd                                                */
/* Purpose     : Command function to test parser                        */
/* Inputs      : Serial port, parm                                      */
/* Outputs     : OK                                                     */
/************************************************************************/
int     testCmd(int port, UINT parm)
{
    sprintf(msgBuf, "Test Command, parm = %u, digits = %u\r\n", parm, decDigits(parm));
    serPutString(port, msgBuf);
    return(OK);
}

/************************************************************************/
/* Function    : checkUsTmr                                             */
/* Purpose     : Command function show timing of microsecond timer      */
/* Inputs      : Serial port, usecs to delay                            */
/* Outputs     : OK                                                     */
/************************************************************************/
int     checkUsTmr(int port, UINT parm)
{
    while(serRxAvail(port) == 0)
    {
        LATGINV = 0x8000;
        tmrDelayUs(parm);
    }
}

/************************************************************************/
/* Function    : checkMsTmr                                             */
/* Purpose     : Command function show timing of millisecond timer      */
/* Inputs      : Serial port, msecs to delay                            */
/* Outputs     : OK                                                     */
/************************************************************************/
int     checkMsTmr(int port, UINT parm)
{
    while(serRxAvail(port) == 0)
    {
        LATGINV = 0x8000;
        tmrDelayMs(parm);
    }
}

