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