The message encoders and decoders now catch exceptions, and throw InvalidMessageException.

Removed the big switch statement from BinaryMessageDecoder - it now uses the decoder factory instead.
issue #35 #36
#story[1095]
This commit is contained in:
fjc40
2017-08-06 22:25:43 +12:00
parent 9c64b678e3
commit 134586f407
34 changed files with 879 additions and 719 deletions
@@ -17,42 +17,71 @@ import java.util.zip.CRC32;
*/ */
public class BinaryMessageDecoder { public class BinaryMessageDecoder {
///Length of the header. /**
* Length of the header.
*/
private static final int headerLength = 15; 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. * Length of the CRC.
*/
private static final int CRCLength = 4;
///The value the first sync byte should have. /**
* The value the first sync byte should have.
*/
private static final byte syncByte1 = (byte) 0x47; private static final byte syncByte1 = (byte) 0x47;
//The value the second sync byte should have. /**
* The value the second sync byte should have.
*/
private static final byte syncByte2 = (byte) 0x83; private static final byte syncByte2 = (byte) 0x83;
///The full message. /**
* The full message.
*/
private byte[] fullMessage; private byte[] fullMessage;
///The messageHeader. /**
* The messageHeader.
*/
private byte[] messageHeader; private byte[] messageHeader;
///The messageBody. /**
* The messageBody.
*/
private byte[] messageBody; private byte[] messageBody;
///The sync bytes from the header.. /**
* The sync bytes from the header.
*/
private byte headerSync1; private byte headerSync1;
private byte headerSync2; private byte headerSync2;
///The message type from the header. /**
* The message type from the header.
*/
private byte headerMessageType; private byte headerMessageType;
///The timestamp from the header. /**
* The timestamp from the header.
*/
private long headerTimeStamp; private long headerTimeStamp;
///The source ID from the header. /**
* The source ID from the header.
*/
private int headerSourceID; private int headerSourceID;
///The message body length from the header. /**
* The message body length from the header.
*/
private int messageBodyLength; private int messageBodyLength;
///CRC value read from message header. /**
* CRC value read from message header.
*/
private long messageCRCValue; private long messageCRCValue;
///Calculated CRC value from message.
/**
* Calculated CRC value from message.
*/
private long calculatedCRCValue; private long calculatedCRCValue;
@@ -114,104 +143,34 @@ public class BinaryMessageDecoder {
//Check the message body length. //Check the message body length.
throw new InvalidMessageException("MessageBody length in header does not equal the messageBody length. MessageBody length in header is: " + messageBodyLength + ", should be: " + messageBody.length); throw new InvalidMessageException("MessageBody length in header does not equal the messageBody length. MessageBody length in header is: " + messageBodyLength + ", should be: " + messageBody.length);
}else if (headerSync1 != syncByte1) { } else if (headerSync1 != syncByte1) {
//Check the first sync byte. //Check the first sync byte.
throw new InvalidMessageException("Sync byte 1 is wrong. Sync byte is: " + headerSync1 + ", should be: " + syncByte1); throw new InvalidMessageException("Sync byte 1 is wrong. Sync byte is: " + headerSync1 + ", should be: " + syncByte1);
}else if (headerSync2 != syncByte2) { } else if (headerSync2 != syncByte2) {
//Check the second sync byte. //Check the second sync byte.
throw new InvalidMessageException("Sync byte 2 is wrong. Sync byte is: " + headerSync2 + ", should be: " + syncByte2); throw new InvalidMessageException("Sync byte 2 is wrong. Sync byte is: " + headerSync2 + ", should be: " + syncByte2);
}else if (calculatedCRCValue != messageCRCValue) { } else if (calculatedCRCValue != messageCRCValue) {
//Check the CRC value. //Check the CRC value.
throw new InvalidMessageException("CRC value is wrong. The calculated value is: " + calculatedCRCValue + ", should be: " + messageCRCValue); throw new InvalidMessageException("CRC value is wrong. The calculated value is: " + calculatedCRCValue + ", should be: " + messageCRCValue);
} }
//Now we create the message object based on what is actually in the message body. //Now we create the message object based on what is actually in the message body.
MessageType mType = MessageType.fromByte(headerMessageType); MessageType messageType = MessageType.fromByte(headerMessageType);
/*MessageDecoder decoder = null; MessageDecoder decoder = null;
try { try {
decoder = DecoderFactory.create(mType); decoder = DecoderFactory.create(messageType);
} catch (InvalidMessageTypeException e) { } catch (InvalidMessageTypeException e) {
throw new InvalidMessageException("Could not create decoder for MessageType: " + mType, e); throw new InvalidMessageException("Could not create decoder for MessageType: " + messageType, e);
}
return decoder.decode(messageBody);*/
switch(mType) {
case HEARTBEAT:
//System.out.println("Decoding HeartBeat Message!");
HeartBeatDecoder heartBeatDecoder = new HeartBeatDecoder();
return heartBeatDecoder.decode(messageBody);
case RACESTATUS:
//System.out.println("Race Status Message");
RaceStatusDecoder rsdecoder = new RaceStatusDecoder();
return rsdecoder.decode(messageBody);
case DISPLAYTEXTMESSAGE:
//System.out.println("Display Text Message");
//No decoder for this.
//throw new InvalidMessageException("Cannot decode DISPLAYTEXTMESSAGE - no decoder.");
case XMLMESSAGE:
//System.out.println("XML Message!");
XMLMessageDecoder xmdecoder = new XMLMessageDecoder();
return xmdecoder.decode(messageBody);
case RACESTARTSTATUS:
//System.out.println("Race Start Status Message");
RaceStartStatusDecoder rssDecoder = new RaceStartStatusDecoder();
return rssDecoder.decode(messageBody);
case YACHTEVENTCODE:
//System.out.println("Yacht Action Code!");
//No decoder for this.
//throw new InvalidMessageException("Cannot decode YACHTEVENTCODE - no decoder.");
case YACHTACTIONCODE:
//System.out.println("Yacht Action Code!");
//No decoder for this.
//throw new InvalidMessageException("Cannot decode YACHTACTIONCODE - no decoder.");
case CHATTERTEXT:
//System.out.println("Chatter Text Message!");
//No decoder for this.
//throw new InvalidMessageException("Cannot decode CHATTERTEXT - no decoder.");
case BOATLOCATION:
//System.out.println("Boat Location Message!");
BoatLocationDecoder blDecoder = new BoatLocationDecoder();
return blDecoder.decode(messageBody);
case MARKROUNDING:
//System.out.println("Mark Rounding Message!");
MarkRoundingDecoder mrDecoder = new MarkRoundingDecoder();
return mrDecoder.decode(messageBody);
case COURSEWIND:
//System.out.println("Course Wind Message!");
CourseWindsDecoder cwDecoder = new CourseWindsDecoder();
return cwDecoder.decode(messageBody);
case AVGWIND:
//System.out.println("Average Wind Message!");
AverageWindDecoder awDecoder = new AverageWindDecoder();
return awDecoder.decode(messageBody);
case BOATACTION:
BoatActionDecoder baDecoder = new BoatActionDecoder();
return baDecoder.decode(messageBody);
default:
//System.out.println("Broken Message!");
//throw new InvalidMessageException("Broken message! Did not recognise message type: " + headerMessageType + ".");
return null;
} }
return decoder.decode(messageBody);
} }
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.AverageWind; import network.Messages.AverageWind;
import network.Utils.ByteConverter; import network.Utils.ByteConverter;
@@ -32,64 +33,67 @@ public class AverageWindDecoder implements MessageDecoder {
@Override @Override
public AC35Data decode(byte[] encodedMessage) { public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
try {
byte messageVersionNumber = encodedMessage[0]; byte messageVersionNumber = encodedMessage[0];
byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7); byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7);
long time = ByteConverter.bytesToLong(byteTime); long time = ByteConverter.bytesToLong(byteTime);
byte[] byteRawPeriod = Arrays.copyOfRange(encodedMessage, 7, 9); byte[] byteRawPeriod = Arrays.copyOfRange(encodedMessage, 7, 9);
int intRawPeriod = ByteConverter.bytesToInt(byteRawPeriod); int intRawPeriod = ByteConverter.bytesToInt(byteRawPeriod);
long rawPeriod = unpackAverageWindPeriod(intRawPeriod); long rawPeriod = unpackAverageWindPeriod(intRawPeriod);
byte[] byteRawSpeed = Arrays.copyOfRange(encodedMessage, 9, 11); byte[] byteRawSpeed = Arrays.copyOfRange(encodedMessage, 9, 11);
int intRawSpeed = ByteConverter.bytesToInt(byteRawSpeed); int intRawSpeed = ByteConverter.bytesToInt(byteRawSpeed);
double rawSpeedKnots = unpackMMperSecToKnots(intRawSpeed); double rawSpeedKnots = unpackMMperSecToKnots(intRawSpeed);
byte[] bytePeriod2 = Arrays.copyOfRange(encodedMessage, 11, 13); byte[] bytePeriod2 = Arrays.copyOfRange(encodedMessage, 11, 13);
int intPeriod2 = ByteConverter.bytesToInt(bytePeriod2); int intPeriod2 = ByteConverter.bytesToInt(bytePeriod2);
long period2 = unpackAverageWindPeriod(intPeriod2); long period2 = unpackAverageWindPeriod(intPeriod2);
byte[] byteSpeed2 = Arrays.copyOfRange(encodedMessage, 13, 15); byte[] byteSpeed2 = Arrays.copyOfRange(encodedMessage, 13, 15);
int intSpeed2 = ByteConverter.bytesToInt(byteSpeed2); int intSpeed2 = ByteConverter.bytesToInt(byteSpeed2);
double speed2Knots = unpackMMperSecToKnots(intSpeed2); double speed2Knots = unpackMMperSecToKnots(intSpeed2);
byte[] bytePeriod3 = Arrays.copyOfRange(encodedMessage, 15, 17); byte[] bytePeriod3 = Arrays.copyOfRange(encodedMessage, 15, 17);
int intPeriod3 = ByteConverter.bytesToInt(bytePeriod3); int intPeriod3 = ByteConverter.bytesToInt(bytePeriod3);
long period3 = unpackAverageWindPeriod(intPeriod3); long period3 = unpackAverageWindPeriod(intPeriod3);
byte[] byteSpeed3 = Arrays.copyOfRange(encodedMessage, 17, 19); byte[] byteSpeed3 = Arrays.copyOfRange(encodedMessage, 17, 19);
int intSpeed3 = ByteConverter.bytesToInt(byteSpeed3); int intSpeed3 = ByteConverter.bytesToInt(byteSpeed3);
double speed3Knots = unpackMMperSecToKnots(intSpeed3); double speed3Knots = unpackMMperSecToKnots(intSpeed3);
byte[] bytePeriod4 = Arrays.copyOfRange(encodedMessage, 19, 21); byte[] bytePeriod4 = Arrays.copyOfRange(encodedMessage, 19, 21);
int intPeriod4 = ByteConverter.bytesToInt(bytePeriod4); int intPeriod4 = ByteConverter.bytesToInt(bytePeriod4);
long period4 = unpackAverageWindPeriod(intPeriod4); long period4 = unpackAverageWindPeriod(intPeriod4);
byte[] byteSpeed4 = Arrays.copyOfRange(encodedMessage, 21, 23); byte[] byteSpeed4 = Arrays.copyOfRange(encodedMessage, 21, 23);
int intSpeed4 = ByteConverter.bytesToInt(byteSpeed4); int intSpeed4 = ByteConverter.bytesToInt(byteSpeed4);
double speed4Knots = unpackMMperSecToKnots(intSpeed4); double speed4Knots = unpackMMperSecToKnots(intSpeed4);
message = new AverageWind(
messageVersionNumber,
time,
rawPeriod,
rawSpeedKnots,
period2,
speed2Knots,
period3,
speed3Knots,
period4,
speed4Knots);
return message;
message = new AverageWind( } catch (Exception e) {
messageVersionNumber, throw new InvalidMessageException("Could not decode AverageWind message.", e);
time, }
rawPeriod,
rawSpeedKnots,
period2,
speed2Knots,
period3,
speed3Knots,
period4,
speed4Knots );
return message;
} }
@@ -1,5 +1,6 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.BoatAction; import network.Messages.BoatAction;
import network.Messages.Enums.BoatActionEnum; import network.Messages.Enums.BoatActionEnum;
@@ -29,14 +30,19 @@ public class BoatActionDecoder implements MessageDecoder {
} }
@Override @Override
public AC35Data decode(byte[] encodedMessage) { public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
BoatActionEnum boatActionEnum = BoatActionEnum.fromByte(encodedMessage[0]); try {
BoatActionEnum boatActionEnum = BoatActionEnum.fromByte(encodedMessage[0]);
message = new BoatAction(boatActionEnum); message = new BoatAction(boatActionEnum);
return message; return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode BoatAction message.", e);
}
} }
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.BoatLocation; import network.Messages.BoatLocation;
import network.Messages.Enums.BoatLocationDeviceEnum; import network.Messages.Enums.BoatLocationDeviceEnum;
@@ -39,115 +40,121 @@ public class BoatLocationDecoder implements MessageDecoder {
@Override @Override
public AC35Data decode(byte[] encodedMessage) { public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1); try {
byte messageVersionNumber = messageVersionNumberBytes[0];
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7); byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
long time = bytesToLong(timeBytes); byte messageVersionNumber = messageVersionNumberBytes[0];
byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11); byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
int sourceID = bytesToInt(sourceIDBytes); long time = bytesToLong(timeBytes);
byte[] seqNumBytes = Arrays.copyOfRange(encodedMessage, 11, 15); byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11);
int seqNum = bytesToInt(seqNumBytes); int sourceID = bytesToInt(sourceIDBytes);
byte[] deviceTypeBytes = Arrays.copyOfRange(encodedMessage, 15, 16); byte[] seqNumBytes = Arrays.copyOfRange(encodedMessage, 11, 15);
BoatLocationDeviceEnum deviceType = BoatLocationDeviceEnum.fromByte(deviceTypeBytes[0]); int seqNum = bytesToInt(seqNumBytes);
byte[] latitudeBytes = Arrays.copyOfRange(encodedMessage, 16, 20); byte[] deviceTypeBytes = Arrays.copyOfRange(encodedMessage, 15, 16);
int numLatitude = bytesToInt(latitudeBytes); BoatLocationDeviceEnum deviceType = BoatLocationDeviceEnum.fromByte(deviceTypeBytes[0]);
double latitude = unpackGPS(numLatitude);
byte[] longitudeBytes = Arrays.copyOfRange(encodedMessage, 20, 24); byte[] latitudeBytes = Arrays.copyOfRange(encodedMessage, 16, 20);
int numLongitude = bytesToInt(longitudeBytes); int numLatitude = bytesToInt(latitudeBytes);
double longitude = unpackGPS(numLongitude); double latitude = unpackGPS(numLatitude);
byte[] altitudeBytes = Arrays.copyOfRange(encodedMessage, 24, 28); byte[] longitudeBytes = Arrays.copyOfRange(encodedMessage, 20, 24);
int numAltitude = bytesToInt(altitudeBytes); int numLongitude = bytesToInt(longitudeBytes);
double longitude = unpackGPS(numLongitude);
byte[] headingBytes = Arrays.copyOfRange(encodedMessage, 28, 30); byte[] altitudeBytes = Arrays.copyOfRange(encodedMessage, 24, 28);
int numHeading = bytesToInt(headingBytes); int numAltitude = bytesToInt(altitudeBytes);
Bearing heading = Bearing.fromDegrees(unpackHeading(numHeading));
byte[] pitchBytes = Arrays.copyOfRange(encodedMessage, 30, 32); byte[] headingBytes = Arrays.copyOfRange(encodedMessage, 28, 30);
short numPitch = bytesToShort(pitchBytes); int numHeading = bytesToInt(headingBytes);
Bearing heading = Bearing.fromDegrees(unpackHeading(numHeading));
byte[] rollBytes = Arrays.copyOfRange(encodedMessage, 32, 34); byte[] pitchBytes = Arrays.copyOfRange(encodedMessage, 30, 32);
short numRoll = bytesToShort(rollBytes); short numPitch = bytesToShort(pitchBytes);
byte[] boatSpeedBytes = Arrays.copyOfRange(encodedMessage, 34, 36); byte[] rollBytes = Arrays.copyOfRange(encodedMessage, 32, 34);
int numBoatSpeed = bytesToInt(boatSpeedBytes); short numRoll = bytesToShort(rollBytes);
double boatSpeedKnots = unpackMMperSecToKnots(numBoatSpeed);
byte[] cogBytes = Arrays.copyOfRange(encodedMessage, 36, 38); byte[] boatSpeedBytes = Arrays.copyOfRange(encodedMessage, 34, 36);
int numCog = bytesToInt(cogBytes); int numBoatSpeed = bytesToInt(boatSpeedBytes);
Bearing cog = Bearing.fromDegrees(unpackHeading(numCog)); double boatSpeedKnots = unpackMMperSecToKnots(numBoatSpeed);
byte[] sogBytes = Arrays.copyOfRange(encodedMessage, 38, 40); byte[] cogBytes = Arrays.copyOfRange(encodedMessage, 36, 38);
int numSog = bytesToInt(sogBytes); int numCog = bytesToInt(cogBytes);
double sogKnots = unpackMMperSecToKnots(numSog); Bearing cog = Bearing.fromDegrees(unpackHeading(numCog));
byte[] apparentWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 40, 42); byte[] sogBytes = Arrays.copyOfRange(encodedMessage, 38, 40);
int numApparentWindSpeed = bytesToInt(apparentWindSpeedBytes); int numSog = bytesToInt(sogBytes);
double apparentWindSpeedKnots = unpackMMperSecToKnots(numApparentWindSpeed); double sogKnots = unpackMMperSecToKnots(numSog);
byte[] apparentWindAngleBytes = Arrays.copyOfRange(encodedMessage, 42, 44); byte[] apparentWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 40, 42);
short numApparentWindAngle = bytesToShort(apparentWindAngleBytes); int numApparentWindSpeed = bytesToInt(apparentWindSpeedBytes);
Azimuth apparentWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numApparentWindAngle)); double apparentWindSpeedKnots = unpackMMperSecToKnots(numApparentWindSpeed);
byte[] trueWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 44, 46); byte[] apparentWindAngleBytes = Arrays.copyOfRange(encodedMessage, 42, 44);
int numTrueWindSpeed = bytesToInt(trueWindSpeedBytes); short numApparentWindAngle = bytesToShort(apparentWindAngleBytes);
double trueWindSpeedKnots = unpackMMperSecToKnots(numTrueWindSpeed); Azimuth apparentWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numApparentWindAngle));
byte[] trueWindDirectionBytes = Arrays.copyOfRange(encodedMessage, 46, 48); byte[] trueWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 44, 46);
short numTrueWindDirection = bytesToShort(trueWindDirectionBytes); int numTrueWindSpeed = bytesToInt(trueWindSpeedBytes);
Bearing trueWindDirection = Bearing.fromDegrees(unpackHeading(numTrueWindDirection)); double trueWindSpeedKnots = unpackMMperSecToKnots(numTrueWindSpeed);
byte[] trueWindAngleBytes = Arrays.copyOfRange(encodedMessage, 48, 50); byte[] trueWindDirectionBytes = Arrays.copyOfRange(encodedMessage, 46, 48);
short numTrueWindAngle = bytesToShort(trueWindAngleBytes); short numTrueWindDirection = bytesToShort(trueWindDirectionBytes);
Azimuth trueWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numTrueWindAngle)); Bearing trueWindDirection = Bearing.fromDegrees(unpackHeading(numTrueWindDirection));
byte[] currentDriftBytes = Arrays.copyOfRange(encodedMessage, 50, 52); byte[] trueWindAngleBytes = Arrays.copyOfRange(encodedMessage, 48, 50);
int numCurrentDrift = bytesToInt(currentDriftBytes); short numTrueWindAngle = bytesToShort(trueWindAngleBytes);
double currentDriftKnots = unpackMMperSecToKnots(numCurrentDrift); Azimuth trueWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numTrueWindAngle));
byte[] currentSetBytes = Arrays.copyOfRange(encodedMessage, 52, 54); byte[] currentDriftBytes = Arrays.copyOfRange(encodedMessage, 50, 52);
int numCurrentSet = bytesToShort(currentSetBytes); int numCurrentDrift = bytesToInt(currentDriftBytes);
Bearing currentSet = Bearing.fromDegrees(unpackHeading(numCurrentSet)); double currentDriftKnots = unpackMMperSecToKnots(numCurrentDrift);
byte[] rudderAngleBytes = Arrays.copyOfRange(encodedMessage, 54, 56); byte[] currentSetBytes = Arrays.copyOfRange(encodedMessage, 52, 54);
short numRudderAngle = bytesToShort(rudderAngleBytes); int numCurrentSet = bytesToShort(currentSetBytes);
Azimuth rudderAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numRudderAngle)); Bearing currentSet = Bearing.fromDegrees(unpackHeading(numCurrentSet));
byte[] rudderAngleBytes = Arrays.copyOfRange(encodedMessage, 54, 56);
short numRudderAngle = bytesToShort(rudderAngleBytes);
Azimuth rudderAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numRudderAngle));
message = new BoatLocation( message = new BoatLocation(
messageVersionNumber, messageVersionNumber,
time, time,
sourceID, sourceID,
seqNum, seqNum,
deviceType, deviceType,
latitude, latitude,
longitude, longitude,
numAltitude, numAltitude,
heading, heading,
numPitch, numPitch,
numRoll, numRoll,
boatSpeedKnots, boatSpeedKnots,
cog, cog,
sogKnots, sogKnots,
apparentWindSpeedKnots, apparentWindSpeedKnots,
apparentWindAngle, apparentWindAngle,
trueWindSpeedKnots, trueWindSpeedKnots,
trueWindDirection, trueWindDirection,
trueWindAngle, trueWindAngle,
currentDriftKnots, currentDriftKnots,
currentSet, currentSet,
rudderAngle ); rudderAngle);
return message; return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode BoatLocation message.", e);
}
} }
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.BoatStatus; import network.Messages.BoatStatus;
import network.Messages.Enums.BoatStatusEnum; import network.Messages.Enums.BoatStatusEnum;
@@ -39,10 +40,12 @@ public class BoatStatusDecoder {
* Decodes the contained message. * Decodes the contained message.
* @param encodedMessage The message to decode. * @param encodedMessage The message to decode.
* @return The decoded message. * @return The decoded message.
* @throws InvalidMessageException Thrown if the encoded message is invalid in some way, or cannot be decoded.
*/ */
public BoatStatus decode(byte[] encodedMessage) { public BoatStatus decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
try {
byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 0, 4); byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 0, 4);
int sourceID = bytesToInt(sourceIDBytes); int sourceID = bytesToInt(sourceIDBytes);
@@ -76,6 +79,10 @@ public class BoatStatusDecoder {
return message; return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode BoatStatus message.", e);
}
} }
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.CourseWind; import network.Messages.CourseWind;
import shared.model.Bearing; import shared.model.Bearing;
@@ -38,49 +39,55 @@ public class CourseWindDecoder {
* Decodes the contained message. * Decodes the contained message.
* @param encodedMessage The message to decode. * @param encodedMessage The message to decode.
* @return The decoded message. * @return The decoded message.
* @throws InvalidMessageException Thrown if the encoded message is invalid in some way, or cannot be decoded.
*/ */
public CourseWind decode(byte[] encodedMessage) { public CourseWind decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
byte[] windId = Arrays.copyOfRange(encodedMessage, 0, 1); try {
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7); byte[] windId = Arrays.copyOfRange(encodedMessage, 0, 1);
long time = bytesToLong(timeBytes);
byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11); byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
int raceIDInt = bytesToInt(raceIDBytes); long time = bytesToLong(timeBytes);
byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 11, 13); byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11);
int windDirectionInt = bytesToInt(windDirectionBytes); int raceIDInt = bytesToInt(raceIDBytes);
Bearing windDirection = Bearing.fromDegrees(unpackHeading(windDirectionInt));
byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 13, 15); byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 11, 13);
int windSpeedInt = bytesToInt(windSpeedBytes); int windDirectionInt = bytesToInt(windDirectionBytes);
double windSpeedKnots = unpackMMperSecToKnots(windSpeedInt); Bearing windDirection = Bearing.fromDegrees(unpackHeading(windDirectionInt));
byte[] bestUpwindAngleBytes = Arrays.copyOfRange(encodedMessage, 15, 17); byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 13, 15);
int bestUpwindAngleInt = bytesToInt(bestUpwindAngleBytes); int windSpeedInt = bytesToInt(windSpeedBytes);
Bearing bestUpwindAngle = Bearing.fromDegrees(unpackHeading(bestUpwindAngleInt)); double windSpeedKnots = unpackMMperSecToKnots(windSpeedInt);
byte[] bestDownwindAngleBytes = Arrays.copyOfRange(encodedMessage, 17, 19); byte[] bestUpwindAngleBytes = Arrays.copyOfRange(encodedMessage, 15, 17);
int bestDownwindAngleInt = bytesToInt(bestDownwindAngleBytes); int bestUpwindAngleInt = bytesToInt(bestUpwindAngleBytes);
Bearing bestDownwindAngle = Bearing.fromDegrees(unpackHeading(bestDownwindAngleInt)); Bearing bestUpwindAngle = Bearing.fromDegrees(unpackHeading(bestUpwindAngleInt));
byte[] flags = Arrays.copyOfRange(encodedMessage, 19, 20); byte[] bestDownwindAngleBytes = Arrays.copyOfRange(encodedMessage, 17, 19);
int bestDownwindAngleInt = bytesToInt(bestDownwindAngleBytes);
Bearing bestDownwindAngle = Bearing.fromDegrees(unpackHeading(bestDownwindAngleInt));
byte[] flags = Arrays.copyOfRange(encodedMessage, 19, 20);
message = new CourseWind(
windId[0],
time,
raceIDInt,
windDirection,
windSpeedKnots,
bestUpwindAngle,
bestDownwindAngle,
flags[0]);
message = new CourseWind( return message;
windId[0],
time,
raceIDInt,
windDirection,
windSpeedKnots,
bestUpwindAngle,
bestDownwindAngle,
flags[0] );
return message; } catch (Exception e) {
throw new InvalidMessageException("Could not decode CourseWind message.", e);
}
} }
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.CourseWind; import network.Messages.CourseWind;
import network.Messages.CourseWinds; import network.Messages.CourseWinds;
@@ -38,41 +39,46 @@ public class CourseWindsDecoder implements MessageDecoder {
@Override @Override
public AC35Data decode(byte[] encodedMessage) { public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
//The header is three bytes. try {
byte messageVersionNumber = encodedMessage[0];
byte byteWindID = encodedMessage[1]; //The header is three bytes.
byte loopCount = encodedMessage[2]; byte messageVersionNumber = encodedMessage[0];
byte byteWindID = encodedMessage[1];
byte loopCount = encodedMessage[2];
//A CourseWind object is 20 bytes. //A CourseWind object is 20 bytes.
final int courseWindByteLength = 20; final int courseWindByteLength = 20;
List<CourseWind> loopMessages = new ArrayList(); List<CourseWind> loopMessages = new ArrayList();
//The header is 3 bytes, so we need the remaining bytes. //The header is 3 bytes, so we need the remaining bytes.
byte[] loopMessagesBytes = Arrays.copyOfRange(encodedMessage, 3, courseWindByteLength * loopCount + 3); byte[] loopMessagesBytes = Arrays.copyOfRange(encodedMessage, 3, courseWindByteLength * loopCount + 3);
for (int messageLoopIndex = 0; messageLoopIndex < (loopCount * courseWindByteLength); messageLoopIndex += courseWindByteLength) { for (int messageLoopIndex = 0; messageLoopIndex < (loopCount * courseWindByteLength); messageLoopIndex += courseWindByteLength) {
byte[] messageBytes = Arrays.copyOfRange(loopMessagesBytes, messageLoopIndex, messageLoopIndex + courseWindByteLength); byte[] messageBytes = Arrays.copyOfRange(loopMessagesBytes, messageLoopIndex, messageLoopIndex + courseWindByteLength);
CourseWindDecoder courseWindDecoder = new CourseWindDecoder(); CourseWindDecoder courseWindDecoder = new CourseWindDecoder();
CourseWind courseWind = courseWindDecoder.decode(messageBytes); CourseWind courseWind = courseWindDecoder.decode(messageBytes);
loopMessages.add(courseWind); loopMessages.add(courseWind);
}
message = new CourseWinds(
messageVersionNumber,
byteWindID,
loopMessages);
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode CourseWinds message.", e);
} }
message = new CourseWinds(
messageVersionNumber,
byteWindID,
loopMessages );
return message;
} }
@@ -1,5 +1,6 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.Enums.BoatActionEnum; import network.Messages.Enums.BoatActionEnum;
import network.Messages.HeartBeat; import network.Messages.HeartBeat;
@@ -30,12 +31,18 @@ public class HeartBeatDecoder implements MessageDecoder {
} }
@Override @Override
public AC35Data decode(byte[] encodedMessage) { public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
message = new HeartBeat(bytesToLong(encodedMessage)); try {
return message; message = new HeartBeat(bytesToLong(encodedMessage));
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode HeartBeat message.", e);
}
} }
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.Enums.JoinAcceptanceEnum; import network.Messages.Enums.JoinAcceptanceEnum;
import network.Messages.JoinAcceptance; import network.Messages.JoinAcceptance;
@@ -32,27 +33,32 @@ public class JoinAcceptanceDecoder implements MessageDecoder {
@Override @Override
public AC35Data decode(byte[] encodedMessage) { public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
//SourceID is first four bytes. try {
byte[] sourceIdBytes = Arrays.copyOfRange(encodedMessage, 0, 4);
//Next byte is acceptance type. //SourceID is first four bytes.
byte[] acceptanceBytes = Arrays.copyOfRange(encodedMessage, 4, 5); byte[] sourceIdBytes = Arrays.copyOfRange(encodedMessage, 0, 4);
//Next byte is acceptance type.
byte[] acceptanceBytes = Arrays.copyOfRange(encodedMessage, 4, 5);
//SourceID is an int.
int sourceID = ByteConverter.bytesToInt(sourceIdBytes);
//SourceID is an int. //Acceptance enum is a byte.
int sourceID = ByteConverter.bytesToInt(sourceIdBytes); JoinAcceptanceEnum acceptanceType = JoinAcceptanceEnum.fromByte(acceptanceBytes[0]);
//Acceptance enum is a byte.
JoinAcceptanceEnum acceptanceType = JoinAcceptanceEnum.fromByte(acceptanceBytes[0]);
message = new JoinAcceptance(acceptanceType, sourceID); message = new JoinAcceptance(acceptanceType, sourceID);
return message; return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode JoinAcceptance message.", e);
}
} }
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.Enums.MarkRoundingBoatStatusEnum; import network.Messages.Enums.MarkRoundingBoatStatusEnum;
import network.Messages.Enums.MarkRoundingSideEnum; import network.Messages.Enums.MarkRoundingSideEnum;
@@ -33,48 +34,54 @@ public class MarkRoundingDecoder implements MessageDecoder {
} }
@Override @Override
public AC35Data decode(byte[] encodedMessage) { public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
byte messageVersionNumber = encodedMessage[0]; try {
byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7); byte messageVersionNumber = encodedMessage[0];
long time = ByteConverter.bytesToLong(byteTime);
byte[] byteAck = Arrays.copyOfRange(encodedMessage, 7, 9); byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7);
int ackNumber = ByteConverter.bytesToInt(byteAck); long time = ByteConverter.bytesToLong(byteTime);
byte[] byteRaceID = Arrays.copyOfRange(encodedMessage, 9, 13); byte[] byteAck = Arrays.copyOfRange(encodedMessage, 7, 9);
int raceID = ByteConverter.bytesToInt(byteRaceID); int ackNumber = ByteConverter.bytesToInt(byteAck);
byte[] byteSourceID = Arrays.copyOfRange(encodedMessage, 13, 17); byte[] byteRaceID = Arrays.copyOfRange(encodedMessage, 9, 13);
int sourceID = ByteConverter.bytesToInt(byteSourceID); int raceID = ByteConverter.bytesToInt(byteRaceID);
byte byteBoatStatus = encodedMessage[17]; byte[] byteSourceID = Arrays.copyOfRange(encodedMessage, 13, 17);
MarkRoundingBoatStatusEnum boatStatus = MarkRoundingBoatStatusEnum.fromByte(byteBoatStatus); int sourceID = ByteConverter.bytesToInt(byteSourceID);
byte byteRoundingSide = encodedMessage[18]; byte byteBoatStatus = encodedMessage[17];
MarkRoundingSideEnum roundingSide = MarkRoundingSideEnum.fromByte(byteRoundingSide); MarkRoundingBoatStatusEnum boatStatus = MarkRoundingBoatStatusEnum.fromByte(byteBoatStatus);
byte byteMarkType = encodedMessage[19]; byte byteRoundingSide = encodedMessage[18];
MarkRoundingTypeEnum markType = MarkRoundingTypeEnum.fromByte(byteMarkType); MarkRoundingSideEnum roundingSide = MarkRoundingSideEnum.fromByte(byteRoundingSide);
byte byteMarkID = encodedMessage[20]; byte byteMarkType = encodedMessage[19];
MarkRoundingTypeEnum markType = MarkRoundingTypeEnum.fromByte(byteMarkType);
byte byteMarkID = encodedMessage[20];
message = new MarkRounding( message = new MarkRounding(
messageVersionNumber, messageVersionNumber,
time, time,
ackNumber, ackNumber,
raceID, raceID,
sourceID, sourceID,
boatStatus, boatStatus,
roundingSide, roundingSide,
markType, markType,
byteMarkID); byteMarkID);
return message; return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode AverageWind message.", e);
}
} }
/** /**
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
@@ -15,7 +16,8 @@ public interface MessageDecoder {
* Decodes a given message. * Decodes a given message.
* @param encodedMessage The message to decode. * @param encodedMessage The message to decode.
* @return The decoded message. * @return The decoded message.
* @throws InvalidMessageException Thrown if the encoded message is invalid in some way, or cannot be decoded.
*/ */
public AC35Data decode(byte[] encodedMessage); public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException;
} }
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.Enums.RaceStartTypeEnum; import network.Messages.Enums.RaceStartTypeEnum;
import network.Messages.RaceStartStatus; import network.Messages.RaceStartStatus;
@@ -35,38 +36,42 @@ public class RaceStartStatusDecoder implements MessageDecoder {
@Override @Override
public AC35Data decode(byte[] encodedMessage) { public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
try {
byte messageVersion = encodedMessage[0]; byte messageVersion = encodedMessage[0];
byte[] timestamp = Arrays.copyOfRange(encodedMessage, 1, 7); byte[] timestamp = Arrays.copyOfRange(encodedMessage, 1, 7);
long time = bytesToLong(timestamp); long time = bytesToLong(timestamp);
byte[] ackNumber = Arrays.copyOfRange(encodedMessage, 7, 9); byte[] ackNumber = Arrays.copyOfRange(encodedMessage, 7, 9);
short ack = bytesToShort(ackNumber); short ack = bytesToShort(ackNumber);
byte[] raceStartTime = Arrays.copyOfRange(encodedMessage, 9, 15); byte[] raceStartTime = Arrays.copyOfRange(encodedMessage, 9, 15);
long startTime = bytesToLong(raceStartTime); long startTime = bytesToLong(raceStartTime);
byte[] raceIdentifier = Arrays.copyOfRange(encodedMessage, 15, 19); byte[] raceIdentifier = Arrays.copyOfRange(encodedMessage, 15, 19);
int raceID = bytesToInt(raceIdentifier); int raceID = bytesToInt(raceIdentifier);
byte notificationType = encodedMessage[19]; byte notificationType = encodedMessage[19];
message = new RaceStartStatus(
messageVersion,
time,
ack,
startTime,
raceID,
RaceStartTypeEnum.fromByte(notificationType)
);
message = new RaceStartStatus( return message;
messageVersion,
time,
ack,
startTime,
raceID,
RaceStartTypeEnum.fromByte(notificationType)
);
return message; } catch (Exception e) {
throw new InvalidMessageException("Could not decode RaceStartStatus message.", e);
}
} }
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.BoatStatus; import network.Messages.BoatStatus;
import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RaceStatusEnum;
@@ -43,70 +44,75 @@ public class RaceStatusDecoder implements MessageDecoder {
@Override @Override
public AC35Data decode(byte[] encodedMessage) { public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
try {
byte[] versionNumBytes = Arrays.copyOfRange(encodedMessage, 0, 1); byte[] versionNumBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
byte versionNum = versionNumBytes[0]; byte versionNum = versionNumBytes[0];
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7); byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
long time = bytesToLong(timeBytes); long time = bytesToLong(timeBytes);
byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11); byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11);
int raceID = bytesToInt(raceIDBytes); int raceID = bytesToInt(raceIDBytes);
byte[] raceStatusBytes = Arrays.copyOfRange(encodedMessage, 11, 12); byte[] raceStatusBytes = Arrays.copyOfRange(encodedMessage, 11, 12);
RaceStatusEnum raceStatus = RaceStatusEnum.fromByte(raceStatusBytes[0]); RaceStatusEnum raceStatus = RaceStatusEnum.fromByte(raceStatusBytes[0]);
byte[] expectedStartBytes = Arrays.copyOfRange(encodedMessage, 12, 18); byte[] expectedStartBytes = Arrays.copyOfRange(encodedMessage, 12, 18);
long expectedStart = bytesToLong(expectedStartBytes); long expectedStart = bytesToLong(expectedStartBytes);
byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 18, 20); byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 18, 20);
int windDirectionInt = bytesToInt(windDirectionBytes); int windDirectionInt = bytesToInt(windDirectionBytes);
Bearing windDirection = Bearing.fromDegrees(AC35UnitConverter.unpackHeading(windDirectionInt)); Bearing windDirection = Bearing.fromDegrees(AC35UnitConverter.unpackHeading(windDirectionInt));
byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 20, 22); byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 20, 22);
int windSpeedInt = bytesToInt(windSpeedBytes); int windSpeedInt = bytesToInt(windSpeedBytes);
double windSpeedKnots = AC35UnitConverter.unpackMMperSecToKnots(windSpeedInt); double windSpeedKnots = AC35UnitConverter.unpackMMperSecToKnots(windSpeedInt);
byte[] numberOfBoatsBytes = Arrays.copyOfRange(encodedMessage, 22, 23); byte[] numberOfBoatsBytes = Arrays.copyOfRange(encodedMessage, 22, 23);
int numberOfBoats = bytesToInt(numberOfBoatsBytes); int numberOfBoats = bytesToInt(numberOfBoatsBytes);
byte[] raceTypeBytes = Arrays.copyOfRange(encodedMessage, 23, 24); byte[] raceTypeBytes = Arrays.copyOfRange(encodedMessage, 23, 24);
RaceTypeEnum raceType = RaceTypeEnum.fromByte(raceTypeBytes[0]); RaceTypeEnum raceType = RaceTypeEnum.fromByte(raceTypeBytes[0]);
byte[] boatStatusesBytes = Arrays.copyOfRange(encodedMessage, 24, 25 + 20 * numberOfBoats); byte[] boatStatusesBytes = Arrays.copyOfRange(encodedMessage, 24, 25 + 20 * numberOfBoats);
List<BoatStatus> boatStatuses = new ArrayList<>(); List<BoatStatus> boatStatuses = new ArrayList<>();
//BoatStatus is 20 bytes. //BoatStatus is 20 bytes.
int boatStatusByteLength = 20; int boatStatusByteLength = 20;
//Decode each BoatStatus. //Decode each BoatStatus.
for (int boatLoopIndex = 0; boatLoopIndex < (numberOfBoats * boatStatusByteLength); boatLoopIndex += boatStatusByteLength) { for (int boatLoopIndex = 0; boatLoopIndex < (numberOfBoats * boatStatusByteLength); boatLoopIndex += boatStatusByteLength) {
byte[] boatStatusBytes = Arrays.copyOfRange(boatStatusesBytes, boatLoopIndex, boatLoopIndex + boatStatusByteLength); byte[] boatStatusBytes = Arrays.copyOfRange(boatStatusesBytes, boatLoopIndex, boatLoopIndex + boatStatusByteLength);
BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder(); BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder();
boatStatuses.add(boatStatusDecoder.decode(boatStatusBytes)); boatStatuses.add(boatStatusDecoder.decode(boatStatusBytes));
}
message = new RaceStatus(
versionNum,
time,
raceID,
raceStatus,
expectedStart,
windDirection,
windSpeedKnots,
raceType,
boatStatuses);
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode RaceStatus message.", e);
} }
message = new RaceStatus(
versionNum,
time,
raceID,
raceStatus,
expectedStart,
windDirection,
windSpeedKnots,
raceType,
boatStatuses );
return message;
} }
@@ -1,6 +1,7 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.Enums.RequestToJoinEnum; import network.Messages.Enums.RequestToJoinEnum;
import network.Messages.RequestToJoin; import network.Messages.RequestToJoin;
@@ -31,20 +32,26 @@ public class RequestToJoinDecoder implements MessageDecoder{
@Override @Override
public AC35Data decode(byte[] encodedRequest) { public AC35Data decode(byte[] encodedRequest) throws InvalidMessageException {
this.encodedRequest = encodedRequest; this.encodedRequest = encodedRequest;
//Request type is first four bytes. try {
byte[] requestTypeBytes = Arrays.copyOfRange(encodedRequest, 0, 4);
//Request type is an integral type. //Request type is first four bytes.
int requestTypeInt = ByteConverter.bytesToInt(requestTypeBytes); byte[] requestTypeBytes = Arrays.copyOfRange(encodedRequest, 0, 4);
RequestToJoinEnum requestType = RequestToJoinEnum.fromInt(requestTypeInt);
//Request type is an integral type.
int requestTypeInt = ByteConverter.bytesToInt(requestTypeBytes);
RequestToJoinEnum requestType = RequestToJoinEnum.fromInt(requestTypeInt);
message = new RequestToJoin(requestType); message = new RequestToJoin(requestType);
return message; return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode RequestToJoin message.", e);
}
} }
@@ -1,5 +1,6 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.Enums.XMLMessageType; import network.Messages.Enums.XMLMessageType;
import network.Messages.XMLMessage; import network.Messages.XMLMessage;
@@ -35,36 +36,42 @@ public class XMLMessageDecoder implements MessageDecoder {
@Override @Override
public AC35Data decode(byte[] encodedMessage) { public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage; this.encodedMessage = encodedMessage;
byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1); try {
byte[] ackNumberBytes = Arrays.copyOfRange(encodedMessage, 1, 3);
byte[] timeStampBytes = Arrays.copyOfRange(encodedMessage, 3, 9); byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
byte[] xmlMsgSubTypeBytes = Arrays.copyOfRange(encodedMessage, 9, 10); byte[] ackNumberBytes = Arrays.copyOfRange(encodedMessage, 1, 3);
byte[] sequenceNumberBytes = Arrays.copyOfRange(encodedMessage, 10, 12); byte[] timeStampBytes = Arrays.copyOfRange(encodedMessage, 3, 9);
byte[] xmlMsgLengthBytes = Arrays.copyOfRange(encodedMessage, 12, 14); byte[] xmlMsgSubTypeBytes = Arrays.copyOfRange(encodedMessage, 9, 10);
byte[] xmlMessagebytes = Arrays.copyOfRange(encodedMessage, 14, encodedMessage.length); byte[] sequenceNumberBytes = Arrays.copyOfRange(encodedMessage, 10, 12);
byte[] xmlMsgLengthBytes = Arrays.copyOfRange(encodedMessage, 12, 14);
byte[] xmlMessagebytes = Arrays.copyOfRange(encodedMessage, 14, encodedMessage.length);
byte messageVersionNumber = messageVersionNumberBytes[0]; byte messageVersionNumber = messageVersionNumberBytes[0];
short ackNumber = bytesToShort(ackNumberBytes); short ackNumber = bytesToShort(ackNumberBytes);
long timeStamp = bytesToLong(timeStampBytes); long timeStamp = bytesToLong(timeStampBytes);
XMLMessageType xmlMsgSubType = XMLMessageType.fromByte(xmlMsgSubTypeBytes[0]); XMLMessageType xmlMsgSubType = XMLMessageType.fromByte(xmlMsgSubTypeBytes[0]);
short sequenceNumber = bytesToShort(sequenceNumberBytes); short sequenceNumber = bytesToShort(sequenceNumberBytes);
short xmlMsgLength = bytesToShort(xmlMsgLengthBytes); short xmlMsgLength = bytesToShort(xmlMsgLengthBytes);
String xmlMessage = new String(xmlMessagebytes); String xmlMessage = new String(xmlMessagebytes);
message = new XMLMessage( message = new XMLMessage(
messageVersionNumber, messageVersionNumber,
ackNumber, ackNumber,
timeStamp, timeStamp,
xmlMsgSubType, xmlMsgSubType,
sequenceNumber, sequenceNumber,
xmlMessage ); xmlMessage);
return message; return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode XMLMessage message.", e);
}
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.AverageWind; import network.Messages.AverageWind;
@@ -24,63 +25,68 @@ public class AverageWindEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
AverageWind averageWind = (AverageWind) message;
//Downcast.
AverageWind averageWind = (AverageWind) message;
byte messageVersionNumber = averageWind.getMessageVersionNumber(); byte messageVersionNumber = averageWind.getMessageVersionNumber();
long time = averageWind.getTime(); long time = averageWind.getTime();
byte[] byteTime = longToBytes(time,6); byte[] byteTime = longToBytes(time, 6);
long rawPeriod = averageWind.getRawPeriod(); long rawPeriod = averageWind.getRawPeriod();
int rawPeriodInt = packAverageWindPeriod(rawPeriod); int rawPeriodInt = packAverageWindPeriod(rawPeriod);
byte[] byteRawPeriod = intToBytes(rawPeriodInt, 2); byte[] byteRawPeriod = intToBytes(rawPeriodInt, 2);
double rawSampleSpeed = averageWind.getRawSpeedKnots(); double rawSampleSpeed = averageWind.getRawSpeedKnots();
int rawSampleSpeedInt = packKnotsToMMperSec(rawSampleSpeed); int rawSampleSpeedInt = packKnotsToMMperSec(rawSampleSpeed);
byte[] byteRawSpeed = intToBytes(rawSampleSpeedInt, 2); byte[] byteRawSpeed = intToBytes(rawSampleSpeedInt, 2);
long period2 = averageWind.getSampleTwoPeriod(); long period2 = averageWind.getSampleTwoPeriod();
int period2Int = packAverageWindPeriod(period2); int period2Int = packAverageWindPeriod(period2);
byte[] bytePeriod2 = intToBytes(period2Int, 2); byte[] bytePeriod2 = intToBytes(period2Int, 2);
double speed2 = averageWind.getSampleTwoSpeedKnots(); double speed2 = averageWind.getSampleTwoSpeedKnots();
int speed2Int = packKnotsToMMperSec(speed2); int speed2Int = packKnotsToMMperSec(speed2);
byte[] byteSpeed2 = intToBytes(speed2Int, 2); byte[] byteSpeed2 = intToBytes(speed2Int, 2);
long period3 = averageWind.getSampleThreePeriod(); long period3 = averageWind.getSampleThreePeriod();
int period3Int = packAverageWindPeriod(period3); int period3Int = packAverageWindPeriod(period3);
byte[] bytePeriod3 = intToBytes(period3Int, 2); byte[] bytePeriod3 = intToBytes(period3Int, 2);
double speed3 = averageWind.getSampleThreeSpeedKnots(); double speed3 = averageWind.getSampleThreeSpeedKnots();
int speed3Int = packKnotsToMMperSec(speed3); int speed3Int = packKnotsToMMperSec(speed3);
byte[] byteSpeed3 = intToBytes(speed3Int, 2); byte[] byteSpeed3 = intToBytes(speed3Int, 2);
long period4 = averageWind.getSampleFourPeriod(); long period4 = averageWind.getSampleFourPeriod();
int period4Int = packAverageWindPeriod(period4); int period4Int = packAverageWindPeriod(period4);
byte[] bytePeriod4 = intToBytes(period4Int, 2); byte[] bytePeriod4 = intToBytes(period4Int, 2);
double speed4 = averageWind.getSampleFourSpeedKnots(); double speed4 = averageWind.getSampleFourSpeedKnots();
int speed4Int = packKnotsToMMperSec(speed4); int speed4Int = packKnotsToMMperSec(speed4);
byte[] byteSpeed4 = intToBytes(speed4Int, 2); byte[] byteSpeed4 = intToBytes(speed4Int, 2);
ByteBuffer result = ByteBuffer.allocate(23);
result.put(messageVersionNumber);
result.put(byteTime);
result.put(byteRawPeriod);
result.put(byteRawSpeed);
result.put(bytePeriod2);
result.put(byteSpeed2);
result.put(bytePeriod3);
result.put(byteSpeed3);
result.put(bytePeriod4);
result.put(byteSpeed4);
return result.array();
ByteBuffer result = ByteBuffer.allocate(23); } catch (Exception e) {
result.put(messageVersionNumber); throw new InvalidMessageException("Could not encode AverageWind message.", e);
result.put(byteTime); }
result.put(byteRawPeriod);
result.put(byteRawSpeed);
result.put(bytePeriod2);
result.put(byteSpeed2);
result.put(bytePeriod3);
result.put(byteSpeed3);
result.put(bytePeriod4);
result.put(byteSpeed4);
return result.array();
} }
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.BoatAction; import network.Messages.BoatAction;
@@ -22,19 +23,25 @@ public class BoatActionEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
BoatAction boatAction = (BoatAction) message;
//Message is 1 byte. //Downcast.
ByteBuffer boatActionMessage = ByteBuffer.allocate(1); BoatAction boatAction = (BoatAction) message;
boatActionMessage.put(intToBytes(boatAction.getBoatAction().getValue(), 1)); //Message is 1 byte.
ByteBuffer boatActionMessage = ByteBuffer.allocate(1);
byte [] result = boatActionMessage.array(); boatActionMessage.put(intToBytes(boatAction.getBoatAction().getValue(), 1));
return result; byte[] result = boatActionMessage.array();
return result;
} catch (Exception e) {
throw new InvalidMessageException("Could not encode BoatAction message.", e);
}
} }
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.BoatLocation; import network.Messages.BoatLocation;
@@ -24,61 +25,67 @@ public class BoatLocationEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
BoatLocation boatLocation = (BoatLocation) message;
//Downcast.
BoatLocation boatLocation = (BoatLocation) message;
int messageVersionNumber = 0b1; int messageVersionNumber = 0b1;
byte[] messageVersionBytes = intToBytes(messageVersionNumber, 1); byte[] messageVersionBytes = intToBytes(messageVersionNumber, 1);
byte[] time = longToBytes(boatLocation.getTime(), 6); byte[] time = longToBytes(boatLocation.getTime(), 6);
byte[] sourceID = intToBytes(boatLocation.getSourceID(), 4); byte[] sourceID = intToBytes(boatLocation.getSourceID(), 4);
byte[] seqNum = longToBytes(boatLocation.getSequenceNumber(), 4); byte[] seqNum = longToBytes(boatLocation.getSequenceNumber(), 4);
byte[] deviceType = intToBytes(boatLocation.getDeviceType().getValue(), 1); byte[] deviceType = intToBytes(boatLocation.getDeviceType().getValue(), 1);
byte[] latitude = intToBytes(packGPS(boatLocation.getLatitude()), 4); byte[] latitude = intToBytes(packGPS(boatLocation.getLatitude()), 4);
byte[] longitude = intToBytes(packGPS(boatLocation.getLongitude()), 4); byte[] longitude = intToBytes(packGPS(boatLocation.getLongitude()), 4);
byte[] altitude = intToBytes(boatLocation.getAltitude(), 4); byte[] altitude = intToBytes(boatLocation.getAltitude(), 4);
byte[] heading = intToBytes(packHeading(boatLocation.getHeading().degrees()), 2); byte[] heading = intToBytes(packHeading(boatLocation.getHeading().degrees()), 2);
byte[] pitch = intToBytes(boatLocation.getPitch(), 2); byte[] pitch = intToBytes(boatLocation.getPitch(), 2);
byte[] roll = intToBytes(boatLocation.getRoll(), 2); byte[] roll = intToBytes(boatLocation.getRoll(), 2);
byte[] boatSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSpeedKnots()), 2); byte[] boatSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSpeedKnots()), 2);
byte[] cog = intToBytes(packHeading(boatLocation.getBoatCOG().degrees()), 2); byte[] cog = intToBytes(packHeading(boatLocation.getBoatCOG().degrees()), 2);
byte[] sog = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSOGKnots()), 2); byte[] sog = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSOGKnots()), 2);
byte[] apparentWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getApparentWindSpeedKnots()), 2); byte[] apparentWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getApparentWindSpeedKnots()), 2);
byte[] apparentWindAngle = intToBytes(packTrueWindAngle(boatLocation.getApparentWindAngle().degrees()), 2); byte[] apparentWindAngle = intToBytes(packTrueWindAngle(boatLocation.getApparentWindAngle().degrees()), 2);
byte[] trueWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getTrueWindSpeedKnots()), 2); byte[] trueWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getTrueWindSpeedKnots()), 2);
byte[] trueWindDirection = intToBytes(packHeading(boatLocation.getTrueWindDirection().degrees()), 2); byte[] trueWindDirection = intToBytes(packHeading(boatLocation.getTrueWindDirection().degrees()), 2);
byte[] trueWindAngle = intToBytes(packTrueWindAngle(boatLocation.getTrueWindAngle().degrees()), 2); byte[] trueWindAngle = intToBytes(packTrueWindAngle(boatLocation.getTrueWindAngle().degrees()), 2);
byte[] currentDrift = intToBytes(packKnotsToMMperSec(boatLocation.getCurrentDriftKnots()), 2); byte[] currentDrift = intToBytes(packKnotsToMMperSec(boatLocation.getCurrentDriftKnots()), 2);
byte[] currentSet = intToBytes(packHeading(boatLocation.getCurrentSet().degrees()), 2); byte[] currentSet = intToBytes(packHeading(boatLocation.getCurrentSet().degrees()), 2);
byte[] rudderAngle = intToBytes(packTrueWindAngle(boatLocation.getRudderAngle().degrees()), 2); byte[] rudderAngle = intToBytes(packTrueWindAngle(boatLocation.getRudderAngle().degrees()), 2);
ByteBuffer result = ByteBuffer.allocate(56); ByteBuffer result = ByteBuffer.allocate(56);
result.put(messageVersionBytes); result.put(messageVersionBytes);
result.put(time); result.put(time);
result.put(sourceID); result.put(sourceID);
result.put(seqNum); result.put(seqNum);
result.put(deviceType); result.put(deviceType);
result.put(latitude); result.put(latitude);
result.put(longitude); result.put(longitude);
result.put(altitude); result.put(altitude);
result.put(heading); result.put(heading);
result.put(pitch); result.put(pitch);
result.put(roll); result.put(roll);
result.put(boatSpeed); result.put(boatSpeed);
result.put(cog); result.put(cog);
result.put(sog); result.put(sog);
result.put(apparentWindSpeed); result.put(apparentWindSpeed);
result.put(apparentWindAngle); result.put(apparentWindAngle);
result.put(trueWindSpeed); result.put(trueWindSpeed);
result.put(trueWindDirection); result.put(trueWindDirection);
result.put(trueWindAngle); result.put(trueWindAngle);
result.put(currentDrift); result.put(currentDrift);
result.put(currentSet); result.put(currentSet);
result.put(rudderAngle); result.put(rudderAngle);
return result.array(); return result.array();
} catch (Exception e) {
throw new InvalidMessageException("Could not encode BoatLocation message.", e);
}
} }
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.BoatStatus; import network.Messages.BoatStatus;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -25,32 +26,40 @@ public class BoatStatusEncoder {
* Encodes a given BoatStatus message. * Encodes a given BoatStatus message.
* @param message The message to encode. * @param message The message to encode.
* @return The encoded message. * @return The encoded message.
* @throws InvalidMessageException Thrown if the message is invalid in some way, or cannot be encoded.
*/ */
public byte[] encode(BoatStatus message) { public byte[] encode(BoatStatus message) throws InvalidMessageException {
//Downcast. try {
BoatStatus boatStatus = (BoatStatus) message;
//BoatStatus is 20 bytes.
ByteBuffer boatStatusBuffer = ByteBuffer.allocate(20);
byte[] sourceID = intToBytes(boatStatus.getSourceID()); //Downcast.
byte[] boatStatusBytes = intToBytes(boatStatus.getBoatStatus().getValue(), 1); BoatStatus boatStatus = (BoatStatus) message;
byte[] legNum = intToBytes(boatStatus.getLegNumber(), 1);
byte[] numPenalties = intToBytes(boatStatus.getNumPenaltiesAwarded(), 1);
byte[] numPenaltiesServed = intToBytes(boatStatus.getNumPenaltiesServed(), 1);
byte[] estNextMarkTime = longToBytes(boatStatus.getEstTimeAtNextMark(), 6);
byte[] estFinishTime = longToBytes(boatStatus.getEstTimeAtFinish(), 6);
boatStatusBuffer.put(sourceID); //BoatStatus is 20 bytes.
boatStatusBuffer.put(boatStatusBytes); ByteBuffer boatStatusBuffer = ByteBuffer.allocate(20);
boatStatusBuffer.put(legNum);
boatStatusBuffer.put(numPenalties);
boatStatusBuffer.put(numPenaltiesServed);
boatStatusBuffer.put(estNextMarkTime);
boatStatusBuffer.put(estFinishTime);
return boatStatusBuffer.array(); byte[] sourceID = intToBytes(boatStatus.getSourceID());
byte[] boatStatusBytes = intToBytes(boatStatus.getBoatStatus().getValue(), 1);
byte[] legNum = intToBytes(boatStatus.getLegNumber(), 1);
byte[] numPenalties = intToBytes(boatStatus.getNumPenaltiesAwarded(), 1);
byte[] numPenaltiesServed = intToBytes(boatStatus.getNumPenaltiesServed(), 1);
byte[] estNextMarkTime = longToBytes(boatStatus.getEstTimeAtNextMark(), 6);
byte[] estFinishTime = longToBytes(boatStatus.getEstTimeAtFinish(), 6);
boatStatusBuffer.put(sourceID);
boatStatusBuffer.put(boatStatusBytes);
boatStatusBuffer.put(legNum);
boatStatusBuffer.put(numPenalties);
boatStatusBuffer.put(numPenaltiesServed);
boatStatusBuffer.put(estNextMarkTime);
boatStatusBuffer.put(estFinishTime);
return boatStatusBuffer.array();
} catch (Exception e) {
throw new InvalidMessageException("Could not encode BoatStatus message.", e);
}
} }
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.CourseWind; import network.Messages.CourseWind;
import shared.model.Bearing; import shared.model.Bearing;
@@ -28,46 +29,53 @@ public class CourseWindEncoder {
* Encodes a given CourseWind message. * Encodes a given CourseWind message.
* @param message The message to encode. * @param message The message to encode.
* @return The encoded message. * @return The encoded message.
* @throws InvalidMessageException Thrown if the message is invalid in some way, or cannot be encoded.
*/ */
public byte[] encode(CourseWind message) { public byte[] encode(CourseWind message) throws InvalidMessageException {
CourseWind courseWind = message; try {
CourseWind courseWind = message;
//CourseWind is 20 bytes. //CourseWind is 20 bytes.
ByteBuffer courseWindBuffer = ByteBuffer.allocate(20); ByteBuffer courseWindBuffer = ByteBuffer.allocate(20);
byte[] windId = intToBytes(courseWind.getID(), 1); byte[] windId = intToBytes(courseWind.getID(), 1);
byte[] timeBytes = longToBytes(courseWind.getTime(), 6); byte[] timeBytes = longToBytes(courseWind.getTime(), 6);
byte[] raceIDBytes = intToBytes(courseWind.getRaceID(), 4); byte[] raceIDBytes = intToBytes(courseWind.getRaceID(), 4);
int windDirectionInt = packHeading(courseWind.getWindDirection().degrees()); int windDirectionInt = packHeading(courseWind.getWindDirection().degrees());
byte[] windDirectionBytes = intToBytes(windDirectionInt, 2); byte[] windDirectionBytes = intToBytes(windDirectionInt, 2);
int windSpeedInt = packKnotsToMMperSec(courseWind.getWindSpeedKnots()); int windSpeedInt = packKnotsToMMperSec(courseWind.getWindSpeedKnots());
byte[] windSpeedBytes = intToBytes(windSpeedInt, 2); byte[] windSpeedBytes = intToBytes(windSpeedInt, 2);
int bestUpwindAngleInt = packHeading(courseWind.getBestUpwindAngle().degrees()); int bestUpwindAngleInt = packHeading(courseWind.getBestUpwindAngle().degrees());
byte[] bestUpwindAngleBytes = intToBytes(bestUpwindAngleInt, 2); byte[] bestUpwindAngleBytes = intToBytes(bestUpwindAngleInt, 2);
int bestDownwindAngleInt = packHeading(courseWind.getBestDownwindAngle().degrees()); int bestDownwindAngleInt = packHeading(courseWind.getBestDownwindAngle().degrees());
byte[] bestDownwindAngleBytes = intToBytes(bestDownwindAngleInt, 2); byte[] bestDownwindAngleBytes = intToBytes(bestDownwindAngleInt, 2);
byte[] flags = intToBytes(courseWind.getFlags(), 1); byte[] flags = intToBytes(courseWind.getFlags(), 1);
courseWindBuffer.put(windId); courseWindBuffer.put(windId);
courseWindBuffer.put(timeBytes); courseWindBuffer.put(timeBytes);
courseWindBuffer.put(raceIDBytes); courseWindBuffer.put(raceIDBytes);
courseWindBuffer.put(windDirectionBytes); courseWindBuffer.put(windDirectionBytes);
courseWindBuffer.put(windSpeedBytes); courseWindBuffer.put(windSpeedBytes);
courseWindBuffer.put(bestUpwindAngleBytes); courseWindBuffer.put(bestUpwindAngleBytes);
courseWindBuffer.put(bestDownwindAngleBytes); courseWindBuffer.put(bestDownwindAngleBytes);
courseWindBuffer.put(flags); courseWindBuffer.put(flags);
return courseWindBuffer.array(); return courseWindBuffer.array();
} catch (Exception e) {
throw new InvalidMessageException("Could not encode CourseWind message.", e);
}
} }
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.BoatAction; import network.Messages.BoatAction;
import network.Messages.CourseWind; import network.Messages.CourseWind;
@@ -24,33 +25,39 @@ public class CourseWindsEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
CourseWinds courseWinds = (CourseWinds) message;
//Downcast.
CourseWinds courseWinds = (CourseWinds) message;
byte messageVersionNumber = CourseWinds.currentMessageVersionNumber; byte messageVersionNumber = CourseWinds.currentMessageVersionNumber;
byte byteWindID = courseWinds.getSelectedWindID(); byte byteWindID = courseWinds.getSelectedWindID();
byte[] loopcount = intToBytes(courseWinds.getCourseWinds().size(), 1); byte[] loopcount = intToBytes(courseWinds.getCourseWinds().size(), 1);
ByteBuffer result = ByteBuffer.allocate(3 + 20 * courseWinds.getCourseWinds().size()); ByteBuffer result = ByteBuffer.allocate(3 + 20 * courseWinds.getCourseWinds().size());
result.put(messageVersionNumber); result.put(messageVersionNumber);
result.put(byteWindID); result.put(byteWindID);
result.put(loopcount); result.put(loopcount);
//Encode each CourseWind. //Encode each CourseWind.
for (CourseWind wind: courseWinds.getCourseWinds()){ for (CourseWind wind : courseWinds.getCourseWinds()) {
CourseWindEncoder courseWindEncoder = new CourseWindEncoder(); CourseWindEncoder courseWindEncoder = new CourseWindEncoder();
byte[] encodedCourseWind = courseWindEncoder.encode(wind); byte[] encodedCourseWind = courseWindEncoder.encode(wind);
result.put(encodedCourseWind); result.put(encodedCourseWind);
}
return result.array();
} catch (Exception e) {
throw new InvalidMessageException("Could not encode CourseWinds message.", e);
} }
return result.array();
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.HeartBeat; import network.Messages.HeartBeat;
@@ -22,18 +23,24 @@ public class HeartBeatEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
HeartBeat heartbeat = (HeartBeat) message;
//Message is 4 bytes. //Downcast.
ByteBuffer heartBeat = ByteBuffer.allocate(4); HeartBeat heartbeat = (HeartBeat) message;
heartBeat.put(longToBytes(heartbeat.getSequenceNumber(), 4));
byte[] result = heartBeat.array(); //Message is 4 bytes.
ByteBuffer heartBeat = ByteBuffer.allocate(4);
heartBeat.put(longToBytes(heartbeat.getSequenceNumber(), 4));
return result; byte[] result = heartBeat.array();
return result;
} catch (Exception e) {
throw new InvalidMessageException("Could not encode HeartBeat message.", e);
}
} }
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.JoinAcceptance; import network.Messages.JoinAcceptance;
import network.Utils.ByteConverter; import network.Utils.ByteConverter;
@@ -23,22 +24,28 @@ public class JoinAcceptanceEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
JoinAcceptance joinAcceptance = (JoinAcceptance) message;
//Message is 5 bytes. //Downcast.
ByteBuffer joinAcceptanceBuffer = ByteBuffer.allocate(5); JoinAcceptance joinAcceptance = (JoinAcceptance) message;
//Source ID is first four bytes. //Message is 5 bytes.
joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getSourceID(), 4)); ByteBuffer joinAcceptanceBuffer = ByteBuffer.allocate(5);
//Acceptance type is next byte.
joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getAcceptanceType().getValue(), 1));
byte [] result = joinAcceptanceBuffer.array(); //Source ID is first four bytes.
joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getSourceID(), 4));
//Acceptance type is next byte.
joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getAcceptanceType().getValue(), 1));
return result; byte[] result = joinAcceptanceBuffer.array();
return result;
} catch (Exception e) {
throw new InvalidMessageException("Could not encode JoinAcceptance message.", e);
}
} }
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.MarkRounding; import network.Messages.MarkRounding;
@@ -23,35 +24,41 @@ public class MarkRoundingEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
MarkRounding markRounding = (MarkRounding) message;
byte messageVersionNumber = markRounding.getMessageVersionNumber(); //Downcast.
byte[] byteTime = longToBytes(markRounding.getTime(), 6); MarkRounding markRounding = (MarkRounding) message;
byte[] byteAck = intToBytes(markRounding.getAckNum(), 2);
byte[] byteRaceID = intToBytes(markRounding.getRaceID(), 4); byte messageVersionNumber = markRounding.getMessageVersionNumber();
byte[] byteSourceID = intToBytes(markRounding.getSourceID(), 4); byte[] byteTime = longToBytes(markRounding.getTime(), 6);
byte[] byteBoatStatus = intToBytes(markRounding.getBoatStatus().getValue(), 1); byte[] byteAck = intToBytes(markRounding.getAckNum(), 2);
byte[] byteRoundingSide = intToBytes(markRounding.getRoundingSide().getValue(), 1); byte[] byteRaceID = intToBytes(markRounding.getRaceID(), 4);
byte[] byteMarkType = intToBytes(markRounding.getMarkType().getValue(), 1); byte[] byteSourceID = intToBytes(markRounding.getSourceID(), 4);
byte[] byteMarkID = intToBytes(markRounding.getMarkID(), 1); byte[] byteBoatStatus = intToBytes(markRounding.getBoatStatus().getValue(), 1);
byte[] byteRoundingSide = intToBytes(markRounding.getRoundingSide().getValue(), 1);
byte[] byteMarkType = intToBytes(markRounding.getMarkType().getValue(), 1);
byte[] byteMarkID = intToBytes(markRounding.getMarkID(), 1);
ByteBuffer result = ByteBuffer.allocate(21); ByteBuffer result = ByteBuffer.allocate(21);
result.put(messageVersionNumber); result.put(messageVersionNumber);
result.put(byteTime); result.put(byteTime);
result.put(byteAck); result.put(byteAck);
result.put(byteRaceID); result.put(byteRaceID);
result.put(byteSourceID); result.put(byteSourceID);
result.put(byteBoatStatus); result.put(byteBoatStatus);
result.put(byteRoundingSide); result.put(byteRoundingSide);
result.put(byteMarkType); result.put(byteMarkType);
result.put(byteMarkID); result.put(byteMarkID);
return result.array(); return result.array();
} catch (Exception e) {
throw new InvalidMessageException("Could not encode MarkRounding message.", e);
}
} }
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
@@ -15,7 +16,8 @@ public interface MessageEncoder {
* Encodes a given message. * Encodes a given message.
* @param message The message to encode. * @param message The message to encode.
* @return Message in byte encoded form. * @return Message in byte encoded form.
* @throws InvalidMessageException Thrown if the message is invalid in some way, or cannot be encoded.
*/ */
public byte[] encode(AC35Data message); public byte[] encode(AC35Data message) throws InvalidMessageException;
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.RaceStartStatus; import network.Messages.RaceStartStatus;
import network.Utils.ByteConverter; import network.Utils.ByteConverter;
@@ -24,28 +25,34 @@ public class RaceStartStatusEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
RaceStartStatus raceStartStatus = (RaceStartStatus) message;
//Downcast.
RaceStartStatus raceStartStatus = (RaceStartStatus) message;
byte messageVersion = raceStartStatus.getMessageVersionNumber(); byte messageVersion = raceStartStatus.getMessageVersionNumber();
byte[] timestamp = longToBytes(raceStartStatus.getTimestamp(), 6); byte[] timestamp = longToBytes(raceStartStatus.getTimestamp(), 6);
byte[] ackNumber = intToBytes(raceStartStatus.getAckNum(), 2); byte[] ackNumber = intToBytes(raceStartStatus.getAckNum(), 2);
byte[] raceStartTime = longToBytes(raceStartStatus.getRaceStartTime(), 6); byte[] raceStartTime = longToBytes(raceStartStatus.getRaceStartTime(), 6);
byte[] raceIdentifier = intToBytes(raceStartStatus.getRaceID()); byte[] raceIdentifier = intToBytes(raceStartStatus.getRaceID());
byte[] notificationType = intToBytes(raceStartStatus.getNotificationType().getValue(), 1); byte[] notificationType = intToBytes(raceStartStatus.getNotificationType().getValue(), 1);
ByteBuffer result = ByteBuffer.allocate(20); ByteBuffer result = ByteBuffer.allocate(20);
result.put(messageVersion); result.put(messageVersion);
result.put(timestamp); result.put(timestamp);
result.put(ackNumber); result.put(ackNumber);
result.put(raceStartTime); result.put(raceStartTime);
result.put(raceIdentifier); result.put(raceIdentifier);
result.put(notificationType); result.put(notificationType);
return result.array(); return result.array();
} catch (Exception e) {
throw new InvalidMessageException("Could not encode RaceStartStatus message.", e);
}
} }
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.BoatStatus; import network.Messages.BoatStatus;
import network.Messages.RaceStatus; import network.Messages.RaceStatus;
@@ -28,68 +29,74 @@ public class RaceStatusEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
RaceStatus raceStatus = (RaceStatus) message;
//Downcast.
RaceStatus raceStatus = (RaceStatus) message;
List<BoatStatus> boatStatuses = raceStatus.getBoatStatuses(); List<BoatStatus> boatStatuses = raceStatus.getBoatStatuses();
//24 byte header, plus 20 bytes per boat status. //24 byte header, plus 20 bytes per boat status.
ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20 * boatStatuses.size()); ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20 * boatStatuses.size());
//Version Number 1 bytes. this changes with the pdf. (2) //Version Number 1 bytes. this changes with the pdf. (2)
byte versionNum = 0b10; byte versionNum = 0b10;
//time (6 bytes) //time (6 bytes)
byte[] timeBytes = longToBytes(raceStatus.getCurrentTime(), 6); byte[] timeBytes = longToBytes(raceStatus.getCurrentTime(), 6);
//race identifier in case multiple races are going at once. //race identifier in case multiple races are going at once.
byte[] raceID = intToBytes(raceStatus.getRaceID()); byte[] raceID = intToBytes(raceStatus.getRaceID());
//race status 0 - 10 //race status 0 - 10
byte[] raceStatusByte = intToBytes(raceStatus.getRaceStatus().getValue(), 1); byte[] raceStatusByte = intToBytes(raceStatus.getRaceStatus().getValue(), 1);
//number of milliseconds from Jan 1, 1970 for when the data is valid //number of milliseconds from Jan 1, 1970 for when the data is valid
byte[] expectedStart = longToBytes(raceStatus.getExpectedStartTime(), 6); byte[] expectedStart = longToBytes(raceStatus.getExpectedStartTime(), 6);
//North = 0x0000 East = 0x4000 South = 0x8000. //North = 0x0000 East = 0x4000 South = 0x8000.
int windDirectionInt = AC35UnitConverter.packHeading(raceStatus.getWindDirection().degrees()); int windDirectionInt = AC35UnitConverter.packHeading(raceStatus.getWindDirection().degrees());
byte[] raceWind = intToBytes(windDirectionInt, 2); byte[] raceWind = intToBytes(windDirectionInt, 2);
//mm/sec //mm/sec
int windSpeedInt = AC35UnitConverter.packKnotsToMMperSec(raceStatus.getWindSpeed()); int windSpeedInt = AC35UnitConverter.packKnotsToMMperSec(raceStatus.getWindSpeed());
byte[] windSpeed = intToBytes(windSpeedInt, 2); byte[] windSpeed = intToBytes(windSpeedInt, 2);
byte[] numBoats = intToBytes(boatStatuses.size(), 1); byte[] numBoats = intToBytes(boatStatuses.size(), 1);
//1 match race, 2 fleet race //1 match race, 2 fleet race
byte[] bytesRaceType = intToBytes(raceStatus.getRaceType().getValue(), 1); byte[] bytesRaceType = intToBytes(raceStatus.getRaceType().getValue(), 1);
raceStatusMessage.put(versionNum); raceStatusMessage.put(versionNum);
raceStatusMessage.put(timeBytes); raceStatusMessage.put(timeBytes);
raceStatusMessage.put(raceID); raceStatusMessage.put(raceID);
raceStatusMessage.put(raceStatusByte); raceStatusMessage.put(raceStatusByte);
raceStatusMessage.put(expectedStart); raceStatusMessage.put(expectedStart);
raceStatusMessage.put(raceWind); raceStatusMessage.put(raceWind);
raceStatusMessage.put(windSpeed); raceStatusMessage.put(windSpeed);
raceStatusMessage.put(numBoats); raceStatusMessage.put(numBoats);
raceStatusMessage.put(bytesRaceType); raceStatusMessage.put(bytesRaceType);
//Encode each BoatStatus. //Encode each BoatStatus.
for (BoatStatus boatStatus : boatStatuses) { for (BoatStatus boatStatus : boatStatuses) {
BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder(); BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder();
byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus); byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus);
raceStatusMessage.put(boatStatusEncoded); raceStatusMessage.put(boatStatusEncoded);
}
return raceStatusMessage.array();
} catch (Exception e) {
throw new InvalidMessageException("Could not encode RaceStatus message.", e);
} }
return raceStatusMessage.array();
} }
} }
@@ -113,8 +113,10 @@ public class RaceVisionByteEncoder {
MessageEncoder encoder = null; MessageEncoder encoder = null;
try { try {
encoder = EncoderFactory.create(message.getType()); encoder = EncoderFactory.create(message.getType());
} catch (InvalidMessageTypeException e) { } catch (InvalidMessageTypeException e) {
throw new InvalidMessageException("Could not create encoder for MessageType: " + message.getType(), e); throw new InvalidMessageException("Could not create encoder for MessageType: " + message.getType(), e);
} }
byte[] encodedMessage = encoder.encode(message); byte[] encodedMessage = encoder.encode(message);
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.RequestToJoin; import network.Messages.RequestToJoin;
import network.Utils.ByteConverter; import network.Utils.ByteConverter;
@@ -21,19 +22,25 @@ public class RequestToJoinEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
RequestToJoin requestToJoin = (RequestToJoin) message;
//Downcast.
RequestToJoin requestToJoin = (RequestToJoin) message;
ByteBuffer requestToJoinBuffer = ByteBuffer.allocate(4); ByteBuffer requestToJoinBuffer = ByteBuffer.allocate(4);
requestToJoinBuffer.put(ByteConverter.intToBytes(requestToJoin.getRequestType().getValue(), 4)); requestToJoinBuffer.put(ByteConverter.intToBytes(requestToJoin.getRequestType().getValue(), 4));
byte [] result = requestToJoinBuffer.array(); byte[] result = requestToJoinBuffer.array();
return result; return result;
} catch (Exception e) {
throw new InvalidMessageException("Could not encode RequestToJoin message.", e);
}
} }
} }
@@ -1,6 +1,7 @@
package network.MessageEncoders; package network.MessageEncoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data; import network.Messages.AC35Data;
import network.Messages.XMLMessage; import network.Messages.XMLMessage;
@@ -24,39 +25,45 @@ public class XMLMessageEncoder implements MessageEncoder {
@Override @Override
public byte[] encode(AC35Data message) { public byte[] encode(AC35Data message) throws InvalidMessageException {
//Downcast. try {
XMLMessage xmlMessage = (XMLMessage) message;
//Downcast.
XMLMessage xmlMessage = (XMLMessage) message;
byte[] messageBytes = xmlMessage.getXmlMessage().getBytes(StandardCharsets.UTF_8); byte[] messageBytes = xmlMessage.getXmlMessage().getBytes(StandardCharsets.UTF_8);
//Message is 14 + xmlMessage.length bytes. //Message is 14 + xmlMessage.length bytes.
ByteBuffer tempOutputByteBuffer = ByteBuffer.allocate(14 + messageBytes.length); ByteBuffer tempOutputByteBuffer = ByteBuffer.allocate(14 + messageBytes.length);
//ackNumber converted to bytes //ackNumber converted to bytes
byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2); byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2);
//Timestamp converted to bytes. //Timestamp converted to bytes.
byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6); byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6);
//sequenceNumber converted to bytes //sequenceNumber converted to bytes
byte[] sequenceNumberBytes = intToBytes(xmlMessage.getSequenceNumber(), 2); byte[] sequenceNumberBytes = intToBytes(xmlMessage.getSequenceNumber(), 2);
//xmlMsgLength converted to bytes //xmlMsgLength converted to bytes
byte[] xmlMsgLengthBytes = intToBytes(xmlMessage.getXmlMsgLength(), 2); byte[] xmlMsgLengthBytes = intToBytes(xmlMessage.getXmlMsgLength(), 2);
tempOutputByteBuffer.put(xmlMessage.getVersionNumber()); tempOutputByteBuffer.put(xmlMessage.getVersionNumber());
tempOutputByteBuffer.put(ackNumberBytes); tempOutputByteBuffer.put(ackNumberBytes);
tempOutputByteBuffer.put(timestampBytes); tempOutputByteBuffer.put(timestampBytes);
tempOutputByteBuffer.put(xmlMessage.getXmlMsgSubType().getValue()); tempOutputByteBuffer.put(xmlMessage.getXmlMsgSubType().getValue());
tempOutputByteBuffer.put(sequenceNumberBytes); tempOutputByteBuffer.put(sequenceNumberBytes);
tempOutputByteBuffer.put(xmlMsgLengthBytes); tempOutputByteBuffer.put(xmlMsgLengthBytes);
tempOutputByteBuffer.put(messageBytes); tempOutputByteBuffer.put(messageBytes);
return tempOutputByteBuffer.array(); return tempOutputByteBuffer.array();
} catch (Exception e) {
throw new InvalidMessageException("Could not encode XMLMessage message.", e);
}
} }
} }
@@ -56,18 +56,21 @@ public class ControllerClient {
BoatAction boatAction = new BoatAction(protocolCode); BoatAction boatAction = new BoatAction(protocolCode);
//Encode BoatAction. //Encode BoatAction.
byte[] encodedBoatAction = new byte[0];
try { try {
encodedBoatAction = RaceVisionByteEncoder.encode(boatAction); byte[] encodedBoatAction = RaceVisionByteEncoder.encode(boatAction);
BinaryMessageEncoder binaryMessage = new BinaryMessageEncoder(MessageType.BOATACTION, System.currentTimeMillis(), 0,
(short) encodedBoatAction.length, encodedBoatAction);
System.out.println("Sending out key: " + protocolCode);
outputStream.write(binaryMessage.getFullMessage());
} catch (InvalidMessageException e) { } catch (InvalidMessageException e) {
Logger.getGlobal().log(Level.WARNING, "Could not encode BoatAction: " + boatAction, e); Logger.getGlobal().log(Level.WARNING, "Could not encode BoatAction: " + boatAction, e);
} }
BinaryMessageEncoder binaryMessage = new BinaryMessageEncoder(MessageType.BOATACTION, System.currentTimeMillis(), 0,
(short) encodedBoatAction.length, encodedBoatAction);
System.out.println("Sending out key: " + protocolCode);
outputStream.write(binaryMessage.getFullMessage());
} }
} }
} }
@@ -1,6 +1,7 @@
package visualiser.gameController; package visualiser.gameController;
import network.BinaryMessageDecoder; import network.BinaryMessageDecoder;
import network.Exceptions.InvalidMessageException;
import network.MessageDecoders.BoatActionDecoder; import network.MessageDecoders.BoatActionDecoder;
import network.Messages.BoatAction; import network.Messages.BoatAction;
import network.Messages.Enums.BoatActionEnum; import network.Messages.Enums.BoatActionEnum;
@@ -10,6 +11,8 @@ import visualiser.gameController.Keys.KeyFactory;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Service for dispatching key press data to race from client * Service for dispatching key press data to race from client
@@ -46,12 +49,22 @@ public class ControllerServer implements Runnable {
byte[] message = new byte[20]; byte[] message = new byte[20];
try { try {
if (inputStream.available() > 0) { if (inputStream.available() > 0) {
inputStream.read(message); inputStream.read(message);
BinaryMessageDecoder encodedMessage = new BinaryMessageDecoder(message); BinaryMessageDecoder encodedMessage = new BinaryMessageDecoder(message);
BoatActionDecoder boatActionDecoder = new BoatActionDecoder(); BoatActionDecoder boatActionDecoder = new BoatActionDecoder();
boatActionDecoder.decode(encodedMessage.getMessageBody());
BoatAction boatAction = boatActionDecoder.getMessage(); try {
System.out.println("Received key: " + boatAction.getBoatAction()); boatActionDecoder.decode(encodedMessage.getMessageBody());
BoatAction boatAction = boatActionDecoder.getMessage();
System.out.println("Received key: " + boatAction.getBoatAction());
} catch (InvalidMessageException e) {
Logger.getGlobal().log(Level.WARNING, "Could not decode BoatAction message.", e);
}
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@@ -1,5 +1,6 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.MessageEncoders.BoatStatusEncoder; import network.MessageEncoders.BoatStatusEncoder;
import network.MessageEncoders.RaceVisionByteEncoder; import network.MessageEncoders.RaceVisionByteEncoder;
import network.Messages.BoatStatus; import network.Messages.BoatStatus;
@@ -55,8 +56,9 @@ public class BoatStatusDecoderTest {
* Encodes and decodes a BoatStatus, and returns it. * Encodes and decodes a BoatStatus, and returns it.
* @param boatStatus The BoatStatus to encode and decode. * @param boatStatus The BoatStatus to encode and decode.
* @return The decoded BoatStatus. * @return The decoded BoatStatus.
* @throws InvalidMessageException Thrown if message cannot be encoded or decoded.
*/ */
private static BoatStatus encodeDecodeBoatStatus(BoatStatus boatStatus) { private static BoatStatus encodeDecodeBoatStatus(BoatStatus boatStatus) throws InvalidMessageException {
BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder(); BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder();
byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus); byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus);
@@ -1,5 +1,6 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.MessageEncoders.CourseWindEncoder; import network.MessageEncoders.CourseWindEncoder;
import network.Messages.BoatStatus; import network.Messages.BoatStatus;
import network.Messages.CourseWind; import network.Messages.CourseWind;
@@ -43,8 +44,9 @@ public class CourseWindDecoderTest {
* Encodes and decodes a CourseWind, and returns it. * Encodes and decodes a CourseWind, and returns it.
* @param courseWind The CourseWind to encode and decode. * @param courseWind The CourseWind to encode and decode.
* @return The decoded CourseWind. * @return The decoded CourseWind.
* @throws InvalidMessageException Thrown if message cannot be encoded or decoded.
*/ */
private static CourseWind encodeDecodeCourseWind(CourseWind courseWind) { private static CourseWind encodeDecodeCourseWind(CourseWind courseWind) throws InvalidMessageException {
CourseWindEncoder courseWindEncoder = new CourseWindEncoder(); CourseWindEncoder courseWindEncoder = new CourseWindEncoder();
byte[] courseWindEncoded = courseWindEncoder.encode(courseWind); byte[] courseWindEncoded = courseWindEncoder.encode(courseWind);