/****************************************************************************/
/* Copyright 1995 MBARI                                                     */
/****************************************************************************/
/* Summary  : Camera Daughter Board Misc Function Driver                    */
/* Filename : camBoard.c                                                    */
/* Author   : Douglas Au                                                    */
/* Project  : Tiburon ROV                                                   */
/* Version  : 1.0                                                           */
/* Created  : 03/27/95                                                      */
/* Modified : 03/27/95                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header:
 * $Log:
*/
/****************************************************************************/

#pragma model(196)
#pragma nosignedchar

#include "C:/C96/INCLUDE/80C196.h"      /* 80C196 Register mapping          */
#include "C:/C96/include/stddef.h"      /* C Standard Definitions           */
#include "const.h"                      /* Misc. constants - TRUE/FALSE etc */
#include "types.h"                      /* MBARI style guide declarations   */
#include "microasm.h"                   /* Assembly language functions      */
#include "malloc.h"                     /* Malloc support routines          */
#include "microcmd.h"                   /* microcontroller commands         */
#include "microdef.h"                   /* Microcontroller Definitions      */
#include "microlib.h"                   /* Microcontroller Library decls.   */
#include "ring.h"                       /* Ring buffer support routines     */

#include "applay.h"                     /* Application layer funcitions     */
#include "scc2692.h"                    /* Signetics SCC2692 UART Definition*/
#include "cam.h"
#include "camboard.h"                   /* Definitions for this application */

                                        /* Forward Declarations for MLocals */
MLocal Void scc2692InitUart( Void );
MLocal Void sccResetChannel(Nat16 chan);

MLocal Void sccRS485TxCtrl(Nat16 chan, Boolean state);
MLocal Void sccRS485RxCtrl(Nat16 chan, Boolean state);
MLocal Void sccTxStartUp(Nat16 chan);
MLocal Void sccWaitForRxIdle(Nat16 chan);
MLocal Void sccSetBaudRate(Nat16 chan);

MLocal Void sccEnableRx(Nat16 chan);
MLocal Void sccEnableTx(Nat16 chan);
MLocal Void sccDisableRx(Nat16 chan);
MLocal Void sccDisableTx(Nat16 chan);
MLocal Void sccEnableRxTx(Nat16 chan);
MLocal Void sccDisableRxTx(Nat16 chan);

MLocal Void sccFlushRx(Nat16 chan);
MLocal Void sccFlushRxTx(Nat16 chan);
MLocal Void sccInterrupt(Nat16 chan);

MLocal Int16 sccBufRead(Nat16 chan, Byte *buffer, Int16 nBytes);
MLocal Int16 sccBufWrite(Nat16 chan, Byte *buffer, Int16 nBytes);
MLocal Void  sccWriteByte(Nat16 chan, Byte txByte);

Byte* uartBaseAddress;
sccUartChan uartChan[CAM_UART_CHAN_PER_UART];

Byte test_buffer[CAM_UART_BUF_SIZE];
Extern MBool cameraLink;
Extern Byte data_resp[DATA_RESP_NUM][DATA_RESP_SIZE];
/****************************************************************************/
/* Function    : camUartInit                                                 */
/* Purpose     : UART Initialization routine                                */
/* Inputs      : None                                                       */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
camUartInit( Byte* uartAddress )
{
    Int16 chan;                         /* Serial Channel index             */

    uartBaseAddress = uartAddress;      /* Save UART Base Address           */

    scc2692InitUart();                  /* Initialize 2692 UART Hardware    */

    for (chan = 0; chan < CAM_UART_CHAN_PER_UART; chan++)
    {
        uartChan[chan].flags.enableStatus = (unsigned) 0;
        uartChan[chan].flags.chanOpen  = (unsigned) FALSE;
        uartChan[chan].flags.protocol  = (unsigned) RS485_MODE;
        uartChan[chan].flags.txBusy    = (unsigned) FALSE;
        uartChan[chan].flags.rxIdle    = (unsigned) FALSE;

        uartChan[chan].rxTerm = LINE_FEED;  /* Default termination character*/
        uartChan[chan].termRecvd = 0;

        ring_init(&uartChan[chan].readBuf,  uartChan[chan].readBuffer,
                  CAM_UART_BUF_SIZE);
        ring_init(&uartChan[chan].writeBuf, uartChan[chan].writeBuffer,
                  CAM_UART_BUF_SIZE);

                                /* Initialize channel dependent UART regs   */
                                /* Disable UART's Receiver and Transmitter  */
                                /* Reset Rx, Tx, Break and Error Flags      */
                                /* Disable RS485 transmitter                */
         sccResetChannel(chan);

                                /* Set line format 8 data/No Parity/2 stop */
         camUartSetLineFormat(chan, CS8, CSTOPB2, PARNONE, RS232_MODE);
      } /* for */
      int0Enable(EXTINT_MASK);  /* Unlock Interrupts from UART             */
} /* camUartInit() */

