You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
7.6 KiB
212 lines
7.6 KiB
package seng302.Networking;
|
|
|
|
import seng302.Networking.MessageDecoders.*;
|
|
import seng302.Networking.Utils.*;
|
|
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.util.Arrays;
|
|
import java.util.zip.CRC32;
|
|
|
|
/**
|
|
* Created by hba56 on 21/04/17.
|
|
*/
|
|
public class BinaryMessageDecoder {
|
|
private byte[] fullMessage;
|
|
private byte[] header;
|
|
private byte[] message;
|
|
private byte[] crc;
|
|
|
|
private byte headerSync1;
|
|
private byte headerSync2;
|
|
private byte headerMessageType;
|
|
private byte[] headerTimeStamp;
|
|
private byte[] headerSourceID;
|
|
private byte[] headerMessageLength;
|
|
|
|
|
|
public BinaryMessageDecoder(byte[] fullMessage) {
|
|
this.fullMessage = fullMessage;
|
|
}
|
|
|
|
public AC35Data decode() throws IndexOutOfBoundsException{
|
|
//get the header
|
|
this.header = Arrays.copyOfRange(this.fullMessage, 0, 15);
|
|
|
|
this.headerSync1 = this.header[0];
|
|
this.headerSync2 = this.header[1];
|
|
this.headerMessageType = this.header[2];
|
|
this.headerTimeStamp = Arrays.copyOfRange(this.header, 3, 9);
|
|
this.headerSourceID = Arrays.copyOfRange(this.header, 9, 13);
|
|
this.headerMessageLength = Arrays.copyOfRange(this.header, 13, 15);
|
|
|
|
if (15 > this.fullMessage.length - 4){
|
|
//System.err.println("Message is too short.");
|
|
return null;
|
|
}
|
|
//get message
|
|
this.message = Arrays.copyOfRange(this.fullMessage, 15, this.fullMessage.length - 4);
|
|
|
|
//get crc
|
|
this.crc = Arrays.copyOfRange(this.fullMessage, this.fullMessage.length - 4, fullMessage.length);
|
|
|
|
|
|
CRC32 crc = new CRC32();
|
|
crc.reset();
|
|
crc.update(this.fullMessage);
|
|
|
|
//run through the checks
|
|
if (this.message.length != twoByteToInt(this.headerMessageLength) && this.message.length != twoByteToIntBE(this.headerMessageLength)){
|
|
System.err.println("message length in header does not equal the message length");
|
|
System.err.println("message length in header: " + twoByteToInt(this.headerMessageLength));
|
|
System.err.println("message length: " + this.message.length);
|
|
return null;
|
|
}else if(this.headerSync1 != 0x47){
|
|
System.err.println("Sync byte 1 is wrong");
|
|
return null;
|
|
}else if(this.headerSync2 !=(byte) 0x83){
|
|
System.err.println("Sync byte 2 is wrong");
|
|
return null;
|
|
}/*else if(crc.getValue() != 0){
|
|
//todo check crc
|
|
System.err.println("CRC is not 0 and is instead:" + crc.getValue());
|
|
return;
|
|
}*/
|
|
|
|
MessageType mType = MessageType.valueOf(this.headerMessageType);
|
|
AC35Data data = null;
|
|
|
|
switch(mType){
|
|
case HEARTBEAT:
|
|
System.out.println("HeartBeat Message!");
|
|
data = new Heartbeat();
|
|
break;
|
|
case RACESTATUS:
|
|
System.out.println("Race Status Message");
|
|
RaceStatusDecoder rsdecoder = new RaceStatusDecoder(this.message);
|
|
data = new RaceStatus(rsdecoder.getTime(), rsdecoder.getRace(), rsdecoder.getRaceState(), rsdecoder.getStartTime(), rsdecoder.getRaceWindDir(), rsdecoder.getRaceWindSpeed(), rsdecoder.getRaceType(), rsdecoder.getBoats());
|
|
break;
|
|
case DISPLAYTEXTMESSAGE:
|
|
System.out.println("Display Text Message");
|
|
//no decoder for this.
|
|
break;
|
|
case XMLMESSAGE:
|
|
System.out.println("XML Message!");
|
|
XMLMessageDecoder xmdecoder = new XMLMessageDecoder(this.message);
|
|
xmdecoder.decode();
|
|
data = new XMLMessage(xmdecoder.getAckNumber(), xmdecoder.getTimeStamp(), xmdecoder.getXmlMsgSubType(), xmdecoder.getSequenceNumber(), xmdecoder.getXmlMsgLength(), xmdecoder.getXmlMessageInputSource());
|
|
break;
|
|
case RACESTARTSTATUS:
|
|
System.out.println("Race Start Status Message");
|
|
RaceStartStatusDecoder rssDecoder = new RaceStartStatusDecoder(this.message);
|
|
data = new RaceStartStatus(rssDecoder.getTime(), rssDecoder.getAck(), rssDecoder.getStartTime(), rssDecoder.getRaceID(), rssDecoder. getNotification());
|
|
break;
|
|
case YACHTEVENTCODE:
|
|
System.out.println("Yacht Action Code!");
|
|
//no decoder
|
|
break;
|
|
case YACHTACTIONCODE:
|
|
System.out.println("Yacht Action Code!");
|
|
//no decoder
|
|
break;
|
|
case CHATTERTEXT:
|
|
System.out.println("Chatter Text Message!");
|
|
//no decoder
|
|
break;
|
|
case BOATLOCATION:
|
|
System.out.println("Boat Location Message!");
|
|
BoatLocationDecoder blDecoder = new BoatLocationDecoder(this.message);
|
|
data = blDecoder.getMessage();
|
|
break;
|
|
case MARKROUNDING:
|
|
System.out.println("Mark Rounding Message!");
|
|
MarkRoundingDecoder mrDecoder = new MarkRoundingDecoder(this.message);
|
|
data = mrDecoder.getMarkRounding();
|
|
break;
|
|
case COURSEWIND:
|
|
System.out.println("Couse Wind Message!");
|
|
CourseWindDecoder cwDecoder = new CourseWindDecoder(this.message);
|
|
data =new CourseWinds(cwDecoder.getMessageVersionNumber(), cwDecoder.getByteWindID(), cwDecoder.getLoopMessages());
|
|
break;
|
|
case AVGWIND:
|
|
System.out.println("Average Wind Message!");
|
|
AverageWindDecoder awDecoder = new AverageWindDecoder(this.message);
|
|
data = awDecoder.getAverageWind();
|
|
break;
|
|
default:
|
|
System.out.println("Broken Message!");
|
|
break;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
private short bytesToShort(byte[] bytesShort){
|
|
ByteBuffer wrapped = ByteBuffer.wrap(bytesShort);
|
|
short num = wrapped.getShort();
|
|
return num;
|
|
}
|
|
|
|
private int bytesToInt(byte[] bytesInt){
|
|
ByteBuffer wrapped = ByteBuffer.wrap(bytesInt);
|
|
int num = wrapped.getInt();
|
|
return num;
|
|
}
|
|
|
|
private int twoByteToInt(byte[] bytesInt){
|
|
byte[] bytes = new byte[2];
|
|
bytes[1] = bytesInt[0];
|
|
bytes[0] = bytesInt[1];
|
|
int num = ByteBuffer.wrap(bytes).getShort();
|
|
|
|
return num;
|
|
}
|
|
|
|
private int twoByteToIntBE(byte[] bytesInt){
|
|
ByteBuffer byteBuffer = ByteBuffer.allocate(4);
|
|
byteBuffer.order(ByteOrder.BIG_ENDIAN);
|
|
byteBuffer.put((byte)0);
|
|
byteBuffer.put((byte)0);
|
|
byteBuffer.put(bytesInt);
|
|
int num = byteBuffer.getInt(0);
|
|
return num;
|
|
}
|
|
|
|
private long bytesToLong(byte[] bytesLong){
|
|
ByteBuffer byteBuffer = ByteBuffer.allocate(8);
|
|
byteBuffer.order(ByteOrder.BIG_ENDIAN);
|
|
byteBuffer.put((byte)0);
|
|
byteBuffer.put((byte)0);
|
|
byteBuffer.put(bytesLong[0]);
|
|
byteBuffer.put(bytesLong[1]);
|
|
byteBuffer.put(bytesLong[2]);
|
|
byteBuffer.put(bytesLong[3]);
|
|
byteBuffer.put(bytesLong[4]);
|
|
byteBuffer.put(bytesLong[5]);
|
|
long longVal = byteBuffer.getLong(0);
|
|
return longVal;
|
|
}
|
|
|
|
public long getTimeStamp() {
|
|
return bytesToLong(this.headerTimeStamp);
|
|
}
|
|
|
|
public int getSourceID() {
|
|
return bytesToInt(this.headerSourceID);
|
|
}
|
|
|
|
public short getMessageLength() {
|
|
return bytesToShort(this.headerMessageLength);
|
|
}
|
|
|
|
public int getMessageType(){
|
|
return (int) this.headerMessageType;
|
|
}
|
|
|
|
public byte[] getMessage() {
|
|
return message;
|
|
}
|
|
}
|
|
|