package util;
public class L2Channel {
private static final int L2_PACKET_SIZE = 128;
private static final int L2_BUFFER_SIZE = (L2_PACKET_SIZE * 2 + 4);
private static final int DLE = 0x10;
private static final int STX = 0x02;
private static final int ETX = 0x03;
private enum L2Error {
DLE_ERROR, // DLE is followed by a value different from STX,ETX or DLE
L2_RX_OVERFLOW, // L2 RX buffer Overflow
L2_TX_OVERFLOW, // L2 TX Buffer is overflow
CHSUM_ERROR, // Error in the caculated/received packet checksum
LENGTH_FIELD_ERROR, // Length field in packet to long/short
MISSING_START, // The first characters must be a DLE STX sequence
LAST_L2_ERROR
// Must always be the last number in enum!!
};
private static String getL2ErrorString(L2Error error) {
String result = null;
switch (error) {
case DLE_ERROR:
result = "DLE_ERROR";
break;
case L2_RX_OVERFLOW:
result = "L2_RX_OVERFLOW";
break;
case L2_TX_OVERFLOW:
result = "L2_TX_OVERFLOW";
break;
case CHSUM_ERROR:
result = "CHSUM_ERROR";
break;
case LENGTH_FIELD_ERROR:
result = "LENGTH_FIELD_ERROR";
break;
case MISSING_START:
result = "MISSING_START";
break;
case LAST_L2_ERROR:
result = "LAST_L2_ERROR";
break;
default:
result = "UNKNONW";
}
return result;
}
private enum l2_state_t {
L2_SYNC_STATE, L2_WAIT_STX_STATE, L2_RECV_STATE, L2_DLE_STATE
};
private class L2ControlType {
@SuppressWarnings("unused")
public long RXSignal_cnt; // Total number of signals received on L2
@SuppressWarnings("unused")
public long RXData_cnt; // Total number of data bytes received on L2
// (excl. DLE, STX, ETX & Bytestuffing)
@SuppressWarnings("unused")
public long RXBuffer_cnt; // Total number of bytes received on L2
@SuppressWarnings("unused")
public long TXSignal_cnt; // Total number of signals sent on L2
@SuppressWarnings("unused")
public long TXData_cnt; // Total number of data bytes sent on L2
// (excl. DLE, STX, ETX & Bytestuffing)
@SuppressWarnings("unused")
public long TXBuffer_cnt; // Total number of bytes sent on L2
public L2ControlType() {
RXSignal_cnt = RXData_cnt = RXBuffer_cnt = TXSignal_cnt = TXData_cnt = TXBuffer_cnt = 0;
}
}
private L2ControlType L2Control;
private l2_state_t l2_state;;
private byte[] l2_recv_buffer;
private byte[] l2_send_buffer;
private int l2_recv_buffer_ptr;
private short ptr;
private byte checksum;
private IL2ErrorHandler errorHandler;
public L2Channel(IL2ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
L2Control = new L2ControlType();
l2_state = l2_state_t.L2_SYNC_STATE;
l2_recv_buffer_ptr = 0;
l2_recv_buffer = new byte[L2_BUFFER_SIZE];
l2_send_buffer = new byte[L2_BUFFER_SIZE];
}
public void receive_callback(byte[] msg) {
;
}
public void send_callback(byte[] msg, short ptr) {
;
}
private void L2ErrorHandler(L2Error error, byte offendingByte) {
if (errorHandler != null) {
errorHandler.errorOccurred(getL2ErrorString(error), offendingByte);
}
}
private static short l2_stuff(byte[] buffer, short ptr, byte c) {
if (c == DLE) {
buffer[ptr++] = DLE;
}
buffer[ptr++] = c;
return ptr;
}
synchronized public final void l2_send(byte[] buffer) {
if (prologue((short) buffer.length)) {
int bufferIndex = 0;
while (bufferIndex < buffer.length) {
write(buffer[bufferIndex]);
bufferIndex++;
}
epilogue();
}
}
protected void epilogue() {
ptr = l2_stuff(l2_send_buffer, ptr, checksum);
l2_send_buffer[ptr++] = DLE;
l2_send_buffer[ptr++] = ETX;
L2Control.TXBuffer_cnt += ptr;
send_callback(l2_send_buffer, (short) ptr);
}
protected void write(byte b) {
ptr = l2_stuff(l2_send_buffer, ptr, b);
checksum += b;
}
public boolean prologue(short length) {
ptr = 0;
checksum = 0;
L2Control.TXSignal_cnt++;
L2Control.TXData_cnt += length;
if (length >= L2_PACKET_SIZE) {
L2ErrorHandler(L2Error.L2_TX_OVERFLOW, (byte) 0);
return false;
}
l2_send_buffer[ptr++] = DLE;
l2_send_buffer[ptr++] = STX;
ptr = l2_stuff(l2_send_buffer, ptr, (byte) (length & 0xff));
ptr = l2_stuff(l2_send_buffer, ptr, (byte) ((length >> 8) & 0xff));
return true;
}
synchronized public final void l2_recv(byte[] buffer) {
int length = buffer.length;
L2Control.RXBuffer_cnt += length; // Total number of signals
int index = 0;
// received on L2
while (length-- > 0) {
switch (l2_state) {
case L2_SYNC_STATE:
if (buffer[index] == DLE)
l2_state = l2_state_t.L2_WAIT_STX_STATE;
else
L2ErrorHandler(L2Error.MISSING_START, buffer[index]);
break;
case L2_WAIT_STX_STATE:
if (buffer[index] == STX) {
l2_state = l2_state_t.L2_RECV_STATE;
l2_recv_buffer_ptr = 0;
} else if (buffer[index] != DLE) {
l2_state = l2_state_t.L2_SYNC_STATE;
L2ErrorHandler(L2Error.MISSING_START, buffer[index]);
}
break;
case L2_RECV_STATE:
if (buffer[index] == DLE)
l2_state = l2_state_t.L2_DLE_STATE;
else {
l2_recv_buffer[l2_recv_buffer_ptr++] = buffer[index];
}
break;
case L2_DLE_STATE:
if (buffer[index] == DLE) {
l2_recv_buffer[l2_recv_buffer_ptr++] = DLE;
l2_state = l2_state_t.L2_RECV_STATE;
} else if (buffer[index] == ETX) {
short message_length = (short) (l2_recv_buffer[0] | (l2_recv_buffer[1] << 8));
byte checksum;
int i;
if (message_length != l2_recv_buffer_ptr - 3) {
L2ErrorHandler(L2Error.LENGTH_FIELD_ERROR, (byte) 0);
l2_state = l2_state_t.L2_SYNC_STATE;
continue;
}
// Normal Checksum compensates for an error in the BMC
// code, this error is not in the Simulated BMC
for (i = 0, checksum = 0; i < message_length; i++)
checksum += l2_recv_buffer[2 + i];
if (checksum != l2_recv_buffer[2 + message_length]) {
l2_state = l2_state_t.L2_SYNC_STATE;
L2ErrorHandler(L2Error.CHSUM_ERROR, (byte) 0);
continue;
}
L2Control.RXSignal_cnt++;
L2Control.RXData_cnt += message_length;
{
byte[] message = new byte[message_length];
for (int count = 0; count < message_length; count++) {
message[count] = l2_recv_buffer[count + 2];
}
receive_callback(message);
}
l2_state = l2_state_t.L2_SYNC_STATE;
} else {
l2_state = l2_state_t.L2_SYNC_STATE;
L2ErrorHandler(L2Error.DLE_ERROR, (byte) 0);
}
break;
}
index++;
if (l2_recv_buffer_ptr >= L2_BUFFER_SIZE) {
l2_state = l2_state_t.L2_SYNC_STATE;
L2ErrorHandler(L2Error.L2_RX_OVERFLOW, (byte) 0);
}
}
}
}