/****************************************************************************/
/* Function    : camUartOpenSerialChan                                      */
/* Purpose     : Open Camera UART Serial Channel                            */
/* Inputs      : Pointer to Serial Board data structure, channel number     */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
camUartOpenSerialChan(Nat16 chan, protocol proto)
{
    sccFlushRxTx(chan);             /* Flush input and output buffers     */

                                    /* Set up user specified line format    */
    sccResetChannel(chan);
                                    /* Reset Rx, Tx, Break and Error Flags  */
                                    /* Disable RS485 Transmitter            */

                                    /* Set Default Baud Rate to 19.2k baud  */
                                    /* Set line format 8 data/No Par/2 stop */
    camUartSetLineFormat(chan, CS8, CSTOPB2, PARNONE, proto);

                                    /* Mark channel as open                 */
    uartChan[chan].flags.chanOpen  = (unsigned) TRUE;
    uartChan[chan].termRecvd = 0;

    sccEnableRx(chan);              /* Enable Receiver, Txmit is disabled   */

    if (uartChan[chan].flags.protocol == (unsigned) RS485_MODE)
    {                               /* Wait for line to become idle         */
        sccWaitForRxIdle(chan);
        sccFlushRx(chan);           /* Flush read output buffer             */
    } /* if */

    else if (uartChan[chan].flags.protocol == (unsigned) RS232_MODE)
                                    /* RTS must be asserted to enable      */
        sccRS485TxCtrl(chan, ON);   /* automatic RTS generation by receiver*/

    sccRS485RxCtrl(chan, ON);       /* Enable Transceiver Receiver          */
} /* camUartOpenSerialChan() */

/****************************************************************************/
/* Function    : camUartSerialChanClose                                     */
/* Purpose     : Close Camera Serial Channel                                */
/* Inputs      : Pointer to Serial Board data structure, channel number     */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
camUartSerialChanClose(Nat16 chan)
{
                                    /* Negate RTS to stop Transmit device   */
                                    /* from sending any more data           */
    *(UART_REG(chan, COMMAND_REG)) = NEGATE_RTSN;

                                    /* Mark channel as closed               */
    uartChan[chan].flags.chanOpen = (unsigned) FALSE;

    sccDisableRxTx(chan);           /* Disable receiver and transmitter     */
} /* camUartSerialChanClose() */

/****************************************************************************/
/* Function    : camUartSerialChanWrite                                      */
/* Purpose     : Writes nBytes from buffer to the specified serial channel  */
/* Inputs      : Serial Board structure, channel number, buffer, No bytes   */
/* Outputs     : Returns the actual number of bytes written or ERROR.       */
/****************************************************************************/
    Int16
camUartSerialChanWrite(Nat16 chan, Byte *buffer, Int16 nBytes)
{
    if (uartChan[chan].flags.chanOpen == (unsigned) FALSE)
        return (ERROR);

    return (sccBufWrite(chan, buffer, nBytes) );
} /* camUartSerialChanWrite() */

/****************************************************************************/
/* Function    : camUartSerialChanRead                                       */
/* Purpose     : Put up to nBytes from specified serial channel into buffer */
/* Inputs      : Serial Board structure, channel number, buffer, No bytes   */
/* Outputs     : Returns the actual number of bytes read or ERROR.          */
/****************************************************************************/
    Int16
camUartSerialChanRead(Nat16 chan, Byte *buffer, Int16 nBytes)
{
    if (uartChan[chan].flags.chanOpen == (unsigned) FALSE)
        return (ERROR);

    return(sccBufRead (chan, buffer, nBytes) );
} /* camUartSerialChanRead() */


    Void
camUartSerialChanRxFlush(Nat16 chan)
{
    sccFlushRx(chan);
} /* camUartSerialChanRxFlush() */

    Int16
camUartTermRecvd(Nat16 chan)
{
    return (uartChan[chan].termRecvd);
} /* camUartTermRecvd() */

    Int16
