Network: Moved the Network message classes from the Utils package to the Messages package. Renamed BoatLocationMessage to BoatLocation and BoatStatusMessage to BoatStatus to be consistent with other message classes. Renamed the BoatStatus enumeration to BoatStatusEnum as it conflicted with BoatStatus (the message). Moved the BoatStatusEnum and MessageType enumerations from the Utils package to the Messages/Enums package. Changed the BoatStatusEnum and MessageType enumerations to use map look ups in the enum.fromByte(b) method - this means that there's less copy and pasted values, and the fromByte function doesn't need to be modified if new enumerations are added. Added a sequenceNumber member to the Heartbeat class. Added an InvalidMessageException in the package Networking/Exceptions. This is thrown when a message is read, but it is invalid in some way. Refactored/tidied up the Networking/BinaryMessageEncoder and Decoder classes. The decoder throws InvalidMessageExceptions instead of returning null. Visualiser: VisualiserInput now wraps a DataInputStream around the socket. This provides the stream.readFully(buffer) function, which is a blocking read, removing the need for busy wait loops. Replaced the getBytes() function with getNextMessage() and getNextMessageBytes(). These read the next message from the socket, and return it as a message object and a byte array, respectively. Changed the current heartbeat timeout to 10 seconds. Added some work-in-progress code to attempt to reconnect when connection is lost. It currently doesn't work. I think Fan-Wu was doing a proper implementation, however. VisualiserInput also has a queue of received events. Currently not really used, but could be useful in the future. Events get added as they are read. Changed VisualiserInputs main loop to use instanceOf instead of switch+case. Feedback wanted - are there any downsides to using this instanceOf method? #story[778,782]main
parent
466e22437b
commit
b247244665
@ -1,167 +1,281 @@
|
|||||||
package seng302.Networking;
|
package seng302.Networking;
|
||||||
|
|
||||||
|
import seng302.Networking.Exceptions.InvalidMessageException;
|
||||||
import seng302.Networking.MessageDecoders.*;
|
import seng302.Networking.MessageDecoders.*;
|
||||||
|
import seng302.Networking.Messages.*;
|
||||||
import seng302.Networking.Utils.*;
|
import seng302.Networking.Utils.*;
|
||||||
|
import seng302.Networking.Messages.Enums.MessageType;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by hba56 on 21/04/17.
|
* Created by hba56 on 21/04/17.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class can be used to decode/convert a byte array into a messageBody object, descended from AC35Data.
|
||||||
|
*/
|
||||||
public class BinaryMessageDecoder {
|
public class BinaryMessageDecoder {
|
||||||
|
|
||||||
|
///Length of the header.
|
||||||
|
private static final int headerLength = 15;
|
||||||
|
///Length of the CRC.
|
||||||
|
private static final int CRCLength = 4;//TODO these should probably be static defined somewhere else to be shared.
|
||||||
|
|
||||||
|
///The value the first sync byte should have.
|
||||||
|
private static final byte syncByte1 = (byte) 0x47;
|
||||||
|
//The value the second sync byte should have.
|
||||||
|
private static final byte syncByte2 = (byte) 0x83;
|
||||||
|
|
||||||
|
///The full message.
|
||||||
private byte[] fullMessage;
|
private byte[] fullMessage;
|
||||||
private byte[] header;
|
///The messageHeader.
|
||||||
private byte[] message;
|
private byte[] messageHeader;
|
||||||
private byte[] crc;
|
///The messageBody.
|
||||||
|
private byte[] messageBody;
|
||||||
|
|
||||||
|
///The sync bytes from the header..
|
||||||
private byte headerSync1;
|
private byte headerSync1;
|
||||||
private byte headerSync2;
|
private byte headerSync2;
|
||||||
|
|
||||||
|
///The message type from the header.
|
||||||
private byte headerMessageType;
|
private byte headerMessageType;
|
||||||
private byte[] headerTimeStamp;
|
|
||||||
private byte[] headerSourceID;
|
|
||||||
private byte[] headerMessageLength;
|
|
||||||
|
|
||||||
|
///The timestamp from the header.
|
||||||
|
private long headerTimeStamp;
|
||||||
|
|
||||||
|
///The source ID from the header.
|
||||||
|
private int headerSourceID;
|
||||||
|
|
||||||
|
///The message body length from the header.
|
||||||
|
private int messageBodyLength;
|
||||||
|
|
||||||
|
///CRC value read from message header.
|
||||||
|
private long messageCRCValue;
|
||||||
|
///Calculated CRC value from message.
|
||||||
|
private long calculatedCRCValue;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param fullMessage Entire encoded binary message.
|
||||||
|
*/
|
||||||
public BinaryMessageDecoder(byte[] fullMessage) {
|
public BinaryMessageDecoder(byte[] fullMessage) {
|
||||||
this.fullMessage = fullMessage;
|
this.fullMessage = fullMessage;
|
||||||
}
|
|
||||||
|
|
||||||
public AC35Data decode() throws IndexOutOfBoundsException{
|
//Get the messageHeader.
|
||||||
//get the header
|
this.messageHeader = Arrays.copyOfRange(this.fullMessage, 0, 15);
|
||||||
this.header = Arrays.copyOfRange(this.fullMessage, 0, 15);
|
|
||||||
|
|
||||||
this.headerSync1 = this.header[0];
|
//Get the sync bytes.
|
||||||
this.headerSync2 = this.header[1];
|
this.headerSync1 = this.messageHeader[0];
|
||||||
this.headerMessageType = this.header[2];
|
this.headerSync2 = this.messageHeader[1];
|
||||||
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){
|
//Get the message type.
|
||||||
//System.err.println("Message is too short.");
|
this.headerMessageType = this.messageHeader[2];
|
||||||
return null;
|
|
||||||
}
|
//Get the header timestamp.
|
||||||
//get message
|
this.headerTimeStamp = ByteConverter.bytesToLong(Arrays.copyOfRange(this.messageHeader, 3, 9));
|
||||||
this.message = Arrays.copyOfRange(this.fullMessage, 15, this.fullMessage.length - 4);
|
|
||||||
|
//Get the source ID for the message.
|
||||||
|
this.headerSourceID = ByteConverter.bytesToInt(Arrays.copyOfRange(this.messageHeader, 9, 13));
|
||||||
|
|
||||||
|
//Get the length of the message body.
|
||||||
|
this.messageBodyLength = ByteConverter.bytesToInt(Arrays.copyOfRange(this.messageHeader, 13, 15));
|
||||||
|
|
||||||
//get crc
|
|
||||||
this.crc = Arrays.copyOfRange(this.fullMessage, this.fullMessage.length - 4, fullMessage.length);
|
|
||||||
ByteBuffer bytes = ByteBuffer.allocate(this.header.length + this.message.length);
|
|
||||||
bytes.put(this.header);
|
|
||||||
bytes.put(this.message);
|
|
||||||
|
|
||||||
|
//Get the messageBody.
|
||||||
|
this.messageBody = Arrays.copyOfRange(this.fullMessage, this.headerLength, this.headerLength + this.messageBodyLength);
|
||||||
|
|
||||||
|
//Get the CRC value.
|
||||||
|
this.messageCRCValue = ByteConverter.bytesToLong(Arrays.copyOfRange(this.fullMessage, this.fullMessage.length - CRCLength, this.fullMessage.length));
|
||||||
|
|
||||||
|
//Combine the header and body into a single array.
|
||||||
|
ByteBuffer headerBodyByteBuffer = ByteBuffer.allocate(messageHeader.length + messageBody.length);
|
||||||
|
headerBodyByteBuffer.put(messageHeader);
|
||||||
|
headerBodyByteBuffer.put(messageBody);
|
||||||
|
|
||||||
|
//Calculate the CRC value from the header+body array.
|
||||||
CRC32 crc = new CRC32();
|
CRC32 crc = new CRC32();
|
||||||
crc.reset();
|
crc.reset();
|
||||||
crc.update(bytes.array(), 0, bytes.array().length);
|
crc.update(headerBodyByteBuffer.array());
|
||||||
|
this.calculatedCRCValue = crc.getValue();
|
||||||
//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);
|
* Decodes the byte array (binary message) this object was initialized with, and returns the corresponding message object.
|
||||||
return null;
|
* @return Message object corresponding to the binary message.
|
||||||
}else if(this.headerSync1 != 0x47){
|
* @throws InvalidMessageException If the message cannot be decoded.
|
||||||
System.err.println("Sync byte 1 is wrong: " + this.headerSync1);
|
*/
|
||||||
return null;
|
public AC35Data decode() throws InvalidMessageException {
|
||||||
}else if(this.headerSync2 !=(byte) 0x83){
|
|
||||||
System.err.println("Sync byte 2 is wrong: " + this.headerSync2);
|
//Run through the checks to ensure that the message is valid.
|
||||||
return null;
|
if (messageBody.length != messageBodyLength) {//keep like this - hba65
|
||||||
}else if(crc.getValue() != ByteConverter.bytesToLong(this.crc)){
|
//Check the message body length.
|
||||||
//todo check crc
|
throw new InvalidMessageException("MessageBody length in header does not equal the messageBody length. MessageBody length in header is: " + messageBodyLength + ", should be: " + messageBody.length);
|
||||||
System.err.println("CRC is not "+ByteConverter.bytesToLong(this.crc)+" and is instead:" + crc.getValue());
|
|
||||||
return null;
|
}else if (headerSync1 != syncByte1) {
|
||||||
|
//Check the first sync byte.
|
||||||
|
throw new InvalidMessageException("Sync byte 1 is wrong. Sync byte is: " + headerSync1 + ", should be: " + syncByte1);
|
||||||
|
|
||||||
|
}else if (headerSync2 != syncByte2) {
|
||||||
|
//Check the second sync byte.
|
||||||
|
throw new InvalidMessageException("Sync byte 2 is wrong. Sync byte is: " + headerSync2 + ", should be: " + syncByte2);
|
||||||
|
|
||||||
|
}else if (calculatedCRCValue != messageCRCValue) {
|
||||||
|
//Check the CRC value.
|
||||||
|
throw new InvalidMessageException("CRC value is wrong. The calculated value is: " + calculatedCRCValue + ", should be: " + messageCRCValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageType mType = MessageType.valueOf(this.headerMessageType);
|
//Now we create the message object based on what is actually in the message body.
|
||||||
AC35Data data = null;
|
MessageType mType = MessageType.fromByte(headerMessageType);
|
||||||
|
|
||||||
switch(mType) {
|
switch(mType) {
|
||||||
case HEARTBEAT:
|
case HEARTBEAT:
|
||||||
// System.out.println("HeartBeat Message!");
|
//System.out.println("Decoding HeartBeat Message!");
|
||||||
data = new Heartbeat();
|
//TODO maybe use HeartbeatDecoder.decode(message).
|
||||||
break;
|
//TODO also, decoders for each message type should encapsulate the constructing of the object. E.g., return HeartbeatDecoder.decode(message);.
|
||||||
|
return new Heartbeat(ByteConverter.bytesToLong(messageBody));
|
||||||
|
|
||||||
case RACESTATUS:
|
case RACESTATUS:
|
||||||
//System.out.println("Race Status Message");
|
//System.out.println("Race Status Message");
|
||||||
RaceStatusDecoder rsdecoder = new RaceStatusDecoder(this.message);
|
RaceStatusDecoder rsdecoder = new RaceStatusDecoder(messageBody);
|
||||||
data = new RaceStatus(rsdecoder.getTime(), rsdecoder.getRace(), rsdecoder.getRaceState(), rsdecoder.getStartTime(), rsdecoder.getRaceWindDir(), rsdecoder.getRaceWindSpeed(), rsdecoder.getRaceType(), rsdecoder.getBoats());
|
return new RaceStatus(rsdecoder.getTime(), rsdecoder.getRace(), rsdecoder.getRaceState(), rsdecoder.getStartTime(), rsdecoder.getRaceWindDir(), rsdecoder.getRaceWindSpeed(), rsdecoder.getRaceType(), rsdecoder.getBoats());
|
||||||
break;
|
|
||||||
case DISPLAYTEXTMESSAGE:
|
case DISPLAYTEXTMESSAGE:
|
||||||
//System.out.println("Display Text Message");
|
//System.out.println("Display Text Message");
|
||||||
//no decoder for this.
|
//No decoder for this.
|
||||||
break;
|
throw new InvalidMessageException("Cannot decode DISPLAYTEXTMESSAGE - no decoder.");
|
||||||
|
|
||||||
case XMLMESSAGE:
|
case XMLMESSAGE:
|
||||||
//System.out.println("XML Message!");
|
//System.out.println("XML Message!");
|
||||||
XMLMessageDecoder xmdecoder = new XMLMessageDecoder(this.message);
|
XMLMessageDecoder xmdecoder = new XMLMessageDecoder(messageBody);
|
||||||
xmdecoder.decode();
|
xmdecoder.decode();
|
||||||
data = new XMLMessage(xmdecoder.getAckNumber(), xmdecoder.getTimeStamp(), xmdecoder.getXmlMsgSubType(), xmdecoder.getSequenceNumber(), xmdecoder.getXmlMsgLength(), xmdecoder.getXmlMessageInputStream());
|
return new XMLMessage(xmdecoder.getAckNumber(), xmdecoder.getTimeStamp(), xmdecoder.getXmlMsgSubType(), xmdecoder.getSequenceNumber(), xmdecoder.getXmlMsgLength(), xmdecoder.getXmlMessageInputStream());
|
||||||
break;
|
|
||||||
case RACESTARTSTATUS:
|
case RACESTARTSTATUS:
|
||||||
//System.out.println("Race Start Status Message");
|
//System.out.println("Race Start Status Message");
|
||||||
RaceStartStatusDecoder rssDecoder = new RaceStartStatusDecoder(this.message);
|
RaceStartStatusDecoder rssDecoder = new RaceStartStatusDecoder(messageBody);
|
||||||
data = new RaceStartStatus(rssDecoder.getTime(), rssDecoder.getAck(), rssDecoder.getStartTime(), rssDecoder.getRaceID(), rssDecoder. getNotification());
|
return new RaceStartStatus(rssDecoder.getTime(), rssDecoder.getAck(), rssDecoder.getStartTime(), rssDecoder.getRaceID(), rssDecoder. getNotification());
|
||||||
break;
|
|
||||||
case YACHTEVENTCODE:
|
case YACHTEVENTCODE:
|
||||||
//System.out.println("Yacht Action Code!");
|
//System.out.println("Yacht Action Code!");
|
||||||
//no decoder
|
//No decoder for this.
|
||||||
break;
|
throw new InvalidMessageException("Cannot decode YACHTEVENTCODE - no decoder.");
|
||||||
|
|
||||||
case YACHTACTIONCODE:
|
case YACHTACTIONCODE:
|
||||||
//System.out.println("Yacht Action Code!");
|
//System.out.println("Yacht Action Code!");
|
||||||
//no decoder
|
//No decoder for this.
|
||||||
break;
|
throw new InvalidMessageException("Cannot decode YACHTACTIONCODE - no decoder.");
|
||||||
|
|
||||||
case CHATTERTEXT:
|
case CHATTERTEXT:
|
||||||
//System.out.println("Chatter Text Message!");
|
//System.out.println("Chatter Text Message!");
|
||||||
//no decoder
|
//No decoder for this.
|
||||||
break;
|
throw new InvalidMessageException("Cannot decode CHATTERTEXT - no decoder.");
|
||||||
|
|
||||||
case BOATLOCATION:
|
case BOATLOCATION:
|
||||||
//System.out.println("Boat Location Message!");
|
//System.out.println("Boat Location Message!");
|
||||||
BoatLocationDecoder blDecoder = new BoatLocationDecoder(this.message);
|
BoatLocationDecoder blDecoder = new BoatLocationDecoder(messageBody);
|
||||||
data = blDecoder.getMessage();
|
return blDecoder.getMessage();
|
||||||
break;
|
|
||||||
case MARKROUNDING:
|
case MARKROUNDING:
|
||||||
//System.out.println("Mark Rounding Message!");
|
//System.out.println("Mark Rounding Message!");
|
||||||
MarkRoundingDecoder mrDecoder = new MarkRoundingDecoder(this.message);
|
MarkRoundingDecoder mrDecoder = new MarkRoundingDecoder(messageBody);
|
||||||
data = mrDecoder.getMarkRounding();
|
return mrDecoder.getMarkRounding();
|
||||||
break;
|
|
||||||
case COURSEWIND:
|
case COURSEWIND:
|
||||||
//System.out.println("Couse Wind Message!");
|
//System.out.println("Couse Wind Message!");
|
||||||
CourseWindDecoder cwDecoder = new CourseWindDecoder(this.message);
|
CourseWindDecoder cwDecoder = new CourseWindDecoder(messageBody);
|
||||||
data =new CourseWinds(cwDecoder.getMessageVersionNumber(), cwDecoder.getByteWindID(), cwDecoder.getLoopMessages());
|
return new CourseWinds(cwDecoder.getMessageVersionNumber(), cwDecoder.getByteWindID(), cwDecoder.getLoopMessages());
|
||||||
break;
|
|
||||||
case AVGWIND:
|
case AVGWIND:
|
||||||
//System.out.println("Average Wind Message!");
|
//System.out.println("Average Wind Message!");
|
||||||
AverageWindDecoder awDecoder = new AverageWindDecoder(this.message);
|
AverageWindDecoder awDecoder = new AverageWindDecoder(messageBody);
|
||||||
data = awDecoder.getAverageWind();
|
return awDecoder.getAverageWind();
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
//System.out.println("Broken Message!");
|
//System.out.println("Broken Message!");
|
||||||
break;
|
throw new InvalidMessageException("Broken message! Did not recognise message type: " + headerMessageType + ".");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public long getTimeStamp() {
|
/**
|
||||||
return ByteConverter.bytesToLong(this.headerTimeStamp);
|
* Returns the first sync byte value.
|
||||||
|
* @return The first sync byte value.
|
||||||
|
*/
|
||||||
|
public byte getHeaderSync1() {
|
||||||
|
return headerSync1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSourceID() {
|
/**
|
||||||
return ByteConverter.bytesToInt(this.headerSourceID, ByteOrder.BIG_ENDIAN);
|
* Returns the second sync byte value.
|
||||||
|
* @return The second sync byte value.
|
||||||
|
*/
|
||||||
|
public byte getHeaderSync2() {
|
||||||
|
return headerSync2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getMessageLength() {
|
/**
|
||||||
return ByteConverter.bytesToShort(this.headerMessageLength);
|
* Returns the message type.
|
||||||
|
* @return The message type.
|
||||||
|
*/
|
||||||
|
public byte getHeaderMessageType() {
|
||||||
|
return headerMessageType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMessageType(){
|
/**
|
||||||
return (int) this.headerMessageType;
|
* Returns the header timestamp.
|
||||||
|
* @return The header timestamp.
|
||||||
|
*/
|
||||||
|
public long getHeaderTimeStamp() {
|
||||||
|
return headerTimeStamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getMessage() {
|
/**
|
||||||
return message;
|
* Returns the header source ID.
|
||||||
|
* @return The header source ID.
|
||||||
|
*/
|
||||||
|
public int getHeaderSourceID() {
|
||||||
|
return headerSourceID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the message body length, according to the header.
|
||||||
|
* @return The message body length.
|
||||||
|
*/
|
||||||
|
public int getMessageBodyLength() {
|
||||||
|
return messageBodyLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the message CRC value, according to the header.
|
||||||
|
* @return The message CRC value.
|
||||||
|
*/
|
||||||
|
public long getMessageCRCValue() {
|
||||||
|
return messageCRCValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the calculated CRC value from the message header + body contents.
|
||||||
|
* @return The calculated CRC value.
|
||||||
|
*/
|
||||||
|
public long getCalculatedCRCValue() {
|
||||||
|
return calculatedCRCValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the message body.
|
||||||
|
* @return The message body.
|
||||||
|
*/
|
||||||
|
public byte[] getMessageBody() {
|
||||||
|
return messageBody;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
package seng302.Networking.Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by f123 on 07-May-17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception which is thrown when a message is read, but it is invalid in some way (CRC is wrong, sync bytes, etc...).
|
||||||
|
*/
|
||||||
|
public class InvalidMessageException extends Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param message String message.
|
||||||
|
*/
|
||||||
|
public InvalidMessageException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param message String message.
|
||||||
|
* @param cause Cause of the exception.
|
||||||
|
*/
|
||||||
|
public InvalidMessageException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package seng302.Networking.Messages;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by fwy13 on 25/04/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import seng302.Networking.Messages.Enums.MessageType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base class for all message types.
|
||||||
|
*/
|
||||||
|
public abstract class AC35Data {
|
||||||
|
|
||||||
|
///Message type from the header.
|
||||||
|
private MessageType type;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param type The concrete type of this message.
|
||||||
|
*/
|
||||||
|
public AC35Data (MessageType type){
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The concrete type of message this is.
|
||||||
|
* @return The type of message this is.
|
||||||
|
*/
|
||||||
|
public MessageType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,6 @@
|
|||||||
package seng302.Networking.Utils;
|
package seng302.Networking.Messages;
|
||||||
|
|
||||||
|
import seng302.Networking.Messages.Enums.MessageType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by fwy13 on 25/04/17.
|
* Created by fwy13 on 25/04/17.
|
||||||
@ -1,4 +1,6 @@
|
|||||||
package seng302.Networking.Utils;
|
package seng302.Networking.Messages;
|
||||||
|
|
||||||
|
import seng302.Networking.Messages.Enums.MessageType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by fwy13 on 21/04/17.
|
* Created by fwy13 on 21/04/17.
|
||||||
@ -1,4 +1,6 @@
|
|||||||
package seng302.Networking.Utils;
|
package seng302.Networking.Messages;
|
||||||
|
|
||||||
|
import seng302.Networking.Messages.Enums.MessageType;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
package seng302.Networking.Messages.Enums;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by esa46 on 28/04/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration that encapsulates the various statuses a boat can have.
|
||||||
|
*/
|
||||||
|
public enum BoatStatusEnum {
|
||||||
|
UNDEFINED(0),
|
||||||
|
PRESTART(1),
|
||||||
|
RACING(2),
|
||||||
|
FINISHED(3),
|
||||||
|
DNS(4),
|
||||||
|
DNF(5),
|
||||||
|
DSQ(6),
|
||||||
|
OCS(7),
|
||||||
|
NOT_A_STATUS(-1);
|
||||||
|
|
||||||
|
///Primitive value of the enum.
|
||||||
|
private byte value;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor. Creates a BoatStatusEnum from a given primitive integer value, cast to a byte.
|
||||||
|
* @param value Integer, which is cast to byte, to construct from.
|
||||||
|
*/
|
||||||
|
private BoatStatusEnum(int value) {
|
||||||
|
this.value = (byte)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the primitive value of the enum.
|
||||||
|
* @return Primitive value of the enum.
|
||||||
|
*/
|
||||||
|
public byte getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///Stores a mapping between Byte values and BoatStatusEnum values.
|
||||||
|
private static final Map<Byte, BoatStatusEnum> byteToStatusMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static initialization block. Initializes the byteToStatusMap.
|
||||||
|
*/
|
||||||
|
static {
|
||||||
|
for (BoatStatusEnum type : BoatStatusEnum.values()) {
|
||||||
|
byteToStatusMap.put(type.value, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the enumeration value which corresponds to a given byte value.
|
||||||
|
* @param boatStatusByte Byte value to convert to a BoatStatusEnum value.
|
||||||
|
* @return The BoatStatusEnum value which corresponds to the given byte value.
|
||||||
|
*/
|
||||||
|
public static BoatStatusEnum fromByte(byte boatStatusByte) {
|
||||||
|
//Gets the corresponding MessageType from the map.
|
||||||
|
BoatStatusEnum type = byteToStatusMap.get(boatStatusByte);
|
||||||
|
|
||||||
|
if (type == null) {
|
||||||
|
//If the byte value wasn't found, return the NOT_A_STATUS BoatStatusEnum.
|
||||||
|
return BoatStatusEnum.NOT_A_STATUS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//Otherwise, return the BoatStatusEnum.
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
package seng302.Networking.Messages.Enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by hba56 on 21/04/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration that encapsulates the various types of messages that can be sent.
|
||||||
|
*/
|
||||||
|
public enum MessageType {
|
||||||
|
HEARTBEAT(1),
|
||||||
|
RACESTATUS(12),
|
||||||
|
DISPLAYTEXTMESSAGE(20),
|
||||||
|
XMLMESSAGE(26),
|
||||||
|
RACESTARTSTATUS(27),
|
||||||
|
YACHTEVENTCODE(29),
|
||||||
|
YACHTACTIONCODE(31),
|
||||||
|
CHATTERTEXT(36),
|
||||||
|
BOATLOCATION(37),
|
||||||
|
MARKROUNDING(38),
|
||||||
|
COURSEWIND(44),
|
||||||
|
AVGWIND(47),
|
||||||
|
NOTAMESSAGE(0);
|
||||||
|
|
||||||
|
///Primitive value of the enum.
|
||||||
|
private byte value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor. Creates a MessageType enum from a given primitive integer value, cast to a byte.
|
||||||
|
* @param value Integer, which is cast to byte, to construct from.
|
||||||
|
*/
|
||||||
|
private MessageType(int value) {
|
||||||
|
this.value = (byte)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the primitive value of the enum.
|
||||||
|
* @return Primitive value of the enum.
|
||||||
|
*/
|
||||||
|
public byte getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///Stores a mapping between Byte values and MessageType values.
|
||||||
|
private static final Map<Byte, MessageType> byteToTypeMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static initialization block. Initializes the byteToTypeMap.
|
||||||
|
*/
|
||||||
|
static {
|
||||||
|
for (MessageType type : MessageType.values()) {
|
||||||
|
byteToTypeMap.put(type.value, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the enumeration value which corresponds to a given byte value.
|
||||||
|
* @param messageTypeByte Byte value to convert to a MessageType value.
|
||||||
|
* @return The MessageType value which corresponds to the given byte value.
|
||||||
|
*/
|
||||||
|
public static MessageType fromByte(byte messageTypeByte) {
|
||||||
|
//Gets the corresponding MessageType from the map.
|
||||||
|
MessageType type = byteToTypeMap.get(messageTypeByte);
|
||||||
|
|
||||||
|
if (type == null) {
|
||||||
|
//If the byte value wasn't found, return the NOTAMESSAGE MessageType.
|
||||||
|
return MessageType.NOTAMESSAGE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//Otherwise, return the MessageType.
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package seng302.Networking.Messages;
|
||||||
|
|
||||||
|
import seng302.Networking.Messages.Enums.MessageType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by fwy13 on 25/04/17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a Heartbeat message.
|
||||||
|
*/
|
||||||
|
public class Heartbeat extends AC35Data {
|
||||||
|
|
||||||
|
///Sequence number of the heartbeat.
|
||||||
|
private long sequenceNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ctor.
|
||||||
|
* @param sequenceNumber Sequence number of the heartbeat.
|
||||||
|
*/
|
||||||
|
public Heartbeat(long sequenceNumber) {
|
||||||
|
super(MessageType.HEARTBEAT);
|
||||||
|
this.sequenceNumber = sequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sequence number of this heartbeat message.
|
||||||
|
* @return Sequence number of this heartbeat message.
|
||||||
|
*/
|
||||||
|
public long getSequenceNumber() {
|
||||||
|
return sequenceNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,6 @@
|
|||||||
package seng302.Networking.Utils;
|
package seng302.Networking.Messages;
|
||||||
|
|
||||||
|
import seng302.Networking.Messages.Enums.MessageType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by fwy13 on 19/04/17.
|
* Created by fwy13 on 19/04/17.
|
||||||
@ -1,11 +1,12 @@
|
|||||||
package seng302.Networking.Utils;
|
package seng302.Networking.Messages;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import seng302.Networking.Messages.Enums.MessageType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by fwy13 on 25/04/17.
|
* Created by fwy13 on 25/04/17.
|
||||||
*/
|
*/
|
||||||
public class RaceStartStatus extends AC35Data {
|
public class RaceStartStatus extends AC35Data {
|
||||||
|
|
||||||
private long timestamp;
|
private long timestamp;
|
||||||
private int ackNum;
|
private int ackNum;
|
||||||
private long raceStartTime;
|
private long raceStartTime;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package seng302.Networking.Utils;
|
package seng302.Networking.Messages;
|
||||||
|
|
||||||
import org.xml.sax.InputSource;
|
import seng302.Networking.Messages.Enums.MessageType;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
package seng302.Networking.Utils;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by fwy13 on 25/04/17.
|
|
||||||
*/
|
|
||||||
public abstract class AC35Data {
|
|
||||||
|
|
||||||
protected MessageType type;
|
|
||||||
|
|
||||||
public AC35Data (MessageType type){
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageType getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
package seng302.Networking.Utils.Enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by esa46 on 28/04/17.
|
|
||||||
*/
|
|
||||||
public enum BoatStatus {
|
|
||||||
|
|
||||||
UNDEFINED(0), PRESTART(1), RACING(2), FINISHED(3), DNS(4), DNF(5), DSQ(6), OCS(7), NOT_A_STATUS(-1);
|
|
||||||
|
|
||||||
private byte value;
|
|
||||||
|
|
||||||
private BoatStatus(int value) { this.value = (byte)value; }
|
|
||||||
|
|
||||||
public byte getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BoatStatus valueOf(byte bite){
|
|
||||||
switch(bite){
|
|
||||||
case 0:
|
|
||||||
return UNDEFINED;
|
|
||||||
case 1:
|
|
||||||
return PRESTART;
|
|
||||||
case 2:
|
|
||||||
return RACING;
|
|
||||||
case 3:
|
|
||||||
return FINISHED;
|
|
||||||
case 4:
|
|
||||||
return DNS;
|
|
||||||
case 5:
|
|
||||||
return DNF;
|
|
||||||
case 6:
|
|
||||||
return DSQ;
|
|
||||||
case 7:
|
|
||||||
return OCS;
|
|
||||||
default:
|
|
||||||
return NOT_A_STATUS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
package seng302.Networking.Utils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by fwy13 on 25/04/17.
|
|
||||||
*/
|
|
||||||
public class Heartbeat extends AC35Data{
|
|
||||||
|
|
||||||
public Heartbeat(){
|
|
||||||
super(MessageType.HEARTBEAT);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
package seng302.Networking.Utils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by hba56 on 21/04/17.
|
|
||||||
*/
|
|
||||||
public enum MessageType {
|
|
||||||
HEARTBEAT(1), RACESTATUS(12), DISPLAYTEXTMESSAGE(20),
|
|
||||||
XMLMESSAGE(26), RACESTARTSTATUS(27), YACHTEVENTCODE(29), YACHTACTIONCODE(31),
|
|
||||||
CHATTERTEXT(36), BOATLOCATION(37), MARKROUNDING(38), COURSEWIND(44), AVGWIND(47), NOTAMESSAGE(0);
|
|
||||||
|
|
||||||
private byte value;
|
|
||||||
|
|
||||||
private MessageType(int value) { this.value = (byte)value; }
|
|
||||||
|
|
||||||
public byte getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MessageType valueOf(byte bite){
|
|
||||||
switch(bite){
|
|
||||||
case 1:
|
|
||||||
return HEARTBEAT;
|
|
||||||
case 12:
|
|
||||||
return RACESTATUS;
|
|
||||||
case 20:
|
|
||||||
return DISPLAYTEXTMESSAGE;
|
|
||||||
case 26:
|
|
||||||
return XMLMESSAGE;
|
|
||||||
case 27:
|
|
||||||
return RACESTARTSTATUS;
|
|
||||||
case 29:
|
|
||||||
return YACHTEVENTCODE;
|
|
||||||
case 31:
|
|
||||||
return YACHTACTIONCODE;
|
|
||||||
case 36:
|
|
||||||
return CHATTERTEXT;
|
|
||||||
case 37:
|
|
||||||
return BOATLOCATION;
|
|
||||||
case 38:
|
|
||||||
return MARKROUNDING;
|
|
||||||
case 44:
|
|
||||||
return COURSEWIND;
|
|
||||||
case 47:
|
|
||||||
return AVGWIND;
|
|
||||||
default:
|
|
||||||
return NOTAMESSAGE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in new issue