/****************************************************************************/
/* Copyright 1991, 1992 MBARI                                               */
/****************************************************************************/
/* Summary  : SIO32 Serial Controller microcontroller board support library */
/* Filename : sysLib.c                                                      */
/* Author   : Andrew Pearce                                                 */
/* Project  : ROV 1.5 SIO32 Serial Controller Rev 1.0                       */
/* Version  : 1.0                                                           */
/* Created  : 10/01/91                                                      */
/* Modified : 08/14/92                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* 08/14/92 - Reversed relay control bit ordering for Breakout Board        */
/*            Hardware Rev 2.0                                              */
/****************************************************************************/

#pragma model(196)
#pragma nosignedchar

#include "C:/C96/INCLUDE/80C196.h"  /* 80196 Register mapping               */
#include "C:/C96/INCLUDE/STDDEF.h"  /* Standard Definitions                 */
#include "const.h"                  /* Misc. constants - TRUE/FALSE etc     */
#include "types.h"                  /* MBARI style guide declarations       */
#include "microdef.h"               /* Microcontroller Definitions          */
#include "microlib.h"               /* Microcontroller library decls        */
#include "applay.h"                 /* Application layer functions          */
#include "microCmd.h"               /* microcontroller commands             */
#include "./syslib.h"               /* Hardware specific declarations       */

Extern Word  ledState;              /* Front Panel LED Status               */
Nat16  gfEnableState;               /* Ground Fault Enable Status           */
MLocal DWord relayCtrlState;        /* Relay status Word                    */

/****************************************************************************/
/* Function    : initIoport1                                                */
/* Purpose     : Initialize ioport1 on 196 microcontroller to power up state*/
/* Inputs      : None                                                       */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
initIoport1( Void )
{
                                        /* SPARE P1.0  = 1, SPARE P1.1  = 1 */
                                        /* SPARE P1.2  = 1, GF_ENABLE\  = 1 */
                                        /* LED CTRL\   = 1, GNDFLT TEST = 0 */
                                        /* SPARE P1.6  = 0, RELAY ENAB\ = 1 */

    writeIoport1(0x9f, SET_PORT);       /* Write value to port 1 and update */
                                        /* the software's internal copy     */
    ledState = OFF;                     /* LED is now off so update state   */
    gfEnableState = OFF;                /* GF Monitoring is enabled         */
} /* initIoport1() */

/****************************************************************************/
/* Function    : initIoport2                                                */
/* Purpose     : Initialize ioport2 on 196 microcontroller to power up state*/
/* Inputs      : None                                                       */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
initIoport2( Void )
{
                                        /* TXD    P2.0 = 1, RXD   P2.1  = 1 */
                                        /* EXTINT P2.2 = 1, T2CLK P2.3  = 1 */
                                        /* T2RST  P2.4 = 1, RLY STROBE  = 0 */
                                        /* RELAY DATA  = 0, RELAY CLOCK = 0 */
     writeIoport2(0x1f, SET_PORT);      /* Write value to port 2 and update */
                                        /* the software's internal copy     */

    ioc1 = IOC1_SELECT_TXD;             /* Select P2.5, EXTINT, TIMER 1 & 2 */
                                        /* Int Disable HSO.4 & 5 Disabled,  */
                                        /* TXD, HSI Hold Reg Loaded         */
} /* initIoport2() */

/****************************************************************************/
/* Function    : setBaudRate                                                */
/* Purpose     : Set built in serial port baud rate to specified value      */
/* Inputs      : Desired baud rate                                          */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
setBaudRate(Nat16 baudRate)
{
                                        /* Calculate Baud Rate              */
                                        /* Write Low Byte of Baud Rate      */
    baud_rate = (CLOCK_FREQ/baudRate/16 - 1) % 256;
                                        /* Write High Byte of Baud Rate     */
    baud_rate = ((CLOCK_FREQ/baudRate/16 - 1) / 256) | 0x80;
} /* setBaudRate() */