camUartBytesRecvd(Nat16 chan)
{
    return (ring_entries( &uartChan[chan].readBuf ));
} /* camUartBytesRecvd() */


    Int16
camUartWaitForData(Nat16 chan)
{
    Nat16 ticks;                        /* Saves current ticker value       */

    ticks = read_sysclock();
    while ( (camUartBytesRecvd(chan) == 0) &&
            ( (read_sysclock() - ticks) < CAM_TIMEOUT) );

    return (camUartBytesRecvd(chan));
} /* camUartWaitForData() */

    Int16
camUartWaitForTerm(Nat16 chan)
{
    Nat16 ticks;                        /* Saves current ticker value       */

    ticks = read_sysclock();
    while ( (camUartTermRecvd(chan) == 0) &&
            ( (read_sysclock() - ticks) < CAM_TIMEOUT) );

    return (camUartTermRecvd(chan));
} /* camUartWaitForTerm() */

/****************************************************************************/
/* Function    : camUartSetLineFormat                                        */
/* Purpose     : Set  data bits, stop bits & parity for channel   */
/* Inputs      : Serial board address, channel, line format manifest consts */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
camUartSetLineFormat(Nat16 chan, Nat16 dataBits, Nat16 stopBits,
                             Nat16 parity, protocol proto)
{
    sccSetBaudRate(chan);

                                    /* Set pointer to MODE_REG1             */
    *(UART_REG(chan, COMMAND_REG)) = RESET_MR1;

                                    /* Initialize parity & data bit settings*/
    *(UART_REG(chan, MODE_REG1)) =
            RxRTS_OFF | RxINT_RxREADY | CHAR_ERR_MODE | parity | dataBits;

                                    /* Initialize stop bit setting          */
    *(UART_REG(chan, MODE_REG2)) =  TxCTS_OFF | CHAN_NORMAL |
       (proto == RS232_MODE  ? TxRTS_OFF : TxRTS_ON) | stopBits;

                                    /* Save protocol in Channel data struct */
    uartChan[chan].flags.protocol = (unsigned) proto;
} /* camUartSetLineFormat() */

/****************************************************************************/
/* Function    : camUartIsr                                                 */
/* Purpose     : Interrupt Handler for Camera UART Interrupts               */
/* Inputs      : Serial board address                                       */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
camUartIsr( Void )
{
    sccInterrupt(0);            /* Process interrupts for channel 0    */
} /* camUartIsr() */

/****************************************************************************/
/* Function    : sccBufWrite                                                */
/* Purpose     : Writes nBytes into ring buffer for specified serial channel*/
/* Inputs      : Serial Board structure, channel number, buffer, No bytes   */
/* Outputs     : Returns the actual number of bytes written                 */
/****************************************************************************/
    MLocal Int16
sccBufWrite(Nat16 chan, Byte *buffer, Int16 nBytes)
{
    Int16 bytes = 0;
                                    /* Copy data from user to ring buffer   */
    while ( ( bytes++ < nBytes) &&
            (ring_put(&uartChan[chan].writeBuf, *buffer++)) );
    int0Disable(EXTINT_MASK);       /* Lock Interrupts from UART            */
                                    /* If transmitter is idle, start it up  */
    if (uartChan[chan].flags.txBusy)
        int0Enable(EXTINT_MASK);    /* Unlock Interrupts from UART          */
    else
    {                               /* Set transmitter state busy           */
        uartChan[chan].flags.txBusy = (unsigned) TRUE;
        int0Enable(EXTINT_MASK);    /* Unlock Interrupts from UART          */
        sccTxStartUp(chan);         /* Enable transmitter and send 1st byte */
    } /* else */

    return (bytes);                 /* Return number of bytes written       */
} /* sccBufWrite() */

/****************************************************************************/
/* Function    : sccBufRead                                                 */
/* Purpose     : Read nBytes from ring buffer for specified serial channel  */
/* Inputs      : Serial Board structure, channel number, buffer, No bytes   */
/* Outputs     : Returns the actual number of bytes read                    */
/****************************************************************************/
    MLocal Int16
sccBufRead(Nat16 chan, Byte *buffer, Int16 nBytes)
{
     Int16 bytes = 0;

     if (nBytes == 0) return (0);

     do                            /* Copy data from ring to user buffer   */
     {
         if ( (*buffer = ring_get(&uartChan[chan].readBuf)) == ERROR)
             return (bytes);

         bytes++;

         if (*buffer++ == uartChan[chan].rxTerm)
         {
             uartChan[chan].termRecvd--;
             return (bytes);
          } /* if */
     } while (bytes < nBytes);

     return (bytes);                /* Return number of bytes read          */
} /* sccBufRead() */

