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 != ByteConverter.bytesToShort(this.headerMessageLength)){//keep like this - hba65 System.err.println("message length in header does not equal the message length"); System.err.println("message length in header: " + ByteConverter.bytesToInt(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: " + this.headerSync1); return null; }else if(this.headerSync2 !=(byte) 0x83){ System.err.println("Sync byte 2 is wrong: " + this.headerSync2); 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; } public long getTimeStamp() { return ByteConverter.bytesToLong(this.headerTimeStamp); } public int getSourceID() { return ByteConverter.bytesToInt(this.headerSourceID, ByteOrder.BIG_ENDIAN); } public short getMessageLength() { return ByteConverter.bytesToShort(this.headerMessageLength); } public int getMessageType(){ return (int) this.headerMessageType; } public byte[] getMessage() { return message; } }