/****************************************************************************/
/* Function    : transmitControl                                            */
/* Purpose     : Enable/disable RS485 transmitter                           */
/* Inputs      : Desired state - ON/OFF                                     */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
transmitControl(Int16 mode)
{
#if 0                                   /* USES RS232 SO THIS IS NOT NEEDED */
    if (mode == OFF)                    /* Disable 485 transmitter          */
        writeIoport2(~RS485_CONTROL_BIT, AND_PORT);

    else if (mode == ON)                /* Enable 485 transmitter           */
        writeIoport2(RS485_CONTROL_BIT, OR_PORT);
#endif
} /* transmitControl() */

/****************************************************************************/
/* Function    : groundFaultTest                                            */
/* Purpose     : Enable/disable Ground fault test mode                      */
/* Inputs      : Desired state - ON/OFF                                     */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
groundFaultTest(Int16 status)
{
    if (status == ON )             /* Set bit 5 (GNDFLT_TEST) to a 1       */
        writeIoport1(GF_TEST_CONTROL_BIT, OR_PORT);

    else
        if (status == OFF)         /* Set bit 5 (GNDFLT_TEST) to a 0       */
            writeIoport1(~GF_TEST_CONTROL_BIT, AND_PORT);

} /* groundFaultTest */

/****************************************************************************/
/* Function    : readLocalGroundFault                                       */
/* Purpose     : Read local ground fault current                            */
/* Inputs      : None                                                       */
/* Outputs     : Returns ground fault current in microamps                  */
/****************************************************************************/
    Nat16
readLocalGroundFault( Void )
{
    Nat32   sum;
    Nat16   local_gf_current, i;

    for (i = 0, sum = 0; i < GF_AVG_READS; i++)
        sum += (Nat16) (readAnalogChannel(LOCAL_GND_FLT_CHANNEL) + 0x0200);

    local_gf_current = (Nat16) (sum / GF_AVG_READS);
    return( BITS_TO_MICROAMPS(local_gf_current) );
} /* readLocalGroundFault */

/****************************************************************************/
/* Function    : ledControl                                                 */
/* Purpose     : Set state of on board LED                                  */
/* Inputs      : None                                                       */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
ledControl(Int16 status)
{
    if (status == OFF)                  /* Set bit 4 (LED_CTRL\) to a 1     */
        setIoport1Bit(LED_CONTROL_BIT);

    else
        if (status == ON)               /* Set bit 4 (LED_CTRL\) to a 0     */
            clrIoport1Bit(LED_CONTROL_BIT);
} /* ledControl */

/****************************************************************************/
/* Function    : readTemperature                                            */
/* Purpose     : Read on board temperature sensor                           */
/* Inputs      : None                                                       */
/* Outputs     : Returns sensor tempreature in degrees C                    */
/****************************************************************************/
    Int16
readTemperature( Void )
{                               /* Assuming a 4.2K Resistor                 */
    Int16   raw_temp;           /* Raw temperature from sensor              */
    Int16   degrees;            /* Converted to degrees Centigrade          */
                                /* 1 count = 5.0v/1024 = 4.8828 mV          */
                                /* 1 count = 1.157 degrees C                */

                                /* Read raw value from sensor               */
    raw_temp = readAnalogChannel(TEMP_SENSOR_CHANNEL) + 512;

                                /* subtract offset and multiply by          */
                                /* 100 to improve dynamic range for         */
                                /* the conversion to degrees                */
    degrees = (Int16) ((( ((Int32) raw_temp) * 116) / 100) - 273);

    return(degrees);            /* Return temperature in degrees C          */
} /* readTemperature() */

/****************************************************************************/
/* Function    : initRelayControl                                           */
/* Purpose     : Initialize all serial isolation relays to closed           */
/* Inputs      : None                                                       */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
initRelayControl( Void )
{
    writeRelayControl(CLOSE_ALL_RELAYS);/* Close all RS485 Relays           */
} /* initRelayControl() */