/****************************************************************************/
/* Function    : sccFlushRx                                                 */
/* Purpose     : Flush Serial Board Receive buffer                          */
/* Inputs      : Pointer to Serial Board data structure, channel number     */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccFlushRx(Nat16 chan)
{
    uartChan[chan].termRecvd = 0;

                                    /* Re-initializing ring buffer to flush */
    ring_init(&uartChan[chan].readBuf,
            uartChan[chan].readBuffer, CAM_UART_BUF_SIZE);
} /* sccFlushRx */

/****************************************************************************/
/* Function    : sccFlushRxTx                                               */
/* Purpose     : Flush Serial Board Receive and Transmit buffers            */
/* Inputs      : Pointer to Serial Board data structure, channel number     */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccFlushRxTx(Nat16 chan)
{
    uartChan[chan].termRecvd = 0;

                                    /* Re-initializing ring buffer to flush */
    ring_init(&uartChan[chan].readBuf,
            uartChan[chan].readBuffer, CAM_UART_BUF_SIZE);

                                    /* Re-initializing ring buffer to flush */
    ring_init(&uartChan[chan].writeBuf,
            uartChan[chan].writeBuffer, CAM_UART_BUF_SIZE);
} /* sccFlushRxTx */

/****************************************************************************/
/* Function    : sccTxStartUp                                               */
/* Purpose     : Start transmitter for the specified serial channel         */
/* Inputs      : Serial Board structure, channel number                     */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
sccTxStartUp(Nat16 chan)
{
                                  /* Everything depends on operating mode   */
    if (uartChan[chan].flags.protocol == (unsigned) RS232_MODE)
                                          /* ********** RS232 Mode ******** */
        sccEnableRxTx(chan);              /* Enable the transmitter. This   */
                                          /* causes a TxRDY Interrupt and   */
                                          /* ISR sends the first byte       */

    else if (uartChan[chan].flags.protocol == (unsigned) RS485_MODE)
    {                                     /* ********* RS485 Mode ********* */
        sccEnableRx(chan);                /* Enable the UART Rx, disable Tx */
        sccWaitForRxIdle(chan);           /* Wait for Rx to go idle         */
        sccDisableRx(chan);               /* Disable the UART receiver      */

        sccRS485TxCtrl(chan, ON);         /* Enable RS485 Transmitter       */

        sccEnableTx(chan);                /* Enable the transmitter. This   */
                                          /* causes a TxRDY Interrupt and   */
                                          /* ISR sends the first byte       */
    } /* else */

    else if (uartChan[chan].flags.protocol == (unsigned) RS422_MODE)
    {                                     /* ********* RS422 Mode ********* */
        sccRS485TxCtrl(chan, ON);         /* Enable RS422 Transmitter       */
        sccEnableTx(chan);                /* Enable the transmitter. This   */
                                          /* causes a TxRDY Interrupt and   */
                                          /* ISR sends the first byte       */
    } /* else */
} /* sccTxStartUp() */

/****************************************************************************/
/* Function    : scc2692InitUart                                            */
/* Purpose     : Both serial channels of the SCC2692 are initialized:       */
/*               OP0 is set to RTS Mode, RS485 Transmitter is disabled &    */
/*               Receiver Ready interrupts are enabled                      */
/* Inputs      : None                                                       */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
scc2692InitUart( Void )
{
    Reg Nat16 chan;                 /* channel loop counter                 */

                                    /* Initialize all channels in a UART    */
    for (chan = 0; chan < CAM_UART_CHAN_PER_UART; chan += 2)
    {
                                    /* Set pointer to MODE_REG1             */
        *(UART_REG(chan, COMMAND_REG)) = RESET_MR1;

                                    /* Initialize parity & data bit settings*/
        *(UART_REG(chan, MODE_REG1)) =
            RxRTS_OFF | RxINT_RxREADY | CHAR_ERR_MODE | PARNONE | CS8;

                                    /* Set OP0A & OP0B pins to RTSN Mode    */
        *(UART_REG(chan, MODE_REG2)) =
              CHAN_NORMAL | CSTOPB2 | TxCTS_OFF | TxRTS_OFF;
    } /* for */

                                    /* Use OPR reg bits to control OP lines */
    *(UART_REG(0, OUT_CONFIG_REG)) = OP_MAP_TO_OPR;

                                    /* Interrupt enabled for Receive Byte,  */
                                    /* or Transmit Byte                     */
    *(UART_REG(0, INT_MASK_REG)) =  RxRDYA | RxRDYB | TxRDYA | TxRDYB;
} /* scc2692InitUart() */

