Refactored RaceStatusDecoder to be more consistent with other decoders - it now has a getMessage() function. Added BoatStatus encoder and decoder - the RaceStatus encoder and decoder uses this for BoatStatuses. The BoatStatus encoder doesn't implement the MessageEncoder interface as BoatStatus is not a proper message type (doesn't inherit from AC35Data). Added remaining cases to EncoderFactory, but commented them out. BoatStatus now uses BoatStatusEnum instead of a byte. Added some comments to RaceStatus, and it uses enums instead of bytes. MockOutput logs a warning if a RaceStatus cannot be encoded. Added a BoatStatusDecoderTest. Updated RaceStatusDecoder to use new encoders/decoders. issue #35 #36 #story[1095]main
parent
e464ee298e
commit
b1922fc3fc
@ -0,0 +1,90 @@
|
|||||||
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Messages.BoatStatus;
|
||||||
|
import network.Messages.Enums.BoatStatusEnum;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static network.Utils.ByteConverter.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes {@link BoatStatus} messages.
|
||||||
|
*/
|
||||||
|
public class BoatStatusDecoder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encoded message.
|
||||||
|
*/
|
||||||
|
private byte[] encodedMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decoded message.
|
||||||
|
*/
|
||||||
|
private BoatStatus message;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a decoder to decode a given message.
|
||||||
|
* @param encodedMessage The message to decode.
|
||||||
|
*/
|
||||||
|
public BoatStatusDecoder(byte[] encodedMessage) {
|
||||||
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
|
decode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the contained message.
|
||||||
|
*/
|
||||||
|
private void decode() {
|
||||||
|
|
||||||
|
|
||||||
|
byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 0, 4);
|
||||||
|
int sourceID = bytesToInt(sourceIDBytes);
|
||||||
|
|
||||||
|
byte[] boatStatusBytes = Arrays.copyOfRange(encodedMessage, 4, 5);
|
||||||
|
BoatStatusEnum boatStatus = BoatStatusEnum.fromByte(boatStatusBytes[0]);
|
||||||
|
|
||||||
|
byte[] legNumberBytes = Arrays.copyOfRange(encodedMessage, 5, 6);
|
||||||
|
byte legNumber = legNumberBytes[0];
|
||||||
|
|
||||||
|
byte[] numPenaltiesAwardedBytes = Arrays.copyOfRange(encodedMessage, 6, 7);
|
||||||
|
byte numPenaltiesAwarded = numPenaltiesAwardedBytes[0];
|
||||||
|
|
||||||
|
byte[] numPenaltiesServedBytes = Arrays.copyOfRange(encodedMessage, 7, 8);
|
||||||
|
byte numPenaltiesServed = numPenaltiesServedBytes[0];
|
||||||
|
|
||||||
|
byte[] estTimeAtNextMarkBytes = Arrays.copyOfRange(encodedMessage, 8, 14);
|
||||||
|
long estTimeAtNextMark = bytesToLong(estTimeAtNextMarkBytes);
|
||||||
|
|
||||||
|
byte[] estTimeAtFinishBytes = Arrays.copyOfRange(encodedMessage, 14, 20);
|
||||||
|
long estTimeAtFinish = bytesToLong(estTimeAtFinishBytes);
|
||||||
|
|
||||||
|
message = new BoatStatus(
|
||||||
|
sourceID,
|
||||||
|
boatStatus,
|
||||||
|
legNumber,
|
||||||
|
numPenaltiesAwarded,
|
||||||
|
numPenaltiesServed,
|
||||||
|
estTimeAtNextMark,
|
||||||
|
estTimeAtFinish );
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the decoded message.
|
||||||
|
* @return The decoded message.
|
||||||
|
*/
|
||||||
|
public BoatStatus getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Messages.BoatStatus;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import static network.Utils.ByteConverter.intToBytes;
|
||||||
|
import static network.Utils.ByteConverter.longToBytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This encoder can encode a {@link BoatStatus} message.
|
||||||
|
*/
|
||||||
|
public class BoatStatusEncoder {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
public BoatStatusEncoder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a given BoatStatus message.
|
||||||
|
* @param message The message to encode.
|
||||||
|
* @return The encoded message.
|
||||||
|
*/
|
||||||
|
public byte[] encode(BoatStatus message) {
|
||||||
|
|
||||||
|
//Downcast.
|
||||||
|
BoatStatus boatStatus = (BoatStatus) message;
|
||||||
|
|
||||||
|
//BoatStatus is 20 bytes.
|
||||||
|
ByteBuffer boatStatusBuffer = ByteBuffer.allocate(20);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Messages.AC35Data;
|
||||||
|
import network.Messages.BoatStatus;
|
||||||
|
import network.Messages.RaceStatus;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static network.Utils.ByteConverter.intToBytes;
|
||||||
|
import static network.Utils.ByteConverter.longToBytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This encoder can encode a {@link RaceStatus} message.
|
||||||
|
*/
|
||||||
|
public class RaceStatusEncoder implements MessageEncoder {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
public RaceStatusEncoder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encode(AC35Data message) {
|
||||||
|
|
||||||
|
//Downcast.
|
||||||
|
RaceStatus raceStatus = (RaceStatus) message;
|
||||||
|
|
||||||
|
|
||||||
|
List<BoatStatus> boatStatuses = raceStatus.getBoatStatuses();
|
||||||
|
|
||||||
|
//24 byte header, plus 20 bytes per boat status.
|
||||||
|
ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20 * boatStatuses.size());
|
||||||
|
|
||||||
|
//Version Number 1 bytes. this changes with the pdf. (2)
|
||||||
|
byte versionNum = 0b10;
|
||||||
|
|
||||||
|
//time (6 bytes)
|
||||||
|
byte[] timeBytes = longToBytes(raceStatus.getCurrentTime(), 6);
|
||||||
|
|
||||||
|
//race identifier in case multiple races are going at once.
|
||||||
|
byte[] raceID = intToBytes(raceStatus.getRaceID());
|
||||||
|
|
||||||
|
//race status 0 - 10
|
||||||
|
byte[] raceStatusByte = intToBytes(raceStatus.getRaceStatus().getValue(), 1);
|
||||||
|
|
||||||
|
//number of milliseconds from Jan 1, 1970 for when the data is valid
|
||||||
|
byte[] expectedStart = longToBytes(raceStatus.getExpectedStartTime(), 6);
|
||||||
|
|
||||||
|
//North = 0x0000 East = 0x4000 South = 0x8000.
|
||||||
|
byte[] raceWind = intToBytes(raceStatus.getWindDirection(), 2);
|
||||||
|
|
||||||
|
//mm/sec
|
||||||
|
byte[] windSpeed = intToBytes(raceStatus.getWindSpeed(), 2);
|
||||||
|
|
||||||
|
|
||||||
|
byte[] numBoats = intToBytes(boatStatuses.size(), 1);
|
||||||
|
|
||||||
|
//1 match race, 2 fleet race
|
||||||
|
byte[] bytesRaceType = intToBytes(raceStatus.getRaceType().getValue(), 1);
|
||||||
|
|
||||||
|
|
||||||
|
raceStatusMessage.put(versionNum);
|
||||||
|
raceStatusMessage.put(timeBytes);
|
||||||
|
raceStatusMessage.put(raceID);
|
||||||
|
raceStatusMessage.put(raceStatusByte);
|
||||||
|
raceStatusMessage.put(expectedStart);
|
||||||
|
raceStatusMessage.put(raceWind);
|
||||||
|
raceStatusMessage.put(windSpeed);
|
||||||
|
raceStatusMessage.put(numBoats);
|
||||||
|
raceStatusMessage.put(bytesRaceType);
|
||||||
|
|
||||||
|
//Encode each BoatStatus.
|
||||||
|
for (BoatStatus boatStatus : boatStatuses) {
|
||||||
|
|
||||||
|
BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder();
|
||||||
|
|
||||||
|
byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus);
|
||||||
|
|
||||||
|
raceStatusMessage.put(boatStatusEncoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
return raceStatusMessage.array();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
import network.MessageEncoders.BoatStatusEncoder;
|
||||||
|
import network.MessageEncoders.RaceVisionByteEncoder;
|
||||||
|
import network.Messages.BoatStatus;
|
||||||
|
import network.Messages.Enums.BoatStatusEnum;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for the BoatStatus encoder and decoder
|
||||||
|
*/
|
||||||
|
public class BoatStatusDecoderTest {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BoatStatus message, encodes it, decodes it, and checks that the result matches the starting message.
|
||||||
|
* @throws Exception if test fails.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void boatStatusEncodeDecodeTest() throws Exception {
|
||||||
|
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
|
||||||
|
//Create data to serialize.
|
||||||
|
int boatSourceID = 5;
|
||||||
|
BoatStatusEnum boatStatusEnum = BoatStatusEnum.RACING;
|
||||||
|
byte boatLegNumber = 5;
|
||||||
|
byte boatPenaltiesAwarded = 4;
|
||||||
|
byte boatPenaltiesServed = 2;
|
||||||
|
long boatTimeAtNextMark = time + (1000 * 3);
|
||||||
|
long boatTimeAtFinish = boatTimeAtNextMark + (1000 * 15);
|
||||||
|
|
||||||
|
BoatStatus boatStatus = new BoatStatus(
|
||||||
|
boatSourceID,
|
||||||
|
boatStatusEnum,
|
||||||
|
boatLegNumber,
|
||||||
|
boatPenaltiesAwarded,
|
||||||
|
boatPenaltiesServed,
|
||||||
|
boatTimeAtNextMark,
|
||||||
|
boatTimeAtFinish );
|
||||||
|
|
||||||
|
|
||||||
|
BoatStatus boatStatusDecoded = encodeDecodeBoatStatus(boatStatus);
|
||||||
|
|
||||||
|
compareBoatStatusMessages(boatStatus, boatStatusDecoded);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes and decodes a BoatStatus, and returns it.
|
||||||
|
* @param boatStatus The BoatStatus to encode and decode.
|
||||||
|
* @return The decoded BoatStatus.
|
||||||
|
*/
|
||||||
|
private static BoatStatus encodeDecodeBoatStatus(BoatStatus boatStatus) {
|
||||||
|
|
||||||
|
BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder();
|
||||||
|
|
||||||
|
byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus);
|
||||||
|
|
||||||
|
BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder(boatStatusEncoded);
|
||||||
|
|
||||||
|
BoatStatus boatStatusDecoded = boatStatusDecoder.getMessage();
|
||||||
|
|
||||||
|
return boatStatusDecoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two BoatStatus messages to check that they are equal.
|
||||||
|
* @param original The original BoatStatus message.
|
||||||
|
* @param decoded The decoded BoatStatus message.
|
||||||
|
*/
|
||||||
|
public static void compareBoatStatusMessages(BoatStatus original, BoatStatus decoded) {
|
||||||
|
|
||||||
|
Assert.assertEquals(original.getSourceID(), decoded.getSourceID());
|
||||||
|
Assert.assertEquals(original.getBoatStatus(), decoded.getBoatStatus());
|
||||||
|
Assert.assertEquals(original.getLegNumber(), decoded.getLegNumber());
|
||||||
|
Assert.assertEquals(original.getNumPenaltiesAwarded(), decoded.getNumPenaltiesAwarded());
|
||||||
|
Assert.assertEquals(original.getNumPenaltiesServed(), decoded.getNumPenaltiesServed());
|
||||||
|
Assert.assertEquals(original.getEstTimeAtNextMark(), decoded.getEstTimeAtNextMark());
|
||||||
|
Assert.assertEquals(original.getEstTimeAtFinish(), decoded.getEstTimeAtFinish());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in new issue