/****************************************************************************/
/* Function    : relayOutputCtrl                                            */
/* Purpose     : Enable/disable relay control signal to GMS breakout board  */
/* Inputs      : Desired state - ON/OFF                                     */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
relayOutputCtrl(Word status)
{
    if (status == (Word) OFF)           /* Set bit 7 (RELAY_ENAB\) to a 1   */
        writeIoport1(0x80, OR_PORT);
    else
        if (status == (Word) ON)        /* Set bit 7 (RELAY_ENAB\) to a 0   */
            writeIoport1(0x7f, AND_PORT);

} /* relayOutputCtrl */

/****************************************************************************/
/* Function    : relayOutputCtrl                                            */
/* Purpose     : Writes a new 32 bit control word to the Spauge 5832 Relay  */
/*               control chip. The data is clocked out 1 bit at a time until*/
/*               all 32 bits have been sent, then the strobe line is pulsed */
/*               to latch the new value into the chip's output latch which  */
/*               turns on or off the relays.                                */
/* Inputs      : Relay control word. Bit = 0 for CLOSED, Bit = 1 for OPEN   */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
writeRelayControl(DWord relayCtrl)
{
    DWord   mask;

    relayCtrlState = relayCtrl;     /* Save present state for bit changing */
    relayCtrl = relayCtrl << 9;     /* Adjust 23 bit control word to 32 bit*/

    for (mask = 0x00000001; mask != 0x00000000; mask = mask << 1)
    {
        if ((relayCtrl & mask) != 0)
            writeIoport2(0x40, OR_PORT);        /* Data line = 1 P2.6       */
        else
            writeIoport2(0xbf, AND_PORT);       /* Data line = 0 P2.6       */

        writeIoport2(0x80, OR_PORT);            /* Clock line = 1 P2.7      */
        writeIoport2(0x7f, AND_PORT);           /* Clock line = 0 P2.7      */
    } /* for */

    writeIoport2(0x20, OR_PORT);                /* Strobe line = 1 P2.5     */
    writeIoport2(0xdf, AND_PORT);               /* Strobe line = 0 P2.5     */

    relayOutputCtrl(ON);                /* Enable Relay Driver Outputs      */

} /* writeRelayControl() */

/****************************************************************************/
/* Function    : extRelayControl                                            */
/* Purpose     : Open/close a relay on the GMS breakout board               */
/* Inputs      : Relay number (0 - MAX_RELAYS), desired state - OPEN/CLOSED */
/* Outputs     : Returns OK or ERROR                                        */
/****************************************************************************/
    Int16
extRelayControl(relay, mode)
    Word    relay;                  /* Relay number                         */
    Word    mode;                   /* Select OPEN or CLOSED                */
{
    DWord   relayMask;              /* Bit mask used to enable relay        */

                                    /* Check relay number is valid          */
    if ((relay < 0) || (relay > MAX_RELAYS))
        return(ERROR);              /* Relay number is invalid              */

    relayMask = 1;
    relayMask = relayMask << relay; /* Create relay control mask            */

    if (mode == OPEN)               /* Turn Relay On, ie Open               */
        writeRelayControl(relayMask | relayCtrlState);
    else                            /* Turn Relay Off, ie Closed            */
        writeRelayControl((~relayMask) & relayCtrlState);

    return(OK);
} /* extRelayControl() */

/****************************************************************************/
/* Function    : extRelayStatus                                             */
/* Purpose     : Return relay state bit vector                              */
/* Inputs      : None                                                       */
/* Outputs     : Returns Bit Vector Double Word                             */
/****************************************************************************/
    DWord
extRelayStatus( Void )
{
    return(relayCtrlState);
} /* extRelayStatus() */

/****************************************************************************/
/* Function    : checkGfcurrent                                             */
/* Purpose     : Check GF current against thresholds                        */
/* Inputs      : GF Current in micro amps                                   */
/* Outputs     : None, but sends SRQ packet to serial port                  */
/****************************************************************************/
    MLocal MBool