/****************************************************************************/
/* Function    : sccResetChannel                                            */
/* Purpose     : resets a SCC2692 serial channel to the following state:    */
/*               Receiver, Transmitter & Error Status set to power up state */
/*               Break change interrupt is cleared, UART Rx and Tx disabled */
/* Inputs      : Base address of quad serial board, channel number          */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccResetChannel(Nat16 chan)
{
                                    /* Put Rx and Rx in reset state         */
    *(UART_REG(chan, COMMAND_REG)) = RESET_RX;
    *(UART_REG(chan, COMMAND_REG)) = RESET_TX;
    *(UART_REG(chan, COMMAND_REG)) = RESET_ERROR;
    *(UART_REG(chan, COMMAND_REG)) = RESET_BREAK;

                                    /* Disable recevier and transmitter     */
    *(UART_REG(chan, COMMAND_REG)) = (RX_DISABLE | TX_DISABLE);

    sccRS485TxCtrl(chan, OFF);      /* Disable RS485 transmitter            */
} /* sccResetChannel() */

/****************************************************************************/
/* Function    : sccEnableRx                                                */
/* Purpose     : Enable a channel's receiver                                */
/* Inputs      : Base address of quad serial board, channel number          */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccEnableRx(Nat16 chan)
{
                                  /* Enable UART Receiver                   */
    uartChan[chan].flags.enableStatus |= (unsigned) RX_ENABLE;
    *(UART_REG(chan, COMMAND_REG)) = RX_ENABLE;
} /* sccEnableRx() */

/****************************************************************************/
/* Function    : sccEnableTx                                                */
/* Purpose     : Enable a channel's transmitter                             */
/* Inputs      : Base address of quad serial board, channel number          */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccEnableTx(Nat16 chan)
{
                                  /* Enable UART Transmitter                */
    uartChan[chan].flags.enableStatus |= (unsigned) TX_ENABLE;
    *(UART_REG(chan, COMMAND_REG)) =  TX_ENABLE;
} /* sccEnableTx() */

/****************************************************************************/
/* Function    : sccEnableRxTx                                              */
/* Purpose     : Enable a channel's receiver & transmitter                  */
/* Inputs      : Base address of quad serial board, channel number          */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccEnableRxTx(Nat16 chan)
{
                                  /* Enable UART Transmitter                */
    uartChan[chan].flags.enableStatus |= (unsigned) (TX_ENABLE | RX_ENABLE);
    *(UART_REG(chan, COMMAND_REG)) =  (RX_ENABLE | TX_ENABLE);
} /* sccEnableRxTx() */

/****************************************************************************/
/* Function    : sccDisableRx                                               */
/* Purpose     : Disable a channel's receiver                               */
/* Inputs      : Base address of quad serial board, channel number          */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccDisableRx(Nat16 chan)
{
                                  /* Disable UART Receiver                  */
    uartChan[chan].flags.enableStatus &= (unsigned) ~RX_ENABLE;
    *(UART_REG(chan, COMMAND_REG)) = RX_DISABLE;
} /* sccDisableRx() */

/****************************************************************************/
/* Function    : sccDisableTx                                               */
/* Purpose     : Disable a channel's transmitter                            */
/* Inputs      : Base address of quad serial board, channel number          */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccDisableTx(Nat16 chan)
{
                                  /* Disable UART Transmitter               */
    uartChan[chan].flags.enableStatus &= (unsigned) ~TX_ENABLE;
    *(UART_REG(chan, COMMAND_REG)) = TX_DISABLE;
} /* sccDisableTx() */

/****************************************************************************/
/* Function    : sccDisableRxTx                                             */
/* Purpose     : Disable a channel's receiver and transmitter               */
/* Inputs      : Base address of quad serial board, channel number          */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccDisableRxTx(Nat16 chan)
{
                                  /* Disable UART Receiver                  */
    uartChan[chan].flags.enableStatus &= (unsigned) ~(RX_ENABLE | TX_ENABLE);
    *(UART_REG(chan, COMMAND_REG)) = (RX_DISABLE | TX_DISABLE);
} /* sccDisableRxTx() */

