package org.reprap.comms.snap;
import java.io.IOException;
public class SNAPPacket {
/**
*
*/
private final int offset_sync = 0;
/**
*
*/
private final int offset_hdb2 = 1;
/**
*
*/
private final int offset_hdb1 = 2;
/**
*
*/
private final int offset_dab = 3;
/**
*
*/
private final int offset_sab = 4;
/**
*
*/
private final int offset_payload = 5;
/**
*
*/
private final byte syncMarker = 0x54;
/**
*
*/
private final int maxSize = 64;
/**
* Full raw packet contents including all headers
*/
private byte [] buffer;
/**
*
*/
private int receiveLength = 0;
/**
*
*/
private boolean complete = false;
/**
*
*/
SNAPPacket() {
buffer = new byte[maxSize];
}
/**
* @param srcAddress
* @param destAddress
* @param payload
*/
SNAPPacket(SNAPAddress srcAddress, SNAPAddress destAddress, byte [] payload) {
buffer = new byte[payload.length + offset_payload + 1];
buffer[offset_sync] = syncMarker;
buffer[offset_hdb2] = 0x51;
buffer[offset_hdb1] = 0x30;
buffer[offset_dab] = (byte)destAddress.getAddress();
buffer[offset_sab] = (byte)srcAddress.getAddress();
setLength(payload.length);
for(int i = 0; i < payload.length; i++)
buffer[i + offset_payload] = payload[i];
generateChecksum();
complete = true;
}
/**
*
*/
private void generateChecksum() {
int length = getLength() + offset_payload;
SNAPChecksum crc = new SNAPChecksum();
for(int i = 1; i < length; i++)
crc.addData(buffer[i]);
buffer[length] = crc.getResult();
}
/**
* @return the packet type
*/
public byte getPacketType() {
return buffer[0]; // TODO fix offset
}
/**
* @return the payload
*/
public byte [] getPayload() {
int length = getLength();
byte [] payload = new byte[length];
for(int i = 0; i < length; i++)
payload[i] = buffer[i + offset_payload];
return payload;
}
/**
* @return the raw data of the packet
*/
public byte [] getRawData() {
return buffer;
}
/**
*
* @param data
* @return true is the packet is now complete, otherwise false
* @throws IOException
*/
public boolean receiveByte(byte data) throws IOException {
if (complete)
throw new IOException("Received data beyond end of packet");
if (receiveLength >= maxSize)
throw new IOException("Received too much data");
buffer[receiveLength++] = data;
if (receiveLength > 4) {
int expectedLength = getLength() + offset_payload + 1;
if (receiveLength >= expectedLength)
return true;
}
return false;
}
/**
* @return true if the packet passed validation
*/
public boolean validate() {
if (receiveLength < offset_payload)
return false;
int expectedLength = getLength() + offset_payload + 1;
if (receiveLength != expectedLength)
return false;
SNAPChecksum crc = new SNAPChecksum();
for(int i = offset_hdb2; i < receiveLength - 1; i++)
crc.addData(buffer[i]);
byte expectedCRC = buffer[receiveLength - 1];
return crc.getResult() == expectedCRC;
}
/**
* @return the source address of the packet
*/
public SNAPAddress getSourceAddress() {
return new SNAPAddress(buffer[offset_sab]);
}
/**
* @return the destination address for the packet
*/
public SNAPAddress getDestinationAddress() {
return new SNAPAddress(buffer[offset_dab]);
}
/**
* @param length
*/
private void setLength(int length) {
buffer[offset_hdb1] = (byte)((buffer[offset_hdb1] & 0xf0) |
(length > 7 ? 8 : length));
}
/**
* @return the lenght of the packet
*/
public int getLength() {
int l = buffer[offset_hdb1] & 0x0f;
if ((l & 8) != 0)
return 8 << (l & 7);
return l;
}
/**
* @return NAK packet
*/
public SNAPPacket generateNAK() {
SNAPPacket resp = new SNAPPacket(getDestinationAddress(), getSourceAddress(), new byte [] {});
resp.buffer[offset_hdb2] = (byte)((resp.buffer[offset_hdb2] & 0xfc) | 3);
resp.generateChecksum();
return resp;
}
/**
* @return ACK packet
*/
public SNAPPacket generateACK() {
SNAPPacket resp = new SNAPPacket(getDestinationAddress(), getSourceAddress(), new byte [] {});
resp.buffer[offset_hdb2] = (byte)((resp.buffer[offset_hdb2] & 0xfc) | 2);
resp.generateChecksum();
return resp;
}
/**
* @return true if the packet represents an ACK
*/
public boolean isAck() {
return ((buffer[offset_hdb2] & 3) == 2);
}
/**
* @return true if the packet represents a NAK
*/
public boolean isNak() {
return ((buffer[offset_hdb2] & 3) == 3);
}
}