Return | Jackpot | Comms | HostInterface | Config | Timer | JackSystem

/*
 * Comms.java
 */


/**
 * Communication object performs basic handling of incoming and outgoing messages.
 * It checks the incomming message for correct envelope (STX, VLI, ... ETX, LRC)
 * and if checks out then it dispatches the message to the HostInterface object where
 * the message is processed further.
 * If the HostInterface object wishes to send a response back to the host communication
 * object creates appropriate envelope around outgoing data. <p>
 * Outgoing message is not transmitted if node address is global (ADDR_ALL) 
 * addressing all nodes. This is to prevent collisions on the network.
 */
class Comms extends Thread
{
    /** Maximum size of the input/output message */
    public static final int MAX_MSG_SIZE = 128;

    /** Start of text character */
    public static final byte CH_STX = 2;
    /** End of text character */
    public static final byte CH_ETX = 3;

    /** No error detected */
    public static final int NO_ERR = 0;
    public static final int ERR_OVERFLOW = 1;
    public static final int ERR_NODATA = 2;
    public static final int ERR_DISABLED = 3;
    public static final int ERR_NOETX = 4;
    public static final int ERR_BADLRC = 5;

    /** Message receive states */
    private static final int ST_STX = 1;
    private static final int ST_VLI = 2;
    private static final int ST_DATA = 3;
    private static final int ST_ETX = 4;
    private static final int ST_LRC = 5;
    private static final int ST_RECEIVED = 6;

    /** Buffer for incomming messages */
    private byte data_in[] = new byte[MAX_MSG_SIZE];
    /** Buffer for outgoing messages */
    private byte data_out[] = new byte[MAX_MSG_SIZE];
    private int pos, inLen, error, state;
    private byte lrc;
    /** Reference to configuration object */
    private Config Conf = null;

    /**
     * Set to true every time message is received. If not set within certain
     * time limit (usually 60secs) then Jackpot board is re-started
     */
    boolean haveMessage = false;

    /**
     * Constructor for communication object.
     * @param Conf reference to configuration object
     */
    public Comms(Config Conf)
    {
        state = ST_STX;
        error = NO_ERR;
        this.Conf = Conf;
    }

    /**
     * Initialises the communication interface to specified baud rate,
     * flushes the in/out buffers and enables the receiver.
     * @param   Baud baud rate to be used for communication
     * @return  True if initialisation was successful. False is returned if
     *          specified Baud rate was not 9600,19200 or 38400.
     */
    public boolean Init(int Baud)
    {
        if (Baud != 38400 && Baud != 19200 && Baud != 9600)
            return false;

        SetBaudRate(Baud);
        RxMode();
        Flush();
        return true;
    }

    /**
     * Writes the message to the communication port. First it checks for the
     * correctness of data, then it enables the transmitter and puts
     * envelope around the message. Envelope has the following format:
     * <STX><VLI><..data..><ETX><LRC>. LRC is calculated as EOR operation on
     * all data sent including STX, VLI and ETX. At the end of transmission
     * receiver is re-enabled.
     * @param   Len length of the outgoing data
     * @param   Msg byte array containing the outgoing data
     * @return  ERR_NODATA if input parameters do not contain message.
     *          NO_ERR is returned is transmission was OK.
     */
    private int WriteMessage(int Len, byte[] Msg)
    {
        if (Msg == null || Msg.length == 0 || Len < 1)
            return ERR_NODATA;

        TxMode();
        lrc = CH_STX;
        lrc ^= (byte)Len;
        PutByte(CH_STX);
        PutByte((byte)(Len));
        for (int i=0; i < Len; i++)
        {
            PutByte(Msg[i]);
            lrc ^= Msg[i];
        }
        PutByte(CH_ETX);
        lrc ^= CH_ETX;
        PutByte(lrc);
        RxMode();

        return NO_ERR;
    }


    /**
     * Main processing method for Comms object thread. Here are all
     * incomming messages assembled and checked. If message checks Ok then
     * handler, corresponding to the type of message, is invoked. Once
     * the message has been processed an outgoing message can be formed by
     * the HostInterface object and transmitted.
     */
    public void run()
    {
        Timer MsgTimer = new Timer();
        HostInterface HostInt = new HostInterface(Conf);
        while (true)
        {
            if (state != ST_STX && MsgTimer.Expired())
            {
                state = ST_STX;
                error = NO_ERR;
                Flush();
            }
            if (ByteReceived())
            {
                byte ch = GetByte();
                switch (state)
                {
                    case ST_STX:
                        if (ch == CH_STX)
                        {
                            lrc = ch;
                            state = ST_VLI;

                            // start message timeout
                            MsgTimer.Start(1000);
                        }
                        break;

                    case ST_VLI:
                        inLen = ch;
                        lrc ^= ch;
                        pos = 0;
                        state = ST_DATA;
                        break;

                    case ST_DATA:
                        if (pos < inLen)
                        {
                            data_in[pos++] = ch;
                            lrc ^= ch;
                        }
                        if (pos >= inLen)
                            state = ST_ETX;
                        break;

                    case ST_ETX:
                        if (ch == CH_ETX)
                        {
                            lrc ^= ch;
                            state = ST_LRC;
                        }
                        else
                            error = ERR_NOETX;
                        break;

                    case ST_LRC:
                        if (lrc == ch)
                        {
                            state = ST_RECEIVED;
                        }
                        else
                            error = ERR_BADLRC;
                        break;
                }
            }
            if (state == ST_RECEIVED)
            {
                haveMessage = true;
                int outLen = HostInt.Process(inLen, data_in, data_out);
                if (outLen > 0)
                {
                   // do not send response if all nodes were addressed
                   if (data_out[HostInt.POS_ADDR] != HostInt.ADDR_ALL)
                        sWriteMessage(outLen, data_out);

                    // reset the system if required
                    if (data_out[HostInt.POS_CMD] == HostInt.CMD_RESET &&
                        data_out[HostInt.POS_RESP] == HostInt.NO_ERR)
                    {
                        JackSystem.SystemReset(2000);
                    }

                }
                state = ST_STX;
            }
        }
    }


    /**
     * Writes single byte to the comm port.
     * @param   Val byte value to be transmitted.
     * @return  False if there is not enough room in the transmit buffer,
     *          otherwise true is returned.
     */
    private native boolean PutByte(byte Val);

    /**
     * Checks is the receive buffer contain any unread characters.
     * @return  True if there are characters in the receive buffer,
     *          otherwise false is returned.
     */
    private native boolean ByteReceived();

    /**
     * Reads the byte from the receive buffer.
     * @return  Received byte.
     */
    private native byte GetByte();

    /**
     * Clears the input/output buffers.
     */
    private native void Flush();

    private native void Enable(boolean Tx, boolean Rx);

    /**
     * Install the interrupt handler for the comm port and sets the baud
     * rate to the specified value.
     * @param   Baud baud rate to be used for communication.
     */
    private native void SetBaudRate(int Baud);

    /**
     * Activates the transmitter and deactivates the receiver.
     */
    private native void TxMode();

    /**
     * Activates receiver the and deactivates the transmitter.
     */
    private native void RxMode();

}


Return | Jackpot | Comms | HostInterface | Config | Timer | JackSystem