/****************************************************************************/
/* Function    : sccRS485TxCtrl                                             */
/* Purpose     : Enable/Disable of RS485 transmitter.                       */
/* Inputs      : Base address of quad serial board, channel number, state   */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccRS485TxCtrl(Nat16 chan, Boolean state)
{
#if AUTOMATIC_RTS
                                   /* Enable or disable RS485 Transmitter   */
   *(UART_REG(chan, COMMAND_REG)) = (state == OFF ? NEGATE_RTSN : ASSERT_RTSN);#else

   *(UART_REG(chan, COMMAND_REG)) = NEGATE_RTSN;
#endif
} /* sccRS485TxCtrl() */

/****************************************************************************/
/* Function    : sccRS485RxCtrl                                             */
/* Purpose     : Enable/Disable of RS485 receiver.                          */
/* Inputs      : Base address of quad serial board, channel number, state   */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccRS485RxCtrl(Nat16 chan, Boolean state)
{
    if (chan == 0)                  /* Enable or disable RS485 Receiver     */
       *(UART_REG(0, (state == OFF ? RESET_OUT_PORT : SET_OUT_PORT))) = OP6;
    else
       *(UART_REG(0, (state == OFF ? RESET_OUT_PORT : SET_OUT_PORT))) = OP7;
} /* sccRS485RxCtrl() */

/****************************************************************************/
/* Function    : sccSetBaudRate                                             */
/* Purpose     : Sets baurd rate for serial channel                         */
/* Inputs      : Serial board address, channel, baud rate manifest constant */
/* Note        : The AUX_CTRL_REG select the baud rate group FOR ADJECENT   */
/*               CHANNELS so both channels MUST use rates from same group   */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccSetBaudRate(Nat16 chan)
{
                                  /* Set baud rate to IP3 or 4 x 16 */
    *(UART_REG(0, CLK_SEL_REG)) = (IPx16 << 4) | IPx16;
    *(UART_REG(1, CLK_SEL_REG)) = (IPx16 << 4) | IPx16;
} /* sccSetBaudRate() */

/****************************************************************************/
/* Function    : sccSetloopback                                             */
/* Purpose     : Sets loopback mode for specified serial channel            */
/* Inputs      : Serial board address, channel, loopback enable/disable     */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccSetLoopback(Nat16 chan, Nat16 stopbits, Boolean loopbackCtrl)
{
    *(UART_REG(chan, MODE_REG2) ) =
        (loopbackCtrl == TRUE ? CHAN_LOOPBACK : CHAN_NORMAL) |
         TxRTS_OFF | TxCTS_OFF | stopbits;
} /* sccSetLoopback() */

/****************************************************************************/
/* Function    : sccWaitForRxIdle                                           */
/* Purpose     : waits for a quiet serial channel receiver.                 */
/* Inputs      : Serial board address, channel                              */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccWaitForRxIdle(Nat16 chan)
{
    do
    {                             /* Set channel idle flag. This is cleared */
                                  /* by the interrupt handler when a byte   */
                                  /* is recevied                            */
        uartChan[chan].flags.rxIdle = (unsigned) TRUE;
                                  /* Wait for longer than a character time  */
        taskDelay(CAM_UART_RX_IDLE_TIME);

    } while (uartChan[chan].flags.rxIdle == (unsigned) FALSE);
                                  /* Flag is still true so the line is idle */
} /* sccWaitForRxIdle() */

/****************************************************************************/
/* Function    : sccInterrupt                                               */
/* Purpose     : Processes Interrupt for a single SCC2692 UART Serial Chan  */
/* Inputs      : Serial board address, bit masks for Tx, Rx & Counter Intrs */
/* Outputs     : None                                                       */
/****************************************************************************/
    MLocal Void