checkGFCurrent( Int16 gfCurrent, gfStatus *gfAlarmStatus )
{
    MBool status;
    gfStatus newGfStatus = GF_NORMAL;

    status = (*gfAlarmStatus == GF_CRITICAL ? TRUE : FALSE);
    if (thresholdTest(gfCurrent, GF_CRITICAL_LEVEL, GF_HYSTERESIS, &status)
            == TRUE)
        newGfStatus = GF_CRITICAL;
    else
    {
        status = (*gfAlarmStatus == GF_WARNING ? TRUE : FALSE);
        if (thresholdTest(gfCurrent, GF_WARNING_LEVEL, GF_HYSTERESIS, &status)
                == TRUE)
            newGfStatus = GF_WARNING;
        else
        {
            status = (*gfAlarmStatus == GF_ADVISORY ? TRUE : FALSE);
            if (thresholdTest( gfCurrent, GF_ADVISORY_LEVEL, GF_HYSTERESIS,
                    &status) == TRUE)
               newGfStatus = GF_ADVISORY;

        } /* else */
    } /* else */

    if (*gfAlarmStatus != newGfStatus)
    {
        *gfAlarmStatus = newGfStatus;
        return (TRUE);
    } /* if */

    return (FALSE);
} /* checkGfCurrent() */

/****************************************************************************/
/* Function    : checkGroundFaults                                          */
/* Purpose     : Checks local ground faults & send SRQ Packets              */
/* Inputs      : None                                                       */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
checkGroundFaults( gfStatus *localGfAlarmStatus )
{
    Int16 localGfCurrent;

    if (localGfAlarmStatus != (gfStatus *) NULL)
    {
        localGfCurrent = readLocalGroundFault();
        if (checkGFCurrent(localGfCurrent, localGfAlarmStatus) == TRUE)
            writeServiceRequest(2, LOCAL_GNDFLT_SRQ, *localGfAlarmStatus);
    } /* if */
} /* checkGroundFaults() */

/****************************************************************************/
/* Function    : testGroundFaults                                           */
/* Purpose     : Perform power up test of ground fault monitoring system    */
/* Inputs      : None                                                       */
/* Outputs     : None, but sends SRQ packet to serial port                  */
/****************************************************************************/
    gfTestStatus
testGroundFaults( Void )
{
    gfTestStatus gndFltTestStatus = GF_TEST_OK;

    groundFaultTest(ON);            /* Enable Ground Fault Test Mode        */
    taskDelay(2);                   /* Wait 20 mSecs for GF to charge       */

                                    /* If Ground Fault is not detected then */
                                    /* report a Ground Fault Test Failure   */
    if ((readLocalGroundFault() < GF_TEST_LEVEL))
        gndFltTestStatus = GF_TEST_FAIL_OFF;

    groundFaultTest(OFF);           /* Disable Ground Fault Test Mode       */
    taskDelay(2);                   /* Wait 20 mSecs for GF to discharge    */

                                    /* If Ground Fault is detected then     */
                                    /* report a Ground Fault Test Failure   */
                                    /* NOTE: This could also be a real GF   */
    if ((readLocalGroundFault() >= GF_TEST_LEVEL))
        gndFltTestStatus = GF_TEST_FAIL_ON;

    writeServiceRequest(2, GF_TEST_STATUS_SRQ, gndFltTestStatus);
    return (gndFltTestStatus);
} /* testGroundFaults() */

/****************************************************************************/
/* Function    : gfEnableControl                                            */
/* Purpose     : Enable/disable GF Power supply output                      */
/* Inputs      : Desired state - ON/OFF                                     */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
gfEnableControl(Nat16 mode)
{
    if (mode == ON)                    /* Enable GF power supply           */
        writeIoport1(~GF_ENABLE_CONTROL_BIT, AND_PORT);
    else                               /* Disable GF power suppply         */
        writeIoport1(GF_ENABLE_CONTROL_BIT, OR_PORT);

    gfEnableState = mode;
} /* gfEnableControl() */
