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

/*
 * HostInterface.java
 */


/**
 * Host interface object receives incomming host request from the communication
 * object. Once the message is received it is checked for correct length. Then
 * the appropriate handling method is called to process the message and prepare
 * the response. Response is then passed to the communication object so it can be
 * transmitted to the host.
 */
class HostInterface
{
    final static byte CMD_CONFIG    = 0x41;
    final static byte CMD_READ      = 0x42;
    final static byte CMD_CLEAR     = 0x43;
    final static byte CMD_RELAY     = 0x44;
    final static byte CMD_STATUS    = 0x45;
    final static byte CMD_RESET     = 0x46;
    final static byte CMD_Z80       = 0x47;

    final static byte NO_ERR        = 0x00;
    final static byte ERR_BAD_NODE  = 0x31;
    final static byte ERR_BAD_CMD   = 0x32;
    final static byte ERR_BAD_FIELD = 0x33;
    final static byte ERR_BAD_LEN   = 0x34;
    final static byte ERR_BAD_STATE = 0x35;
    final static byte ERR_TIMEOUT   = 0x36;
    final static byte ERR_COMMS     = 0x37;
    final static byte ERR_BUSY      = 0x38;

    final static int DEF_RESP_LEN   = 3;
    final static int POS_CMD        = 0;
    final static int POS_ADDR       = 1;
    final static int POS_RESP       = 2;
    final static int POS_DATA_IN    = 2;
    final static int POS_DATA_OUT   = 3;

    final static int ID_CNT_IN      = 1;
    final static int ID_CNT_OUT     = 2;
    final static int ID_CNT_START   = 3;

    final static int ADDR_ALL            = 0x99;

    /** Reference to configuration object */
    private Config Conf = null;


    /**
     * Constructor for host interface object. Host interface object handles
     * all incomming requests and forms appropriate response.
     * @param   Conf reference to configuration object.
     */
    HostInterface(Config Conf)
    {
        this.Conf = Conf;
    }

    /**
     * Checks the incomming message and then calls the corresponding handler
     * method.
     * @param   reqLen length of the request
     * @param   Req byte array containg the request
     * @param   Resp byte array into which response will be copied
     * @return  Number of bytes in the response message. Zero may be
     *          returned if request has no data.
     */
    int Process(int reqLen, byte[] Req, byte[] Resp)
    {
        if (reqLen <= 0) return 0;

        // setup default response
        int respLen = 3;
        Resp[POS_CMD] = Req[POS_CMD];
        Resp[POS_ADDR] = Req[POS_ADDR];
        Resp[POS_RESP] = NO_ERR;

        // check node ID
        if (Req[POS_ADDR] != Conf.GetNodeID() && Req[POS_ADDR] != ADDR_ALL)
        {
            Resp[POS_RESP] = ERR_BAD_NODE;
            return respLen;
        }

        switch (Req[POS_CMD])
        {
            case CMD_CONFIG:
                respLen = Config(reqLen, Req, Resp);
                break;

            case CMD_READ:
                respLen = ReadCounters(reqLen, Req, Resp);
                break;

            case CMD_CLEAR:
                respLen = ClearCounters(reqLen, Req, Resp);
                break;

            case CMD_RELAY:
                respLen = AudioRelay(reqLen, Req, Resp);
                break;

            case CMD_STATUS:
                respLen = GetStatus(reqLen, Req, Resp);
                break;

            case CMD_RESET:
                respLen = Reset(reqLen, Req, Resp);
                break;

            case CMD_Z80:
                respLen = Z80Command(reqLen, Req, Resp);
                break;

            default:
                Resp[POS_RESP] = ERR_BAD_CMD;
                respLen = DEF_RESP_LEN;
                break;
        }

        return respLen;
    }

    /**
     * Processes the 'A' command - Configure. Using the configuration object
     * to write new configuration data into internal EEPROM.
     * @param   reqLen length of the request
     * @param   Req byte array containg the request
     * @param   Resp byte array into which response will be copied
     * @return  Number of bytes in the response message.
     */
    private int Config(int reqLen, byte[] Req, byte[] Resp)
    {
        // check request length
        if (reqLen != 26)
        {
            Resp[POS_RESP] = ERR_BAD_LEN;
            return DEF_RESP_LEN;
        }

        Conf.Set(Req);

        return DEF_RESP_LEN;
    }


    /**
     * Processes the 'B' command - Read counters.
     * @param   reqLen length of the request
     * @param   Req byte array containg the request
     * @param   Resp byte array into which response will be copied
     * @return  Number of bytes in the response message.
     */
    private int ReadCounters(int reqLen, byte[] Req, byte[] Resp)
    {
        // check request length
        if (reqLen != 5)
        {
            Resp[POS_RESP] = ERR_BAD_LEN;
            return DEF_RESP_LEN;
        }

        int val = ReadCounter(ID_CNT_IN);
        Resp[POS_DATA_OUT+0] = (byte)(val >> 24);
        Resp[POS_DATA_OUT+1] = (byte)(val >> 16);
        Resp[POS_DATA_OUT+2] = (byte)(val >> 8);
        Resp[POS_DATA_OUT+3] = (byte)val;

        val = ReadCounter(ID_CNT_OUT);
        Resp[POS_DATA_OUT+4] = (byte)(val >> 24);
        Resp[POS_DATA_OUT+5] = (byte)(val >> 16);
        Resp[POS_DATA_OUT+6] = (byte)(val >> 8);
        Resp[POS_DATA_OUT+7] = (byte)val;

        val = ReadCounter(ID_CNT_START);
        Resp[POS_DATA_OUT+8] = (byte)(val >> 24);
        Resp[POS_DATA_OUT+9] = (byte)(val >> 16);
        Resp[POS_DATA_OUT+10] = (byte)(val >> 8);
        Resp[POS_DATA_OUT+11] = (byte)val;

        ClearCounters(Req);

        return DEF_RESP_LEN + 12;
    }

