/*
* 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);
}