From 750ea5c141c81432104043a5c8960f196a16f8b8 Mon Sep 17 00:00:00 2001 From: fjc40 Date: Sun, 6 Aug 2017 18:51:13 +1200 Subject: [PATCH] Added MessageDecoder interface. All decoder implement this. Added DecoderFactory. This creates an appropriate decoder based on a MessageType. BoatActionDecoder implements MessageDecoder. BoatLocationDecoder implements MessageDecoder. HeartBeatDecoder implements MessageDecoder. JoinAcceptance implements MessageDecoder. RaceStatusDecoder implements MessageDecoder. RequestToJoinDecoder implements MessageDecoder. XMLMessageDecoder implements MessageDecoder. Refactored CourseWind decoder/encoder. CourseWind decoder/encoder is for an individual CourseWind. CourseWinds decoder/encoder is for the combined message from the API. Documented BoatAction, and it now contains a BoatActionEnum instead of a byte. Refactored CourseWind and CourseWinds classes. They now expose correct units, instead of packed units. Added CourseWindDecoderTest, and updated CourseWindsDecoderTest. issue #35 #36 #story[1095] --- .../java/network/BinaryMessageDecoder.java | 35 +++-- .../MessageDecoders/BoatActionDecoder.java | 48 +++++-- .../MessageDecoders/BoatLocationDecoder.java | 19 ++- .../MessageDecoders/BoatStatusDecoder.java | 12 +- .../MessageDecoders/CourseWindDecoder.java | 120 +++++++++++------- .../MessageDecoders/CourseWindsDecoder.java | 87 +++++++++++++ .../MessageDecoders/DecoderFactory.java | 70 ++++++++++ .../MessageDecoders/HeartBeatDecoder.java | 19 ++- .../JoinAcceptanceDecoder.java | 18 ++- .../MessageDecoders/MessageDecoder.java | 21 +++ .../MessageDecoders/RaceStatusDecoder.java | 29 +++-- .../MessageDecoders/RequestToJoinDecoder.java | 18 ++- .../MessageDecoders/XMLMessageDecoder.java | 19 ++- .../MessageEncoders/BoatActionEncoder.java | 2 +- .../MessageEncoders/CourseWindEncoder.java | 73 +++++++++++ .../MessageEncoders/CourseWindsEncoder.java | 57 +++++++++ .../MessageEncoders/EncoderFactory.java | 2 +- .../RaceVisionByteEncoder.java | 21 +-- .../java/network/Messages/BoatAction.java | 21 ++- .../java/network/Messages/CourseWind.java | 101 +++++++++++++-- .../java/network/Messages/CourseWinds.java | 58 ++++++++- .../gameController/ControllerServer.java | 8 +- .../BoatActionDecoderTest.java | 6 +- .../BoatLocationDecoderTest.java | 3 +- .../BoatStatusDecoderTest.java | 6 +- .../CourseWindDecoderTest.java | 90 ++++++++----- .../CourseWindsDecoderTest.java | 96 ++++++++++++++ .../MessageDecoders/HeartBeatDecoderTest.java | 3 +- .../JoinAcceptanceDecoderTest.java | 3 +- .../RaceStatusDecoderTest.java | 3 +- .../RequestToJoinDecoderTest.java | 3 +- .../XMLMessageDecoderTest.java | 3 +- 32 files changed, 840 insertions(+), 234 deletions(-) create mode 100644 racevisionGame/src/main/java/network/MessageDecoders/CourseWindsDecoder.java create mode 100644 racevisionGame/src/main/java/network/MessageDecoders/DecoderFactory.java create mode 100644 racevisionGame/src/main/java/network/MessageDecoders/MessageDecoder.java create mode 100644 racevisionGame/src/main/java/network/MessageEncoders/CourseWindEncoder.java create mode 100644 racevisionGame/src/main/java/network/MessageEncoders/CourseWindsEncoder.java create mode 100644 racevisionGame/src/test/java/network/MessageDecoders/CourseWindsDecoderTest.java diff --git a/racevisionGame/src/main/java/network/BinaryMessageDecoder.java b/racevisionGame/src/main/java/network/BinaryMessageDecoder.java index eb9c6997..0ee0d541 100644 --- a/racevisionGame/src/main/java/network/BinaryMessageDecoder.java +++ b/racevisionGame/src/main/java/network/BinaryMessageDecoder.java @@ -2,6 +2,7 @@ package network; import network.Exceptions.InvalidMessageException; +import network.Exceptions.InvalidMessageTypeException; import network.MessageDecoders.*; import network.Messages.*; import network.Messages.Enums.MessageType; @@ -130,16 +131,26 @@ public class BinaryMessageDecoder { //Now we create the message object based on what is actually in the message body. MessageType mType = MessageType.fromByte(headerMessageType); + /*MessageDecoder decoder = null; + try { + decoder = DecoderFactory.create(mType); + } catch (InvalidMessageTypeException e) { + throw new InvalidMessageException("Could not create decoder for MessageType: " + mType, e); + } + + return decoder.decode(messageBody);*/ + + switch(mType) { case HEARTBEAT: //System.out.println("Decoding HeartBeat Message!"); - HeartBeatDecoder heartBeatDecoder = new HeartBeatDecoder(messageBody); - return heartBeatDecoder.getMessage(); + HeartBeatDecoder heartBeatDecoder = new HeartBeatDecoder(); + return heartBeatDecoder.decode(messageBody); case RACESTATUS: //System.out.println("Race Status Message"); - RaceStatusDecoder rsdecoder = new RaceStatusDecoder(messageBody); - return rsdecoder.getMessage(); + RaceStatusDecoder rsdecoder = new RaceStatusDecoder(); + return rsdecoder.decode(messageBody); case DISPLAYTEXTMESSAGE: //System.out.println("Display Text Message"); @@ -148,8 +159,8 @@ public class BinaryMessageDecoder { case XMLMESSAGE: //System.out.println("XML Message!"); - XMLMessageDecoder xmdecoder = new XMLMessageDecoder(messageBody); - return xmdecoder.getMessage(); + XMLMessageDecoder xmdecoder = new XMLMessageDecoder(); + return xmdecoder.decode(messageBody); case RACESTARTSTATUS: //System.out.println("Race Start Status Message"); @@ -173,8 +184,8 @@ public class BinaryMessageDecoder { case BOATLOCATION: //System.out.println("Boat Location Message!"); - BoatLocationDecoder blDecoder = new BoatLocationDecoder(messageBody); - return blDecoder.getMessage(); + BoatLocationDecoder blDecoder = new BoatLocationDecoder(); + return blDecoder.decode(messageBody); case MARKROUNDING: //System.out.println("Mark Rounding Message!"); @@ -183,8 +194,8 @@ public class BinaryMessageDecoder { case COURSEWIND: //System.out.println("Course Wind Message!"); - CourseWindDecoder cwDecoder = new CourseWindDecoder(messageBody); - return new CourseWinds(cwDecoder.getMessageVersionNumber(), cwDecoder.getByteWindID(), cwDecoder.getLoopMessages()); + CourseWindsDecoder cwDecoder = new CourseWindsDecoder(); + return cwDecoder.decode(messageBody); case AVGWIND: //System.out.println("Average Wind Message!"); @@ -192,8 +203,8 @@ public class BinaryMessageDecoder { return awDecoder.getAverageWind(); case BOATACTION: - BoatActionDecoder baDecoder = new BoatActionDecoder(messageBody); - return new BoatAction(baDecoder.getBoatAction()); + BoatActionDecoder baDecoder = new BoatActionDecoder(); + return baDecoder.decode(messageBody); default: //System.out.println("Broken Message!"); diff --git a/racevisionGame/src/main/java/network/MessageDecoders/BoatActionDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/BoatActionDecoder.java index bf2076b5..a3a5d38a 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/BoatActionDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/BoatActionDecoder.java @@ -1,20 +1,50 @@ package network.MessageDecoders; +import network.Messages.AC35Data; +import network.Messages.BoatAction; import network.Messages.Enums.BoatActionEnum; import java.util.Arrays; -public class BoatActionDecoder { - byte byteBoatAction; - BoatActionEnum boatAction; +/** + * Decodes {@link BoatAction} messages. + */ +public class BoatActionDecoder implements MessageDecoder { - public BoatActionDecoder(byte[] encodedBoatAction) { - byteBoatAction = encodedBoatAction[0]; + /** + * The encoded message. + */ + private byte[] encodedMessage; - boatAction = BoatActionEnum.fromByte(byteBoatAction); + /** + * The decoded message. + */ + private BoatAction message; + + + /** + * Constructs a decoder to decode a given message. + */ + public BoatActionDecoder() { + } + + @Override + public AC35Data decode(byte[] encodedMessage) { + this.encodedMessage = encodedMessage; + + BoatActionEnum boatActionEnum = BoatActionEnum.fromByte(encodedMessage[0]); + + message = new BoatAction(boatActionEnum); + + return message; } - public BoatActionEnum getBoatAction() { - return boatAction; + + /** + * Returns the decoded message. + * @return The decoded message. + */ + public BoatAction getMessage() { + return message; } -} \ No newline at end of file +} diff --git a/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java index 46a4dccd..1e175588 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Messages.AC35Data; import network.Messages.BoatLocation; import network.Messages.Enums.BoatLocationDeviceEnum; import shared.model.Azimuth; @@ -15,7 +16,7 @@ import static network.Utils.ByteConverter.*; /** * Decodes {@link BoatLocation} messages. */ -public class BoatLocationDecoder { +public class BoatLocationDecoder implements MessageDecoder { /** * The encoded message. @@ -32,20 +33,14 @@ public class BoatLocationDecoder { /** * Constructs a decoder to decode a given message. - * @param encodedMessage The message to decode. */ - public BoatLocationDecoder(byte[] encodedMessage) { - - this.encodedMessage = encodedMessage; - - decode(); + public BoatLocationDecoder() { } - /** - * Decodes the contained message. - */ - private void decode() { + @Override + public AC35Data decode(byte[] encodedMessage) { + this.encodedMessage = encodedMessage; byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1); byte messageVersionNumber = messageVersionNumberBytes[0]; @@ -152,6 +147,8 @@ public class BoatLocationDecoder { currentSet, rudderAngle ); + return message; + } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/BoatStatusDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/BoatStatusDecoder.java index dd482486..972c1eae 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/BoatStatusDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/BoatStatusDecoder.java @@ -30,19 +30,17 @@ public class BoatStatusDecoder { /** * Constructs a decoder to decode a given message. - * @param encodedMessage The message to decode. */ - public BoatStatusDecoder(byte[] encodedMessage) { - this.encodedMessage = encodedMessage; - - decode(); + public BoatStatusDecoder() { } /** * Decodes the contained message. + * @param encodedMessage The message to decode. */ - private void decode() { + public BoatStatus decode(byte[] encodedMessage) { + this.encodedMessage = encodedMessage; byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 0, 4); @@ -75,6 +73,8 @@ public class BoatStatusDecoder { estTimeAtNextMark, estTimeAtFinish ); + return message; + } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/CourseWindDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/CourseWindDecoder.java index 038a79d2..78bc6f1c 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/CourseWindDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/CourseWindDecoder.java @@ -2,63 +2,93 @@ package network.MessageDecoders; import network.Messages.CourseWind; +import shared.model.Bearing; -import java.util.ArrayList; import java.util.Arrays; -import static network.Utils.ByteConverter.bytesToInt; -import static network.Utils.ByteConverter.bytesToLong; +import static network.Utils.AC35UnitConverter.*; +import static network.Utils.ByteConverter.*; /** - * Created by hba56 on 23/04/17. + * Decodes {@link CourseWind} messages. */ public class CourseWindDecoder { - byte messageVersionNumber; - byte byteWindID; - byte loopCount; - ArrayList loopMessages = new ArrayList(); - - public CourseWindDecoder(byte[] encodedCourseWind) { - final int lengthInBytesOfMessages = 20; - - messageVersionNumber = encodedCourseWind[0]; - byteWindID = encodedCourseWind[1]; - loopCount = encodedCourseWind[2]; - byte[] loopMessagesBytes = Arrays.copyOfRange(encodedCourseWind, 3, lengthInBytesOfMessages*loopCount+3); - int messageLoopIndex = 0; - - for (int i=0; i < loopCount; i++) { - byte[] messageBytes = Arrays.copyOfRange(loopMessagesBytes, messageLoopIndex, messageLoopIndex+20); - ArrayList test = new ArrayList(); - byte[] windId = Arrays.copyOfRange(messageBytes, 0, 1); - byte[] time = Arrays.copyOfRange(messageBytes, 1, 7); - byte[] raceID = Arrays.copyOfRange(messageBytes, 7, 11); - byte[] windDirection = Arrays.copyOfRange(messageBytes, 11, 13); - byte[] windSpeed = Arrays.copyOfRange(messageBytes, 13, 15); - byte[] bestUpwindAngle = Arrays.copyOfRange(messageBytes, 15, 17); - byte[] bestDownwindAngle = Arrays.copyOfRange(messageBytes, 17, 19); - byte[] flags = Arrays.copyOfRange(messageBytes, 19, 20); - - CourseWind message = new CourseWind(windId[0], bytesToLong(time), - bytesToInt(raceID), bytesToInt(windDirection), - bytesToInt(windSpeed), bytesToInt(bestUpwindAngle), - bytesToInt(bestDownwindAngle), flags[0]); - - loopMessages.add(message); - messageLoopIndex += 20; - } - } - public ArrayList getLoopMessages() { - return loopMessages; + /** + * The encoded message. + */ + private byte[] encodedMessage; + + /** + * The decoded message. + */ + private CourseWind message; + + + + /** + * Constructs a decoder to decode a given message. + */ + public CourseWindDecoder() { } - public byte getMessageVersionNumber() { - return messageVersionNumber; + + /** + * Decodes the contained message. + * @param encodedMessage The message to decode. + */ + public CourseWind decode(byte[] encodedMessage) { + this.encodedMessage = encodedMessage; + + byte[] windId = Arrays.copyOfRange(encodedMessage, 0, 1); + + byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7); + long time = bytesToLong(timeBytes); + + byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11); + int raceIDInt = bytesToInt(raceIDBytes); + + byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 11, 13); + int windDirectionInt = bytesToInt(windDirectionBytes); + Bearing windDirection = Bearing.fromDegrees(unpackHeading(windDirectionInt)); + + byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 13, 15); + int windSpeedInt = bytesToInt(windSpeedBytes); + double windSpeedKnots = unpackMMperSecToKnots(windSpeedInt); + + byte[] bestUpwindAngleBytes = Arrays.copyOfRange(encodedMessage, 15, 17); + int bestUpwindAngleInt = bytesToInt(bestUpwindAngleBytes); + Bearing bestUpwindAngle = Bearing.fromDegrees(unpackHeading(bestUpwindAngleInt)); + + 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] ); + + return message; } - public byte getByteWindID() { - return byteWindID; + + /** + * Returns the decoded message. + * @return The decoded message. + */ + public CourseWind getMessage() { + return message; } + } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/CourseWindsDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/CourseWindsDecoder.java new file mode 100644 index 00000000..f478ac6b --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageDecoders/CourseWindsDecoder.java @@ -0,0 +1,87 @@ +package network.MessageDecoders; + + +import network.Messages.AC35Data; +import network.Messages.CourseWind; +import network.Messages.CourseWinds; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static network.Utils.ByteConverter.bytesToInt; +import static network.Utils.ByteConverter.bytesToLong; + + +/** + * Decodes {@link CourseWinds} messages. + */ +public class CourseWindsDecoder implements MessageDecoder { + + /** + * The encoded message. + */ + private byte[] encodedMessage; + + /** + * The decoded message. + */ + private CourseWinds message; + + + + /** + * Constructs a decoder to decode a given message. + */ + public CourseWindsDecoder() { + } + + + @Override + public AC35Data decode(byte[] encodedMessage) { + this.encodedMessage = encodedMessage; + + //The header is three bytes. + byte messageVersionNumber = encodedMessage[0]; + byte byteWindID = encodedMessage[1]; + byte loopCount = encodedMessage[2]; + + + //A CourseWind object is 20 bytes. + final int courseWindByteLength = 20; + + List loopMessages = new ArrayList(); + + //The header is 3 bytes, so we need the remaining bytes. + byte[] loopMessagesBytes = Arrays.copyOfRange(encodedMessage, 3, courseWindByteLength * loopCount + 3); + + for (int messageLoopIndex = 0; messageLoopIndex < (loopCount * courseWindByteLength); messageLoopIndex += courseWindByteLength) { + + byte[] messageBytes = Arrays.copyOfRange(loopMessagesBytes, messageLoopIndex, messageLoopIndex + courseWindByteLength); + + CourseWindDecoder courseWindDecoder = new CourseWindDecoder(); + CourseWind courseWind = courseWindDecoder.decode(messageBytes); + + loopMessages.add(courseWind); + } + + + + message = new CourseWinds( + messageVersionNumber, + byteWindID, + loopMessages ); + + return message; + } + + + /** + * Returns the decoded message. + * @return The decoded message. + */ + public CourseWinds getMessage() { + return message; + } + +} diff --git a/racevisionGame/src/main/java/network/MessageDecoders/DecoderFactory.java b/racevisionGame/src/main/java/network/MessageDecoders/DecoderFactory.java new file mode 100644 index 00000000..500d20f6 --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageDecoders/DecoderFactory.java @@ -0,0 +1,70 @@ +package network.MessageDecoders; + + +import network.Exceptions.InvalidMessageTypeException; +import network.Messages.Enums.MessageType; + +/** + * Factory to create the appropriate decoder for a given message. + */ +public class DecoderFactory { + + + /** + * Private constructor. Currently doesn't need to be constructed. + */ + private DecoderFactory(){ + + } + + + /** + * Creates the correct type of decoder for a given message type. + * @param type Type of message you want a decoder for. + * @return The decoder. + * @throws InvalidMessageTypeException If you pass in a {@link MessageType} that isn't recognised. + */ + public static MessageDecoder create(MessageType type) throws InvalidMessageTypeException { + + + switch (type) { + + case HEARTBEAT: return new HeartBeatDecoder(); + + case RACESTATUS: return new RaceStatusDecoder(); + + //case DISPLAYTEXTMESSAGE: return new DisplayTextMessageDecoder();//TODO + + case XMLMESSAGE: return new XMLMessageDecoder(); + + //case RACESTARTSTATUS: return new RaceStartStatusDecoder();//TODO + + //case YACHTEVENTCODE: return new YachtEventCodeDecoder();//TODO + + //case YACHTACTIONCODE: return new YachtActionCodeDecoder();//TODO + + //case CHATTERTEXT: return new ChatterTextDecoder();//TODO + + case BOATLOCATION: return new BoatLocationDecoder(); + + //case MARKROUNDING: return new MarkRoundingDecoder()//TODO; + + case COURSEWIND: return new CourseWindsDecoder(); + + //case AVGWIND: return new AverageWindDecoder()//TODO; + + case REQUEST_TO_JOIN: return new RequestToJoinDecoder(); + + case JOIN_ACCEPTANCE: return new JoinAcceptanceDecoder(); + + case BOATACTION: return new BoatActionDecoder(); + + + default: throw new InvalidMessageTypeException("Unrecognised message type: " + type); + } + + + + } + +} diff --git a/racevisionGame/src/main/java/network/MessageDecoders/HeartBeatDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/HeartBeatDecoder.java index 0984a9ea..49cdcc5f 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/HeartBeatDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/HeartBeatDecoder.java @@ -1,5 +1,6 @@ package network.MessageDecoders; +import network.Messages.AC35Data; import network.Messages.Enums.BoatActionEnum; import network.Messages.HeartBeat; @@ -8,7 +9,7 @@ import static network.Utils.ByteConverter.bytesToLong; /** * Decodes {@link network.Messages.HeartBeat} messages. */ -public class HeartBeatDecoder { +public class HeartBeatDecoder implements MessageDecoder { /** * The encoded message. @@ -24,21 +25,17 @@ public class HeartBeatDecoder { /** * Constructs a decoder to decode a given message. - * @param encodedMessage The message to decode. */ - public HeartBeatDecoder(byte[] encodedMessage) { - this.encodedMessage = encodedMessage; - - decode(); + public HeartBeatDecoder() { } - - /** - * Decodes the contained message. - */ - private void decode() { + @Override + public AC35Data decode(byte[] encodedMessage) { + this.encodedMessage = encodedMessage; message = new HeartBeat(bytesToLong(encodedMessage)); + + return message; } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/JoinAcceptanceDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/JoinAcceptanceDecoder.java index 95c3889e..eaa82c18 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/JoinAcceptanceDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/JoinAcceptanceDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Messages.AC35Data; import network.Messages.Enums.JoinAcceptanceEnum; import network.Messages.JoinAcceptance; import network.Utils.ByteConverter; @@ -10,7 +11,7 @@ import java.util.Arrays; /** * Decoder for {@link JoinAcceptance} messages. */ -public class JoinAcceptanceDecoder { +public class JoinAcceptanceDecoder implements MessageDecoder { /** * The encoded message. @@ -25,19 +26,14 @@ public class JoinAcceptanceDecoder { /** * Constructs a decoder to decode a given message. - * @param encodedMessage The message to decode. */ - public JoinAcceptanceDecoder(byte[] encodedMessage) { - this.encodedMessage = encodedMessage; - - decode(); + public JoinAcceptanceDecoder() { } - /** - * Decodes the contained message. - */ - private void decode() { + @Override + public AC35Data decode(byte[] encodedMessage) { + this.encodedMessage = encodedMessage; //SourceID is first four bytes. byte[] sourceIdBytes = Arrays.copyOfRange(encodedMessage, 0, 4); @@ -55,6 +51,8 @@ public class JoinAcceptanceDecoder { message = new JoinAcceptance(acceptanceType, sourceID); + + return message; } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/MessageDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/MessageDecoder.java new file mode 100644 index 00000000..39b4370f --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageDecoders/MessageDecoder.java @@ -0,0 +1,21 @@ +package network.MessageDecoders; + + +import network.Messages.AC35Data; + + +/** + * This is the interface that all message decoders must implement. + * It allows for {@link #decode(byte[])}ing messages. + */ +public interface MessageDecoder { + + + /** + * Decodes a given message. + * @param encodedMessage The message to decode. + * @return The decoded message. + */ + public AC35Data decode(byte[] encodedMessage); + +} diff --git a/racevisionGame/src/main/java/network/MessageDecoders/RaceStatusDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/RaceStatusDecoder.java index 307c2815..15700f49 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/RaceStatusDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/RaceStatusDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Messages.AC35Data; import network.Messages.BoatStatus; import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RaceTypeEnum; @@ -20,7 +21,7 @@ import static network.Utils.ByteConverter.bytesToShort; /** * Decodes {@link RaceStatus} messages. */ -public class RaceStatusDecoder { +public class RaceStatusDecoder implements MessageDecoder { /** * The encoded message. @@ -36,19 +37,14 @@ public class RaceStatusDecoder { /** * Constructs a decoder to decode a given message. - * @param encodedMessage The message to decode. */ - public RaceStatusDecoder(byte[] encodedMessage) { - this.encodedMessage = encodedMessage; - - decode(); + public RaceStatusDecoder() { } - /** - * Decodes the contained message. - */ - private void decode() { + @Override + public AC35Data decode(byte[] encodedMessage) { + this.encodedMessage = encodedMessage; byte[] versionNumBytes = Arrays.copyOfRange(encodedMessage, 0, 1); @@ -84,15 +80,18 @@ public class RaceStatusDecoder { List boatStatuses = new ArrayList<>(); + //BoatStatus is 20 bytes. + int boatStatusByteLength = 20; + //Decode each BoatStatus. - for (int boatLoopIndex=0; boatLoopIndex < (numberOfBoats * 20); boatLoopIndex += 20) { + for (int boatLoopIndex = 0; boatLoopIndex < (numberOfBoats * boatStatusByteLength); boatLoopIndex += boatStatusByteLength) { - byte[] boatStatusBytes = Arrays.copyOfRange(boatStatusesBytes, boatLoopIndex, boatLoopIndex + 20); + byte[] boatStatusBytes = Arrays.copyOfRange(boatStatusesBytes, boatLoopIndex, boatLoopIndex + boatStatusByteLength); - BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder(boatStatusBytes); + BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder(); - boatStatuses.add(boatStatusDecoder.getMessage()); + boatStatuses.add(boatStatusDecoder.decode(boatStatusBytes)); } @@ -106,6 +105,8 @@ public class RaceStatusDecoder { windSpeedKnots, raceType, boatStatuses ); + + return message; } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/RequestToJoinDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/RequestToJoinDecoder.java index 2d272f05..1abf61a6 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/RequestToJoinDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/RequestToJoinDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Messages.AC35Data; import network.Messages.Enums.RequestToJoinEnum; import network.Messages.RequestToJoin; import network.Utils.ByteConverter; @@ -10,7 +11,7 @@ import java.util.Arrays; /** * Decoder for {@link network.Messages.RequestToJoin} messages. */ -public class RequestToJoinDecoder { +public class RequestToJoinDecoder implements MessageDecoder{ /** * The encoded message. @@ -24,19 +25,14 @@ public class RequestToJoinDecoder { /** * Constructs a decoder to decode a given message. - * @param encodedRequest The message to decode. */ - public RequestToJoinDecoder(byte[] encodedRequest) { - this.encodedRequest = encodedRequest; - - decode(); + public RequestToJoinDecoder() { } - /** - * Decodes the contained message. - */ - private void decode() { + @Override + public AC35Data decode(byte[] encodedRequest) { + this.encodedRequest = encodedRequest; //Request type is first four bytes. byte[] requestTypeBytes = Arrays.copyOfRange(encodedRequest, 0, 4); @@ -47,6 +43,8 @@ public class RequestToJoinDecoder { message = new RequestToJoin(requestType); + + return message; } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java index 4fb985a1..99c56e28 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java @@ -1,5 +1,6 @@ package network.MessageDecoders; +import network.Messages.AC35Data; import network.Messages.Enums.XMLMessageType; import network.Messages.XMLMessage; @@ -12,7 +13,7 @@ import static network.Utils.ByteConverter.bytesToShort; /** * Decodes {@link network.Messages.XMLMessage} messages. */ -public class XMLMessageDecoder { +public class XMLMessageDecoder implements MessageDecoder { /** * The encoded message. @@ -28,18 +29,14 @@ public class XMLMessageDecoder { /** * Constructs a decoder to decode a given message. - * @param encodedMessage The message to decode. */ - public XMLMessageDecoder(byte[] encodedMessage) { - this.encodedMessage = encodedMessage; - - decode(); + public XMLMessageDecoder() { } - /** - * Decodes the contained message. - */ - private void decode() { + + @Override + public AC35Data decode(byte[] encodedMessage) { + this.encodedMessage = encodedMessage; byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1); byte[] ackNumberBytes = Arrays.copyOfRange(encodedMessage, 1, 3); @@ -66,6 +63,8 @@ public class XMLMessageDecoder { xmlMsgSubType, sequenceNumber, xmlMessage ); + + return message; } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/BoatActionEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/BoatActionEncoder.java index ba5ce901..8083487f 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/BoatActionEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/BoatActionEncoder.java @@ -30,7 +30,7 @@ public class BoatActionEncoder implements MessageEncoder { //Message is 1 byte. ByteBuffer boatActionMessage = ByteBuffer.allocate(1); - boatActionMessage.put(intToBytes(boatAction.getBoatAction(), 1)); + boatActionMessage.put(intToBytes(boatAction.getBoatAction().getValue(), 1)); byte [] result = boatActionMessage.array(); diff --git a/racevisionGame/src/main/java/network/MessageEncoders/CourseWindEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/CourseWindEncoder.java new file mode 100644 index 00000000..b6e407c0 --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageEncoders/CourseWindEncoder.java @@ -0,0 +1,73 @@ +package network.MessageEncoders; + + +import network.Messages.CourseWind; +import shared.model.Bearing; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +import static network.Utils.AC35UnitConverter.*; +import static network.Utils.ByteConverter.*; +import static network.Utils.ByteConverter.bytesToInt; + +/** + * This encoder can encode a {@link CourseWind} message. + */ +public class CourseWindEncoder { + + + /** + * Constructor. + */ + public CourseWindEncoder() { + } + + + /** + * Encodes a given CourseWind message. + * @param message The message to encode. + * @return The encoded message. + */ + public byte[] encode(CourseWind message) { + + CourseWind courseWind = message; + + + //CourseWind is 20 bytes. + ByteBuffer courseWindBuffer = ByteBuffer.allocate(20); + + + byte[] windId = intToBytes(courseWind.getID(), 1); + + byte[] timeBytes = longToBytes(courseWind.getTime(), 6); + + byte[] raceIDBytes = intToBytes(courseWind.getRaceID(), 4); + + int windDirectionInt = packHeading(courseWind.getWindDirection().degrees()); + byte[] windDirectionBytes = intToBytes(windDirectionInt, 2); + + int windSpeedInt = packKnotsToMMperSec(courseWind.getWindSpeedKnots()); + byte[] windSpeedBytes = intToBytes(windSpeedInt, 2); + + int bestUpwindAngleInt = packHeading(courseWind.getBestUpwindAngle().degrees()); + byte[] bestUpwindAngleBytes = intToBytes(bestUpwindAngleInt, 2); + + int bestDownwindAngleInt = packHeading(courseWind.getBestDownwindAngle().degrees()); + byte[] bestDownwindAngleBytes = intToBytes(bestDownwindAngleInt, 2); + + byte[] flags = intToBytes(courseWind.getFlags(), 1); + + courseWindBuffer.put(windId); + courseWindBuffer.put(timeBytes); + courseWindBuffer.put(raceIDBytes); + courseWindBuffer.put(windDirectionBytes); + courseWindBuffer.put(windSpeedBytes); + courseWindBuffer.put(bestUpwindAngleBytes); + courseWindBuffer.put(bestDownwindAngleBytes); + courseWindBuffer.put(flags); + + return courseWindBuffer.array(); + + } +} diff --git a/racevisionGame/src/main/java/network/MessageEncoders/CourseWindsEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/CourseWindsEncoder.java new file mode 100644 index 00000000..193144c3 --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageEncoders/CourseWindsEncoder.java @@ -0,0 +1,57 @@ +package network.MessageEncoders; + + +import network.Messages.AC35Data; +import network.Messages.BoatAction; +import network.Messages.CourseWind; +import network.Messages.CourseWinds; + +import java.nio.ByteBuffer; + +import static network.Utils.ByteConverter.intToBytes; + +/** + * This encoder can encode a {@link CourseWinds} message. + */ +public class CourseWindsEncoder implements MessageEncoder { + + + /** + * Constructor. + */ + public CourseWindsEncoder() { + } + + + @Override + public byte[] encode(AC35Data message) { + + //Downcast. + CourseWinds courseWinds = (CourseWinds) message; + + + byte messageVersionNumber = CourseWinds.currentMessageVersionNumber; + + byte byteWindID = courseWinds.getSelectedWindID(); + + byte[] loopcount = intToBytes(courseWinds.getCourseWinds().size(), 1); + + ByteBuffer result = ByteBuffer.allocate(3 + 20 * courseWinds.getCourseWinds().size()); + + result.put(messageVersionNumber); + result.put(byteWindID); + result.put(loopcount); + + //Encode each CourseWind. + for (CourseWind wind: courseWinds.getCourseWinds()){ + + CourseWindEncoder courseWindEncoder = new CourseWindEncoder(); + byte[] encodedCourseWind = courseWindEncoder.encode(wind); + + result.put(encodedCourseWind); + } + return result.array(); + + + } +} diff --git a/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java b/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java index c026efd7..6ac7ec5b 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java @@ -49,7 +49,7 @@ public class EncoderFactory { //case MARKROUNDING: return new MarkRoundingEncoder();//TODO - //case COURSEWIND: return new CourseWindEncoder();//TODO + case COURSEWIND: return new CourseWindsEncoder(); //case AVGWIND: return new AverageWindEncoder();//TODO diff --git a/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java index ebd67819..a933e179 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java @@ -143,26 +143,7 @@ public class RaceVisionByteEncoder { return result.array(); } - public static byte[] courseWind(byte windID, ArrayList courseWinds){ - int messageVersionNumber = 0b1; - byte byteWindID = windID; - byte[] loopcount = intToBytes(courseWinds.size(), 1); - ByteBuffer result = ByteBuffer.allocate(3 + 20 * courseWinds.size()); - result.put(intToBytes(messageVersionNumber, 1)); - result.put(byteWindID); - result.put(loopcount); - for (CourseWind wind: courseWinds){ - result.put(intToBytes(wind.getID(), 1)); - result.put(longToBytes(wind.getTime(), 6)); - result.put(intToBytes(wind.getRaceID(), 4)); - result.put(intToBytes(wind.getWindDirection(), 2)); - result.put(intToBytes(wind.getWindSpeed(), 2)); - result.put(intToBytes(wind.getBestUpwindAngle(), 2)); - result.put(intToBytes(wind.getBestDownwindAngle(), 2)); - result.put(intToBytes(wind.getFlags(), 1)); - } - return result.array(); - } + public static byte[] averageWind(int time, int rawPeriod, int rawSampleSpeed, int period2, int speed2, int period3, int speed3, int period4, int speed4){ int messageVersionNumber = 0b1; diff --git a/racevisionGame/src/main/java/network/Messages/BoatAction.java b/racevisionGame/src/main/java/network/Messages/BoatAction.java index d20943a5..fcc96aa8 100644 --- a/racevisionGame/src/main/java/network/Messages/BoatAction.java +++ b/racevisionGame/src/main/java/network/Messages/BoatAction.java @@ -4,19 +4,30 @@ import network.Messages.Enums.BoatActionEnum; import network.Messages.Enums.MessageType; /** - * Created by David on 10/07/2017. + * Represents a BoatAction message. */ public class BoatAction extends AC35Data { - private byte boatAction; + /** + * The action for this message. + */ + private BoatActionEnum boatAction; + /** + * Constructs a BoatActon message with a given action. + * @param boatAction Action to use. + */ public BoatAction(BoatActionEnum boatAction){ super(MessageType.BOATACTION); - this.boatAction = boatAction.getValue(); + this.boatAction = boatAction; } - public byte getBoatAction() { + /** + * Returns the action for this message. + * @return The action for this message. + */ + public BoatActionEnum getBoatAction() { return boatAction; } -} \ No newline at end of file +} diff --git a/racevisionGame/src/main/java/network/Messages/CourseWind.java b/racevisionGame/src/main/java/network/Messages/CourseWind.java index 727d5fcc..60575edb 100644 --- a/racevisionGame/src/main/java/network/Messages/CourseWind.java +++ b/racevisionGame/src/main/java/network/Messages/CourseWind.java @@ -2,57 +2,132 @@ package network.Messages; import network.Messages.Enums.MessageType; +import shared.model.Bearing; /** - * Created by fwy13 on 21/04/17. + * Contains a single CourseWind record. + * A CourseWinds message contains one or more CourseWind messages. */ public class CourseWind extends AC35Data { - private int ID, raceID, windDirection, windSpeed, bestUpwindAngle, bestDownwindAngle, flags; + /** + * The ID for this wind source. + */ + private int ID; + + /** + * The time the wind was captured at. Milliseconds since unix epoch. + */ private long time; - public CourseWind(int ID, long time, int raceID, int windDirection, int windSpeed, int bestUpwindAngle, int bestDownwindAngle, - int flags){ + /** + * The ID of the race this applies to. + * 0 means it isn't race specific. + */ + private int raceID; + + /** + * Direction of the wind. + */ + private Bearing windDirection; + + /** + * The speed of the wind, in knots. + */ + private double windSpeedKnots; + + /** + * Optimum upwind sailing angle. + */ + private Bearing bestUpwindAngle; + + /** + * Optimum downwind sailing angle. + */ + private Bearing bestDownwindAngle; + + /** + * Various flags which determine which values are valid. + */ + private short flags; + + + + public CourseWind(int ID, long time, int raceID, Bearing windDirection, double windSpeedKnots, Bearing bestUpwindAngle, Bearing bestDownwindAngle, short flags) { super(MessageType.COURSEWIND); this.ID = ID; this.time = time; this.raceID = raceID; this.windDirection = windDirection; - this.windSpeed = windSpeed; + this.windSpeedKnots = windSpeedKnots; this.bestUpwindAngle = bestUpwindAngle; this.bestDownwindAngle = bestDownwindAngle; this.flags = flags; } + + /** + * Returns the ID of the wind source. + * @return ID of the wind source. + */ public int getID() { return ID; } + /** + * Returns the time that this was captured at. Milliseconds since unix epoch. + * @return Time this wind was captured at. + */ + public long getTime() { + return time; + } + + /** + * Returns the ID of the race this wind source belongs to. 0 means any race. + * @return ID of the race this belongs to. + */ public int getRaceID() { return raceID; } - public int getWindDirection() { + /** + * Returns the direction of the wind. + * @return The direction of the wind. + */ + public Bearing getWindDirection() { return windDirection; } - public int getWindSpeed() { - return windSpeed; + /** + * Returns the wind speed, in knots. + * @return Wind speed, in knots. + */ + public double getWindSpeedKnots() { + return windSpeedKnots; } - public int getBestUpwindAngle() { + /** + * Returns the best upwind sailing angle. + * @return Best upwind sailing angle. + */ + public Bearing getBestUpwindAngle() { return bestUpwindAngle; } - public int getBestDownwindAngle() { + /** + * Returns the best downwind sailing angle. + * @return The best downwind sailing angle. + */ + public Bearing getBestDownwindAngle() { return bestDownwindAngle; } + /** + * Returns various flags which determine which values are valid. + * @return Flag which determines which values are valid. + */ public int getFlags() { return flags; } - public long getTime() { - return time; - } } diff --git a/racevisionGame/src/main/java/network/Messages/CourseWinds.java b/racevisionGame/src/main/java/network/Messages/CourseWinds.java index fc575867..d62f3135 100644 --- a/racevisionGame/src/main/java/network/Messages/CourseWinds.java +++ b/racevisionGame/src/main/java/network/Messages/CourseWinds.java @@ -6,19 +6,67 @@ import network.Messages.Enums.MessageType; import java.util.List; /** - * Created by fwy13 on 25/04/17. + * Represents the information in a CourseWind message (AC streaming spec: 4.11). */ public class CourseWinds extends AC35Data { - private int msgVerNum; - private int selectedWindID; + /** + * The current version number for this message type. + */ + public static final byte currentMessageVersionNumber = 1; + + + /** + * The version number of this message. + */ + private byte messageVersionNumber; + + /** + * The ID of the wind source currently selected. + */ + private byte selectedWindID; + + /** + * A list of wind sources. + */ private List courseWinds; - public CourseWinds(int msgVerNum, int selectedWindID, List courseWinds){ + + /** + * Constructs a CourseWinds with given parameters. + * @param messageVersionNumber The version number of the message. + * @param selectedWindID The selected wind ID. + * @param courseWinds A list of wind sources. + */ + public CourseWinds(byte messageVersionNumber, byte selectedWindID, List courseWinds) { super(MessageType.COURSEWIND); - this.msgVerNum = msgVerNum; + this.messageVersionNumber = messageVersionNumber; this.selectedWindID = selectedWindID; this.courseWinds = courseWinds; } + + /** + * Returns the version number of this message. + * @return Version number of this message. + */ + public byte getMessageVersionNumber() { + return messageVersionNumber; + } + + /** + * Returns the ID of the selected wind source. + * @return ID of the selected wind source. + */ + public byte getSelectedWindID() { + return selectedWindID; + } + + /** + * Returns the list of wind sources. + * @return List of wind sources. + */ + public List getCourseWinds() { + return courseWinds; + } } diff --git a/racevisionGame/src/main/java/visualiser/gameController/ControllerServer.java b/racevisionGame/src/main/java/visualiser/gameController/ControllerServer.java index fb6a257b..df54d16d 100644 --- a/racevisionGame/src/main/java/visualiser/gameController/ControllerServer.java +++ b/racevisionGame/src/main/java/visualiser/gameController/ControllerServer.java @@ -2,6 +2,7 @@ package visualiser.gameController; import network.BinaryMessageDecoder; import network.MessageDecoders.BoatActionDecoder; +import network.Messages.BoatAction; import network.Messages.Enums.BoatActionEnum; import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.KeyFactory; @@ -47,9 +48,10 @@ public class ControllerServer implements Runnable { if (inputStream.available() > 0) { inputStream.read(message); BinaryMessageDecoder encodedMessage = new BinaryMessageDecoder(message); - BoatActionDecoder boatActionDecoder = new BoatActionDecoder(encodedMessage.getMessageBody()); - BoatActionEnum decodedMessage = boatActionDecoder.getBoatAction(); - System.out.println("Received key: " + decodedMessage); + BoatActionDecoder boatActionDecoder = new BoatActionDecoder(); + boatActionDecoder.decode(encodedMessage.getMessageBody()); + BoatAction boatAction = boatActionDecoder.getMessage(); + System.out.println("Received key: " + boatAction.getBoatAction()); } } catch (IOException e) { e.printStackTrace(); diff --git a/racevisionGame/src/test/java/network/MessageDecoders/BoatActionDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/BoatActionDecoderTest.java index d7e13b97..80dacbe6 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/BoatActionDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/BoatActionDecoderTest.java @@ -29,10 +29,10 @@ public class BoatActionDecoderTest { byte [] testEncodedMessage = RaceVisionByteEncoder.encode(message); //Decode. - BoatActionDecoder testDecoder = new BoatActionDecoder(testEncodedMessage); - BoatActionEnum decodedBoatAction = testDecoder.getBoatAction(); + BoatActionDecoder testDecoder = new BoatActionDecoder(); + testDecoder.decode(testEncodedMessage); - BoatAction decodedMessage = new BoatAction(decodedBoatAction); + BoatAction decodedMessage = testDecoder.getMessage(); return decodedMessage; } diff --git a/racevisionGame/src/test/java/network/MessageDecoders/BoatLocationDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/BoatLocationDecoderTest.java index dcc69abe..7fcdeb4a 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/BoatLocationDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/BoatLocationDecoderTest.java @@ -53,7 +53,8 @@ public class BoatLocationDecoderTest { byte [] testEncodedMessage = RaceVisionByteEncoder.encode(testMessage); //Decode. - BoatLocationDecoder testDecoder = new BoatLocationDecoder(testEncodedMessage); + BoatLocationDecoder testDecoder = new BoatLocationDecoder(); + testDecoder.decode(testEncodedMessage); BoatLocation decodedTest = testDecoder.getMessage(); //Check if valid. diff --git a/racevisionGame/src/test/java/network/MessageDecoders/BoatStatusDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/BoatStatusDecoderTest.java index 635e581c..088a85cb 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/BoatStatusDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/BoatStatusDecoderTest.java @@ -59,12 +59,10 @@ public class BoatStatusDecoderTest { private static BoatStatus encodeDecodeBoatStatus(BoatStatus boatStatus) { BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder(); - byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus); - BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder(boatStatusEncoded); - - BoatStatus boatStatusDecoded = boatStatusDecoder.getMessage(); + BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder(); + BoatStatus boatStatusDecoded = boatStatusDecoder.decode(boatStatusEncoded); return boatStatusDecoded; } diff --git a/racevisionGame/src/test/java/network/MessageDecoders/CourseWindDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/CourseWindDecoderTest.java index 53793b81..0a8753db 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/CourseWindDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/CourseWindDecoderTest.java @@ -1,57 +1,77 @@ package network.MessageDecoders; -import network.MessageEncoders.RaceVisionByteEncoder; +import network.MessageEncoders.CourseWindEncoder; +import network.Messages.BoatStatus; import network.Messages.CourseWind; +import network.Messages.Enums.BoatStatusEnum; import org.junit.Assert; import org.junit.Test; - -import java.util.ArrayList; - +import shared.model.Bearing; /** - * Created by hba56 on 23/04/17. + * Test for the CourseWind encoder and decoder */ public class CourseWindDecoderTest { + + + /** + * Creates a CourseWind message, encodes it, decodes it, and checks that the result matches the starting message. + * @throws Exception if test fails. + */ @Test - public void getByteArrayTest(){ + public void courseWindEncodeDecodeTest() throws Exception { + long time = System.currentTimeMillis(); - CourseWind testCourseWind1 = new CourseWind(1, time, 2, - 3, 4, 5, - 7, 6); + CourseWind courseWind = new CourseWind( + 1, + time, + 2, + Bearing.fromDegrees(45), + 4, + Bearing.fromDegrees(70), + Bearing.fromDegrees(160), + (byte) 0x13 ); - long time2 = System.currentTimeMillis(); - CourseWind testCourseWind2 = new CourseWind(2, time2, 2, - 3, 4, 5, - 7, 6); - ArrayList testCourseWinds = new ArrayList(); - testCourseWinds.add(testCourseWind1); - testCourseWinds.add(testCourseWind2); + CourseWind courseWindDecoded = encodeDecodeCourseWind(courseWind); + compareCourseWindMessages(courseWind, courseWindDecoded); - byte[] testEncodedCourseWind = RaceVisionByteEncoder.courseWind((byte) 1, testCourseWinds); + } - CourseWindDecoder testDecoder = new CourseWindDecoder(testEncodedCourseWind); + /** + * Encodes and decodes a CourseWind, and returns it. + * @param courseWind The CourseWind to encode and decode. + * @return The decoded CourseWind. + */ + private static CourseWind encodeDecodeCourseWind(CourseWind courseWind) { - ArrayList testDecodedCourseWinds = testDecoder.getLoopMessages(); + CourseWindEncoder courseWindEncoder = new CourseWindEncoder(); + byte[] courseWindEncoded = courseWindEncoder.encode(courseWind); - Assert.assertEquals(testCourseWinds.get(0).getID(), testDecodedCourseWinds.get(0).getID()); - Assert.assertEquals(testCourseWinds.get(0).getTime(), testDecodedCourseWinds.get(0).getTime()); - Assert.assertEquals(testCourseWinds.get(0).getRaceID(), testDecodedCourseWinds.get(0).getRaceID()); - Assert.assertEquals(testCourseWinds.get(0).getWindDirection(), testDecodedCourseWinds.get(0).getWindDirection()); - Assert.assertEquals(testCourseWinds.get(0).getWindSpeed(), testDecodedCourseWinds.get(0).getWindSpeed()); - Assert.assertEquals(testCourseWinds.get(0).getBestUpwindAngle(), testDecodedCourseWinds.get(0).getBestUpwindAngle()); - Assert.assertEquals(testCourseWinds.get(0).getBestDownwindAngle(), testDecodedCourseWinds.get(0).getBestDownwindAngle()); - Assert.assertEquals(testCourseWinds.get(0).getFlags(), testDecodedCourseWinds.get(0).getFlags()); + CourseWindDecoder courseWindDecoder = new CourseWindDecoder(); + CourseWind courseWindDecoded = courseWindDecoder.decode(courseWindEncoded); - Assert.assertEquals(testCourseWinds.get(1).getID(), testDecodedCourseWinds.get(1).getID()); - Assert.assertEquals(testCourseWinds.get(1).getTime(), testDecodedCourseWinds.get(1).getTime()); - Assert.assertEquals(testCourseWinds.get(1).getRaceID(), testDecodedCourseWinds.get(1).getRaceID()); - Assert.assertEquals(testCourseWinds.get(1).getWindDirection(), testDecodedCourseWinds.get(1).getWindDirection()); - Assert.assertEquals(testCourseWinds.get(1).getWindSpeed(), testDecodedCourseWinds.get(1).getWindSpeed()); - Assert.assertEquals(testCourseWinds.get(1).getBestUpwindAngle(), testDecodedCourseWinds.get(1).getBestUpwindAngle()); - Assert.assertEquals(testCourseWinds.get(1).getBestDownwindAngle(), testDecodedCourseWinds.get(1).getBestDownwindAngle()); - Assert.assertEquals(testCourseWinds.get(1).getFlags(), testDecodedCourseWinds.get(1).getFlags()); + return courseWindDecoded; + } + + + /** + * Compares two CourseWind messages to check that they are equal. + * @param original The original CourseWind message. + * @param decoded The decoded CourseWind message. + */ + public static void compareCourseWindMessages(CourseWind original, CourseWind decoded) { + + Assert.assertEquals(original.getID(), decoded.getID()); + Assert.assertEquals(original.getTime(), decoded.getTime()); + Assert.assertEquals(original.getRaceID(), decoded.getRaceID()); + Assert.assertEquals(original.getWindDirection().degrees(), decoded.getWindDirection().degrees(), 0.01); + Assert.assertEquals(original.getWindSpeedKnots(), decoded.getWindSpeedKnots(), 0.01); + Assert.assertEquals(original.getBestUpwindAngle().degrees(), decoded.getBestUpwindAngle().degrees(), 0.01); + Assert.assertEquals(original.getBestDownwindAngle().degrees(), decoded.getBestDownwindAngle().degrees(), 0.01); + Assert.assertEquals(original.getFlags(), decoded.getFlags()); } + } diff --git a/racevisionGame/src/test/java/network/MessageDecoders/CourseWindsDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/CourseWindsDecoderTest.java new file mode 100644 index 00000000..45c87f55 --- /dev/null +++ b/racevisionGame/src/test/java/network/MessageDecoders/CourseWindsDecoderTest.java @@ -0,0 +1,96 @@ +package network.MessageDecoders; + +import network.MessageEncoders.RaceVisionByteEncoder; +import network.Messages.CourseWind; +import network.Messages.CourseWinds; +import org.junit.Test; +import shared.model.Bearing; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + + +import static org.junit.Assert.*; + + +/** + * Tests for CourseWinds encoder and decoder. + */ +public class CourseWindsDecoderTest { + + /** + * Tests if a CourseWinds message can be encoded and decoded correctly. + * @throws Exception Thrown if an error occurs. + */ + @Test + public void courseWindsEncodeDecodeTest() throws Exception { + + long time1 = System.currentTimeMillis(); + CourseWind testCourseWind1 = new CourseWind( + 1, + time1, + 2, + Bearing.fromDegrees(45), + 4, + Bearing.fromDegrees(70), + Bearing.fromDegrees(160), + (byte) 0xCE ); + + long time2 = System.currentTimeMillis(); + CourseWind testCourseWind2 = new CourseWind( + 2, + time2, + 2, + Bearing.fromDegrees(55), + 4, + Bearing.fromDegrees(80), + Bearing.fromDegrees(180), + (byte) 0x0D ); + + List testCourseWinds = new ArrayList<>(); + testCourseWinds.add(testCourseWind1); + testCourseWinds.add(testCourseWind2); + + CourseWinds courseWinds = new CourseWinds(CourseWinds.currentMessageVersionNumber, (byte) 2, testCourseWinds); + + + byte[] testEncodedCourseWind = RaceVisionByteEncoder.encode(courseWinds); + + CourseWindsDecoder courseWindsDecoder = new CourseWindsDecoder(); + courseWindsDecoder.decode(testEncodedCourseWind); + CourseWinds courseWindsDecoded = courseWindsDecoder.getMessage(); + + compareCourseWindsMessages(courseWinds, courseWindsDecoded); + + + } + + + /** + * Compares two course winds messages to ensure they are the same. + * @param original The original message. + * @param decoded The decoded message. + */ + public static void compareCourseWindsMessages(CourseWinds original, CourseWinds decoded) { + + //Compare header. + assertEquals(original.getMessageVersionNumber(), decoded.getMessageVersionNumber()); + assertEquals(original.getSelectedWindID(), decoded.getSelectedWindID()); + assertEquals(original.getCourseWinds().size(), decoded.getCourseWinds().size()); + + //Compare each CourseWind. + List originalWinds = original.getCourseWinds(); + List decodedWinds = decoded.getCourseWinds(); + + Iterator originalIterator = originalWinds.iterator(); + Iterator decodedIterator = decodedWinds.iterator(); + + while (originalIterator.hasNext() && decodedIterator.hasNext()) { + + CourseWindDecoderTest.compareCourseWindMessages(originalIterator.next(), decodedIterator.next()); + + } + + } +} diff --git a/racevisionGame/src/test/java/network/MessageDecoders/HeartBeatDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/HeartBeatDecoderTest.java index 778a667a..ea1de885 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/HeartBeatDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/HeartBeatDecoderTest.java @@ -28,7 +28,8 @@ public class HeartBeatDecoderTest { byte [] testEncodedMessage = RaceVisionByteEncoder.encode(message); //Decode. - HeartBeatDecoder testDecoder = new HeartBeatDecoder(testEncodedMessage); + HeartBeatDecoder testDecoder = new HeartBeatDecoder(); + testDecoder.decode(testEncodedMessage); HeartBeat decodedMessage = testDecoder.getMessage(); return decodedMessage; diff --git a/racevisionGame/src/test/java/network/MessageDecoders/JoinAcceptanceDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/JoinAcceptanceDecoderTest.java index cd31ad67..1e3a5c3d 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/JoinAcceptanceDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/JoinAcceptanceDecoderTest.java @@ -27,7 +27,8 @@ public class JoinAcceptanceDecoderTest { byte [] testEncodedMessage = RaceVisionByteEncoder.encode(message); //Decode. - JoinAcceptanceDecoder testDecoder = new JoinAcceptanceDecoder(testEncodedMessage); + JoinAcceptanceDecoder testDecoder = new JoinAcceptanceDecoder(); + testDecoder.decode(testEncodedMessage); JoinAcceptance decodedMessage = testDecoder.getMessage(); return decodedMessage; diff --git a/racevisionGame/src/test/java/network/MessageDecoders/RaceStatusDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/RaceStatusDecoderTest.java index 4f1e2721..d9a47b81 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/RaceStatusDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/RaceStatusDecoderTest.java @@ -89,7 +89,8 @@ public class RaceStatusDecoderTest { byte[] encodedRaceStatus = RaceVisionByteEncoder.encode(raceStatusOriginal); - RaceStatusDecoder decoderTest = new RaceStatusDecoder(encodedRaceStatus); + RaceStatusDecoder decoderTest = new RaceStatusDecoder(); + decoderTest.decode(encodedRaceStatus); RaceStatus decodedMessage = decoderTest.getMessage(); diff --git a/racevisionGame/src/test/java/network/MessageDecoders/RequestToJoinDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/RequestToJoinDecoderTest.java index bde4ae75..fe70a709 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/RequestToJoinDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/RequestToJoinDecoderTest.java @@ -28,7 +28,8 @@ public class RequestToJoinDecoderTest { byte [] testEncodedMessage = RaceVisionByteEncoder.encode(message); //Decode. - RequestToJoinDecoder testDecoder = new RequestToJoinDecoder(testEncodedMessage); + RequestToJoinDecoder testDecoder = new RequestToJoinDecoder(); + testDecoder.decode(testEncodedMessage); RequestToJoin decodedMessage = testDecoder.getMessage(); return decodedMessage; diff --git a/racevisionGame/src/test/java/network/MessageDecoders/XMLMessageDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/XMLMessageDecoderTest.java index 32d1a61e..f0c0ba0b 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/XMLMessageDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/XMLMessageDecoderTest.java @@ -45,7 +45,8 @@ public class XMLMessageDecoderTest { - XMLMessageDecoder decoderXML = new XMLMessageDecoder(encodedXML); + XMLMessageDecoder decoderXML = new XMLMessageDecoder(); + decoderXML.decode(encodedXML); XMLMessage decodedMessage = decoderXML.getMessage();