sccInterrupt( Nat16 chan )
{
    MLocal Int16 index;

    Int16 byteNum;
    Reg Byte rxByte;                    /* Character recevied byte          */
    Reg Int16 txByte;                   /* Character to send byte           */

    while( *(UART_REG(chan, STATUS_REG)) & RxRDY)
    {                                   /* Check for byte received interrupt*/
                                        /* Read received byte from UART     */
        rxByte = *(UART_REG(chan, RX_HOLD_REG));

        uartChan[chan].flags.txBusy = (unsigned) TRUE;
        sccEnableRxTx(chan);              /* Enable the transmitter. This   */

        switch(rxByte)
        {
            case DATA1_REQ0:
            case DATA1_REQ1:
            case DATA1_REQ2:
              for(byteNum = 0; byteNum < 4; byteNum++)
                 sccWriteByte(chan, data_resp[DATA1][byteNum]);
              break;

            case DATA2_REQ:
              for(byteNum = 0; byteNum < 4; byteNum++)
                 sccWriteByte(chan, data_resp[DATA2][byteNum]);
              break;

            case DATA3_REQ:
              for(byteNum = 0; byteNum < 4; byteNum++)
                 sccWriteByte(chan, data_resp[DATA3][byteNum]);
              break;

            case DATA4_REQ:
              for(byteNum = 0; byteNum < 4; byteNum++)
                 sccWriteByte(chan, data_resp[DATA4][byteNum]);
              break;

            case DATA5_REQ:
              for(byteNum = 0; byteNum < 4; byteNum++)
                 sccWriteByte(chan, data_resp[DATA5][byteNum]);
              break;

            case DATA6_REQ:
              for(byteNum = 0; byteNum < 4; byteNum++)
                 sccWriteByte(chan, data_resp[DATA6][byteNum]);
              break;

            case DATA7_REQ:
              for(byteNum = 0; byteNum < 4; byteNum++)
                 sccWriteByte(chan, data_resp[DATA7][byteNum]);
              break;

            case DATA8_REQ:
              for(byteNum = 0; byteNum < 4 ; byteNum++)
                 sccWriteByte(chan, data_resp[DATA8][byteNum]);
              break;

            case CCC_REQ:
              {
              for(byteNum = 0; byteNum < 4; byteNum++)
                 sccWriteByte(chan, data_resp[CCC][byteNum]);
              cameraLink = CAMERA_LINK_UP;
              }
              break;

           default:
              uartChan[chan].flags.txBusy = (unsigned) FALSE;
              sccDisableTx(chan);
        }/* End Select */

                                       /* If the channel is open then      */
        if (uartChan[chan].flags.chanOpen)
        {                               /* Save the byte in receive buffer  */
            ring_put(&uartChan[chan].readBuf, rxByte);

                                        /* Check for termination character  */
            if (rxByte == uartChan[chan].rxTerm)
                uartChan[chan].termRecvd++;
            uartChan[chan].flags.rxIdle = FALSE;
                                        /* Used by sccWaitForRxIdle to flag */
                                        /* activity on this channel Rx line */
        } /* if */
    } /* while */


    if (uartChan[chan].flags.chanOpen)
    {                                    /* Check for Transmit Ready Flag   */
        if ( (*(UART_REG(chan, STATUS_REG)) & TxRDY) )
        {                               /* Fetch next byte and send it      */
            if ( (txByte = ring_get(&uartChan[chan].writeBuf)) != ERROR)
            {                           /* got a character to be output     */
                *(UART_REG(chan, TX_HOLD_REG)) = (Byte) txByte;

                if (ring_entries(&uartChan[chan].writeBuf) == 0)
                {                       /* Last byte has been sent          */

                    sccDisableTx(chan); /* So disable Transmitter           */
                                       /* Re-enable recevier if RS485 Mode */
                   if (uartChan[chan].flags.protocol == (unsigned) RS485_MODE)
                         sccEnableRx(chan);

                                        /* Clear Transmitter busy flag      */
                    uartChan[chan].flags.txBusy = (unsigned) FALSE;
                } /* if */
            } /* if */
            else
            {
                sccDisableTx(chan);
                sccRS485TxCtrl(chan, OFF);
                                        /* Re-enable recevier if RS485 Mode */
                if (uartChan[chan].flags.protocol == (unsigned) RS485_MODE)
                    sccEnableRx(chan);
                                        /* Clear Transmitter busy flag      */
                uartChan[chan].flags.txBusy = (unsigned) FALSE;
            } /* if */
        } /* if */
    } /* if */
} /* sccInterrupt() */

   MLocal Void
sccWriteByte(Nat16 chan, Byte txByte)
{

                                         /* Check for Transmit Ready Flag   */
    while  ( (*(UART_REG(chan, STATUS_REG)) & TxRDY) == 0);
    *(UART_REG(chan, TX_HOLD_REG)) =  txByte;
} /* sccWriteByte */



