Added RaceStartStatusEncoder.

Added RaceStartTypeEnum.
Refactored RaceStartStatusDecoder to implement the MessageDecoder interface.
Documented RaceStartStatus, and it actually exposes its properties now.
Updated RaceStartStatusDecoderTest.
issue #35 #36
#story[1095]
main
fjc40 8 years ago
parent e99ad00294
commit ce63f58429

@ -164,8 +164,8 @@ public class BinaryMessageDecoder {
case RACESTARTSTATUS: case RACESTARTSTATUS:
//System.out.println("Race Start Status Message"); //System.out.println("Race Start Status Message");
RaceStartStatusDecoder rssDecoder = new RaceStartStatusDecoder(messageBody); RaceStartStatusDecoder rssDecoder = new RaceStartStatusDecoder();
return new RaceStartStatus(rssDecoder.getTime(), rssDecoder.getAck(), rssDecoder.getStartTime(), rssDecoder.getRaceID(), rssDecoder. getNotification()); return rssDecoder.decode(messageBody);
case YACHTEVENTCODE: case YACHTEVENTCODE:
//System.out.println("Yacht Action Code!"); //System.out.println("Yacht Action Code!");

@ -37,7 +37,7 @@ public class DecoderFactory {
case XMLMESSAGE: return new XMLMessageDecoder(); case XMLMESSAGE: return new XMLMessageDecoder();
//case RACESTARTSTATUS: return new RaceStartStatusDecoder();//TODO case RACESTARTSTATUS: return new RaceStartStatusDecoder();
//case YACHTEVENTCODE: return new YachtEventCodeDecoder();//TODO //case YACHTEVENTCODE: return new YachtEventCodeDecoder();//TODO

@ -1,66 +1,81 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.Messages.AC35Data;
import network.Messages.Enums.RaceStartTypeEnum;
import network.Messages.RaceStartStatus;
import java.util.Arrays; import java.util.Arrays;
import static network.Utils.ByteConverter.*; import static network.Utils.ByteConverter.*;
/** /**
* Created by hba56 on 21/04/17. * Decodes {@link RaceStartStatus} messages.
*/ */
public class RaceStartStatusDecoder { public class RaceStartStatusDecoder implements MessageDecoder {
private byte messageVersion;
private byte[] timestamp;
private byte[] ackNumber;
private byte[] raceStartTime;
private byte[] raceIdentifier;
private byte notificationType;
private long time;
private short ack;
private long startTime;
private int raceID;
private char notification;
public RaceStartStatusDecoder(byte[] encodedRaceStartStatus) {
messageVersion = encodedRaceStartStatus[0];
timestamp = Arrays.copyOfRange(encodedRaceStartStatus, 1, 7);
ackNumber = Arrays.copyOfRange(encodedRaceStartStatus, 7, 9);
raceStartTime = Arrays.copyOfRange(encodedRaceStartStatus, 9, 15);
raceIdentifier = Arrays.copyOfRange(encodedRaceStartStatus, 15, 19);
notificationType = encodedRaceStartStatus[19];
time = bytesToLong(timestamp);
ack = bytesToShort(ackNumber);
startTime = bytesToLong(raceStartTime);
raceID = bytesToInt(raceIdentifier);
notification = bytesToChar(notificationType);
}
/**
* The encoded message.
*/
private byte[] encodedMessage;
public byte getMessageVersion() { /**
return messageVersion; * The decoded message.
} */
private RaceStartStatus message;
public long getTime() {
return time;
}
public short getAck() {
return ack;
}
public long getStartTime() { /**
return startTime; * Constructs a decoder to decode a given message.
*/
public RaceStartStatusDecoder() {
} }
public int getRaceID() {
return raceID; @Override
public AC35Data decode(byte[] encodedMessage) {
this.encodedMessage = encodedMessage;
byte messageVersion = encodedMessage[0];
byte[] timestamp = Arrays.copyOfRange(encodedMessage, 1, 7);
long time = bytesToLong(timestamp);
byte[] ackNumber = Arrays.copyOfRange(encodedMessage, 7, 9);
short ack = bytesToShort(ackNumber);
byte[] raceStartTime = Arrays.copyOfRange(encodedMessage, 9, 15);
long startTime = bytesToLong(raceStartTime);
byte[] raceIdentifier = Arrays.copyOfRange(encodedMessage, 15, 19);
int raceID = bytesToInt(raceIdentifier);
byte notificationType = encodedMessage[19];
message = new RaceStartStatus(
messageVersion,
time,
ack,
startTime,
raceID,
RaceStartTypeEnum.fromByte(notificationType)
);
return message;
} }
public char getNotification() {
return notification; /**
* Returns the decoded message.
* @return The decoded message.
*/
public RaceStartStatus getMessage() {
return message;
} }
} }

@ -37,7 +37,7 @@ public class EncoderFactory {
case XMLMESSAGE: return new XMLMessageEncoder(); case XMLMESSAGE: return new XMLMessageEncoder();
//case RACESTARTSTATUS: return new RaceStartStatusEncoder();//TODO case RACESTARTSTATUS: return new RaceStartStatusEncoder();
//case YACHTEVENTCODE: return new YachtEventCodeEncoder();//TODO //case YACHTEVENTCODE: return new YachtEventCodeEncoder();//TODO

@ -0,0 +1,51 @@
package network.MessageEncoders;
import network.Messages.AC35Data;
import network.Messages.RaceStartStatus;
import network.Utils.ByteConverter;
import java.nio.ByteBuffer;
import static network.Utils.ByteConverter.intToBytes;
import static network.Utils.ByteConverter.longToBytes;
/**
* This encoder can encode a {@link RaceStartStatus} message.
*/
public class RaceStartStatusEncoder implements MessageEncoder {
/**
* Constructor.
*/
public RaceStartStatusEncoder() {
}
@Override
public byte[] encode(AC35Data message) {
//Downcast.
RaceStartStatus raceStartStatus = (RaceStartStatus) message;
byte messageVersion = raceStartStatus.getMessageVersionNumber();
byte[] timestamp = longToBytes(raceStartStatus.getTimestamp(), 6);
byte[] ackNumber = intToBytes(raceStartStatus.getAckNum(), 2);
byte[] raceStartTime = longToBytes(raceStartStatus.getRaceStartTime(), 6);
byte[] raceIdentifier = intToBytes(raceStartStatus.getRaceID());
byte[] notificationType = intToBytes(raceStartStatus.getNotificationType().getValue(), 1);
ByteBuffer result = ByteBuffer.allocate(20);
result.put(messageVersion);
result.put(timestamp);
result.put(ackNumber);
result.put(raceStartTime);
result.put(raceIdentifier);
result.put(notificationType);
return result.array();
}
}

@ -63,25 +63,6 @@ public class RaceVisionByteEncoder {
return result.array(); return result.array();
} }
public static byte[] raceStartStatus(long time, short ack, long startTime, int raceID, char notification){
int messageVersion = 0b1;
byte[] timestamp = longToBytes(time, 6);
byte[] ackNumber = intToBytes(ack, 2);
byte[] raceStartTime = longToBytes(startTime, 6);
int raceIdentifier = raceID;
byte[] notificationType = intToBytes(notification, 1);
ByteBuffer result = ByteBuffer.allocate(20);
result.put(intToBytes(messageVersion, 1));
result.put(timestamp);
result.put(ackNumber);
result.put(raceStartTime);
result.put(intToBytes(raceIdentifier));
result.put(notificationType);
return result.array();
}
public static byte[] yachtEventCode(long time, short acknowledgeNumber, int raceID, int destSourceID, int incidentID, public static byte[] yachtEventCode(long time, short acknowledgeNumber, int raceID, int destSourceID, int incidentID,
int eventID){ int eventID){
int messageVersion = 0b10; int messageVersion = 0b10;

@ -0,0 +1,97 @@
package network.Messages.Enums;
import java.util.HashMap;
import java.util.Map;
/**
* Enumeration that encapsulates the various types race start status notifications. See AC35 streaming spec, 4.5.
*/
public enum RaceStartTypeEnum {
/**
* The race start time is being set.
*/
SET_RACE_START(1),
/**
* The race has been postponed.
*/
RACE_POSTPONED(2),
/**
* The race has been abandoned.
*/
RACE_ABANDONED(3),
/**
* The race has been terminated.
*/
RACE_TERMINATED(4),
/**
* Used to indicate that a given byte value is invalid.
*/
NOT_A_TYPE(-1);
/**
* Primitive value of the enum.
*/
private byte value;
/**
* Ctor. Creates a RaceStartTypeEnum from a given primitive integer value, cast to a byte.
* @param value Integer, which is cast to byte, to construct from.
*/
private RaceStartTypeEnum(int value) {
this.value = (byte) value;
}
/**
* Returns the primitive value of the enum.
* @return Primitive value of the enum.
*/
public byte getValue() {
return value;
}
/**
* Stores a mapping between Byte values and RaceStartTypeEnum values.
*/
private static final Map<Byte, RaceStartTypeEnum> byteToTypeMap = new HashMap<>();
/*
Static initialization block. Initializes the byteToTypeMap.
*/
static {
for (RaceStartTypeEnum type : RaceStartTypeEnum.values()) {
RaceStartTypeEnum.byteToTypeMap.put(type.value, type);
}
}
/**
* Returns the enumeration value which corresponds to a given byte value.
* @param startTypeEnum Byte value to convert to a RaceStartTypeEnum value.
* @return The RaceStartTypeEnum value which corresponds to the given byte value.
*/
public static RaceStartTypeEnum fromByte(byte startTypeEnum) {
//Gets the corresponding MessageType from the map.
RaceStartTypeEnum type = RaceStartTypeEnum.byteToTypeMap.get(startTypeEnum);
if (type == null) {
//If the byte value wasn't found, return the NOT_A_TYPE RaceStartTypeEnum.
return RaceStartTypeEnum.NOT_A_TYPE;
} else {
//Otherwise, return the RaceStartTypeEnum.
return type;
}
}
}

@ -2,20 +2,63 @@ package network.Messages;
import network.Messages.Enums.MessageType; import network.Messages.Enums.MessageType;
import network.Messages.Enums.RaceStartTypeEnum;
/** /**
* Created by fwy13 on 25/04/17. * Represents a RaceStartStatus message from the API, section 4.5.
*/ */
public class RaceStartStatus extends AC35Data { public class RaceStartStatus extends AC35Data {
/**
* The current version number of this message type.
*/
public static final byte currentMessageVersionNumber = 1;
/**
* The version number of this message.
*/
private byte messageVersionNumber;
/**
* The time at which this message was created. Milliseconds since unix epoch.
*/
private long timestamp; private long timestamp;
/**
* Sequence number of message.
*/
private int ackNum; private int ackNum;
/**
* The time the race is expected to start at. Milliseconds since unix epoch.
*/
private long raceStartTime; private long raceStartTime;
/**
* The ID of the race this message relates to.
*/
private int raceID; private int raceID;
private int notificationType;
public RaceStartStatus(long timestamp, int ackNum, long raceStartTime, int raceID, int notificationType){ /**
* The type of notification this is.
*/
private RaceStartTypeEnum notificationType;
/**
* Constructs a RaceStartStatus message with the given parameters.
* @param messageVersionNumber Version number of the message.
* @param timestamp The timestamp at which this message was generated.
* @param ackNum The sequence number of this message.
* @param raceStartTime The expected race start time.
* @param raceID The ID of the race this message relates to.
* @param notificationType The type of notification this is.
*/
public RaceStartStatus(byte messageVersionNumber, long timestamp, int ackNum, long raceStartTime, int raceID, RaceStartTypeEnum notificationType) {
super(MessageType.RACESTARTSTATUS); super(MessageType.RACESTARTSTATUS);
this.messageVersionNumber = messageVersionNumber;
this.timestamp = timestamp; this.timestamp = timestamp;
this.ackNum = ackNum; this.ackNum = ackNum;
this.raceStartTime = raceStartTime; this.raceStartTime = raceStartTime;
@ -23,4 +66,52 @@ public class RaceStartStatus extends AC35Data {
this.notificationType = notificationType; this.notificationType = notificationType;
} }
/**
* Returns the version number of this message.
* @return Version number of this message.
*/
public byte getMessageVersionNumber() {
return messageVersionNumber;
}
/**
* Return the time at which this message was generated. Milliseconds since unix epoch.
* @return Time at which this message was generated.
*/
public long getTimestamp() {
return timestamp;
}
/**
* Returns the sequence number of this message.
* @return Sequence number of this message.
*/
public int getAckNum() {
return ackNum;
}
/**
* Returns the expected race start time. Milliseconds since unix epoch.
* @return Expected race start time.
*/
public long getRaceStartTime() {
return raceStartTime;
}
/**
* Returns the race ID this message relates to.
* @return Race ID this message relates to.
*/
public int getRaceID() {
return raceID;
}
/**
* Returns the type of start status notification this message is.
* @return The type of notification this is.
*/
public RaceStartTypeEnum getNotificationType() {
return notificationType;
}
} }

@ -1,29 +1,62 @@
package network.MessageDecoders; package network.MessageDecoders;
import network.MessageEncoders.RaceVisionByteEncoder; import network.MessageEncoders.RaceVisionByteEncoder;
import network.Messages.Enums.RaceStartTypeEnum;
import network.Messages.RaceStartStatus;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
/** /**
* Created by hba56 on 23/04/17. * Tests for the RaceStartStatus encoder and decoder.
*/ */
public class RaceStartStatusDecoderTest { public class RaceStartStatusDecoderTest {
/**
* Tests if a RaceStartStatus message can be encoded and decoded correctly.
* @throws Exception Thrown when an error occurs.
*/
@Test @Test
public void getByteArrayTest(){ public void raceStartStatusEncodeDecodeTest() throws Exception {
long time = System.currentTimeMillis();
long timestamp = System.currentTimeMillis();
long time2 = System.currentTimeMillis(); long startTime = System.currentTimeMillis() + 10 * 1000;
byte[] encodedRaceStartStatus = RaceVisionByteEncoder.raceStartStatus(time, (short)1,
time2, 2, (char)3);
RaceStartStatusDecoder testDecoder = new RaceStartStatusDecoder(encodedRaceStartStatus); RaceStartStatus raceStartStatus = new RaceStartStatus(
RaceStartStatus.currentMessageVersionNumber,
timestamp,
55,
startTime,
35,
RaceStartTypeEnum.SET_RACE_START
);
Assert.assertEquals(0b1, testDecoder.getMessageVersion()); byte[] encodedRaceStartStatus = RaceVisionByteEncoder.encode(raceStartStatus);
Assert.assertEquals(time, testDecoder.getTime());
Assert.assertEquals(1, testDecoder.getAck()); RaceStartStatusDecoder testDecoder = new RaceStartStatusDecoder();
Assert.assertEquals(time2, testDecoder.getStartTime()); testDecoder.decode(encodedRaceStartStatus);
Assert.assertEquals(2, testDecoder.getRaceID()); RaceStartStatus raceStartStatusDecoded = testDecoder.getMessage();
Assert.assertEquals((char)3, testDecoder.getNotification());
compareRaceStartStatusMessages(raceStartStatus, raceStartStatusDecoded);
} }
/**
* Compares two RaceStartStatus messages to check that they are the same.
* @param original The original message.
* @param decoded The decoded message.
*/
public static void compareRaceStartStatusMessages(RaceStartStatus original, RaceStartStatus decoded) {
Assert.assertEquals(original.getMessageVersionNumber(), decoded.getMessageVersionNumber());
Assert.assertEquals(original.getTimestamp(), decoded.getTimestamp());
Assert.assertEquals(original.getAckNum(), decoded.getAckNum());
Assert.assertEquals(original.getRaceStartTime(), decoded.getRaceStartTime());
Assert.assertEquals(original.getRaceID(), decoded.getRaceID());
Assert.assertEquals(original.getNotificationType(), decoded.getNotificationType());
}
} }

Loading…
Cancel
Save