    /**
     * Processes the 'C' command - Clear counters.
     * @param   reqLen length of the request
     * @param   Req byte array containg the request
     * @param   Resp byte array into which response will be copied
     * @return  Number of bytes in the response message.
     */
    private int ClearCounters(int reqLen, byte[] Req, byte[] Resp)
    {
        // check request length
        if (reqLen != 5)
        {
            Resp[POS_RESP] = ERR_BAD_LEN;
            return DEF_RESP_LEN;
        }

        ClearCounters(Req);

        return DEF_RESP_LEN;
    }


    /**
     * Processes the 'D' command - Audio relay control.
     * @param   reqLen length of the request
     * @param   Req byte array containg the request
     * @param   Resp byte array into which response will be copied
     * @return  Number of bytes in the response message.
     */
    private int AudioRelay(int reqLen, byte[] Req, byte[] Resp)
    {
        // check request length
        if (reqLen != 3)
        {
            Resp[POS_RESP] = ERR_BAD_LEN;
            return DEF_RESP_LEN;
        }

        if (Req[POS_DATA_IN] == 'Y')
            JackSystem.Relay(JackSystem.ON);
        else
            JackSystem.Relay(JackSystem.OFF);
        return DEF_RESP_LEN;
    }


    /**
     * Processes the 'E' command - Get status.
     * @param   reqLen length of the request
     * @param   Req byte array containg the request
     * @param   Resp byte array into which response will be copied
     * @return  Number of bytes in the response message.
     */
    private int GetStatus(int reqLen, byte[] Req, byte[] Resp)
    {
        // check request length
        if (reqLen != 2)
        {
            Resp[POS_RESP] = ERR_BAD_LEN;
            return DEF_RESP_LEN;
        }

        Resp[POS_DATA_OUT] = Conf.GetNodeID();
        Conf.GetNodeName(Resp, POS_DATA_OUT+1);
        short val = Conf.GetDebounce();
        Resp[POS_DATA_OUT+17] = (byte)(val >> 8);
        Resp[POS_DATA_OUT+18] = (byte)val;
        val = Conf.GetDisable();
        Resp[POS_DATA_OUT+19] = (byte)(val >> 8);
        Resp[POS_DATA_OUT+20] = (byte)val;
        val = Conf.GetCntDebounce();
        Resp[POS_DATA_OUT+21] = (byte)(val >> 8);
        Resp[POS_DATA_OUT+22] = (byte)val;
        Conf.GetVersion(Resp, POS_DATA_OUT+23);

        return DEF_RESP_LEN + 28;
    }


    /**
     * Processes the 'F' command - Reset Jackpot. Jackpot can be reset only
     * if counter has been read out and cleared.
     * @param   reqLen length of the request
     * @param   Req byte array containg the request
     * @param   Resp byte array into which response will be copied
     * @return  Number of bytes in the response message.
     */
    private int Reset(int reqLen, byte[] Req, byte[] Resp)
    {
        // check request length
        if (reqLen != 2)
        {
            Resp[POS_RESP] = ERR_BAD_LEN;
            return DEF_RESP_LEN;
        }

        // counters must be zero
        if (ReadCounter(ID_CNT_IN) > 0 || ReadCounter(ID_CNT_OUT) > 0 ||
            ReadCounter(ID_CNT_START) > 0)
        {
            Resp[POS_RESP] = ERR_BAD_STATE;
            return DEF_RESP_LEN;
        }

        return DEF_RESP_LEN;
    }


    /**
     * Clears counters which corresponding request byte has value 'Y'.
     *
     * @param   Req request as received from the host. Information bytes starts
     *          at POS_DATA_IN.
     */
    private void ClearCounters(byte[] Req)
    {
        if (Req[POS_DATA_IN] == (byte)'Y')
            ClearCounter(ID_CNT_IN);

        if (Req[POS_DATA_IN+1] == (byte)'Y')
            ClearCounter(ID_CNT_OUT);

        if (Req[POS_DATA_IN+2] == (byte)'Y')
            ClearCounter(ID_CNT_START);
    }


    /**
     * Not implemented in this version of Jackpot.
     */
    private int Z80Command(int reqLen, byte[] Req, byte[] Resp)
    {
        return DEF_RESP_LEN;
    }

    /**
     * Reads the value of the specified counter.
     *
     * @param   Id ID of the counter. Possible values are ID_CNT_IN, ID_CNT_OUT
     *          and ID_CNT_START.
     * @return  Value of the specified counter.
     */
    private native int ReadCounter(int Id);

    /**
     * Clears the the specified counter.
     *
     * @param   Id ID of the counter. Possible values are ID_CNT_IN, ID_CNT_OUT
     *          and ID_CNT_START.
     */
    private native void ClearCounter(int Id);
}

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