Added Race Status messages to the mock streaming data interface

Tags: #story[29]
This commit is contained in:
Michael Rausch
2017-04-24 21:53:42 +12:00
parent edc306da22
commit 6874f288ee
7 changed files with 354 additions and 4 deletions
+42 -4
View File
@@ -1,13 +1,12 @@
package seng302.server;
import seng302.server.messages.Heartbeat;
import seng302.server.messages.Message;
import seng302.server.messages.XMLMessage;
import seng302.server.messages.XMLMessageSubType;
import seng302.server.messages.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
@@ -15,6 +14,7 @@ public class ServerThread implements Runnable{
private Thread runner;
private StreamingServerSocket server;
private final int HEARTBEAT_PERIOD = 5000;
private final int RACE_STATUS_PERIOD = 1000;
private final int PORT_NUMBER = 8085;
public ServerThread(String threadName){
@@ -45,6 +45,29 @@ public class ServerThread implements Runnable{
return null;
}
/**
* @return A sample race status message
*/
public Message getTestRaceStatusMessage(){
BoatSubMessage boat1 = new BoatSubMessage(1, BoatStatus.PRESTART, 0, 0, 0,
10000, 10000);
BoatSubMessage boat2 = new BoatSubMessage(2, BoatStatus.PRESTART, 0, 0, 0,
10000, 10000);
BoatSubMessage boat3 = new BoatSubMessage(3, BoatStatus.PRESTART, 0, 0, 0,
10000, 10000);
List<BoatSubMessage> boats = new ArrayList<BoatSubMessage>();
boats.add(boat1);
boats.add(boat2);
boats.add(boat3);
return new RaceStatusMessage(1, RaceStatus.PRESTART, 1000, WindDirection.EAST,
100, 3, RaceType.MATCH_RACE, 1, boats);
}
public void run() {
try{
server = new StreamingServerSocket(PORT_NUMBER);
@@ -87,6 +110,21 @@ public class ServerThread implements Runnable{
}
}, 0, HEARTBEAT_PERIOD);
// Timer to send the race status messages
Timer t1 = new Timer();
t1.schedule(new TimerTask() {
@Override
public void run() {
Message statusMessage = getTestRaceStatusMessage();
try {
server.send(statusMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
}, 100, RACE_STATUS_PERIOD);
} catch (IOException e) {
System.err.println(e.getMessage());
}
@@ -0,0 +1,25 @@
package seng302.server.messages;
/**
* The current status of a boat
*/
public enum BoatStatus {
UNDEFINED(0),
PRESTART(1),
RACING(2),
FINISHED(3),
DNS(4),
DNF(5),
DSQ(6),
CS(7);
private long code;
BoatStatus(long code) {
this.code = code;
}
public long getCode(){
return code;
}
}
@@ -0,0 +1,91 @@
package seng302.server.messages;
import java.nio.ByteBuffer;
/**
* The status of each boat, sent within a race status message
*/
public class BoatSubMessage {
private final int MESSAGE_SIZE = 20;
private long sourceId;
private BoatStatus boatStatus;
private long legNumber;
private long numberPenaltiesAwarded;
private long numberPenaltiesServed;
private long estimatedTimeAtNextMark;
private long estimatedTimeAtFinish;
/**
* Boat Sub message from section 4.2 of the AC35 streaming data interface spec
* @param sourceId The source ID of the boat
* @param boatStatus The boats status
* @param legNumber The leg the boat is on (0= prestart, 1=start to first mark etc)
* @param numberPenaltiesAwarded The number of penalties awarded to the boat
* @param numberPenaltiesServed The number of penalties served to the boat
* @param estimatedTimeAtFinish The estimated time (UTC) the boat will finish the race
* @param estimatedTimeAtNextMark The estimated time (UTC) the boat will arrive at the next mark
*/
public BoatSubMessage(long sourceId, BoatStatus boatStatus, long legNumber, long numberPenaltiesAwarded, long numberPenaltiesServed,
long estimatedTimeAtFinish, long estimatedTimeAtNextMark){
this.sourceId = sourceId;
this.boatStatus = boatStatus;
this.legNumber = legNumber;
this.numberPenaltiesAwarded = numberPenaltiesAwarded;
this.numberPenaltiesServed = numberPenaltiesServed;
this.estimatedTimeAtFinish = estimatedTimeAtFinish;
this.estimatedTimeAtNextMark = estimatedTimeAtNextMark;
}
/**
* @return The size of this message in bytes
*/
public int getSize(){
return MESSAGE_SIZE;
}
/**
* @return a ByteBuffer containing this boat status message
*/
public ByteBuffer getByteBuffer(){
ByteBuffer buff = ByteBuffer.allocate(getSize());
int buffPos = 0;
// Source ID, 4 bytes
buff.put(ByteBuffer.allocate(4).putInt((int) sourceId).array());
buffPos += 4;
buff.position(buffPos);
// Boat Status, 1 byte
buff.put(ByteBuffer.allocate(1).put((byte) boatStatus.getCode()).array());
buffPos += 1;
buff.position(buffPos);
// Leg number, 1 byte
buff.put(ByteBuffer.allocate(1).put((byte) legNumber).array());
buffPos += 1;
buff.position(buffPos);
// Number of penalties awarded, 1 byte
buff.put(ByteBuffer.allocate(1).put((byte) numberPenaltiesAwarded).array());
buffPos += 1;
buff.position(buffPos);
// Number of penalties served, 1 byte
buff.put(ByteBuffer.allocate(1).put((byte) numberPenaltiesServed).array());
buffPos += 1;
buff.position(buffPos);
// Estimated time at next mark, 6 bytes
buff.put(ByteBuffer.allocate(6).putInt((int) estimatedTimeAtNextMark).array());
buffPos += 6;
buff.position(buffPos);
// Estimated time at finish, 6 bytes
buff.put(ByteBuffer.allocate(6).putInt((int) estimatedTimeAtFinish).array());
buffPos += 6;
buff.position(buffPos);
return buff;
}
}
@@ -0,0 +1,26 @@
package seng302.server.messages;
/**
* The current status of the race
*/
public enum RaceStatus {
NOTACTIVE(0),
WARNING(1), // Between 3:00 and 1:00 before start
PREPARATORY(2), // Less than 1:00 before start
STARTED(3),
ABANDONED(6),
POSTPONED(7),
TERMINATED(8),
RACE_START_TIME_NOT_SET(9),
PRESTART(10); // More than 3:00 before start
private int code;
RaceStatus(int code){
this.code = code;
}
public int getCode(){
return this.code;
}
}
@@ -0,0 +1,130 @@
package seng302.server.messages;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.zip.CRC32;
public class RaceStatusMessage extends Message{
private final MessageType MESSAGE_TYPE = MessageType.RACE_STATUS;
private final int MESSAGE_VERSION = 2; //Always set to 1
private final int MESSAGE_BASE_SIZE = 24;
// fields
private long currentTime;
private long raceId;
private RaceStatus raceStatus;
private long expectedStartTime;
private WindDirection raceWindDirection;
private long windSpeed;
private long numBoatsInRace;
private RaceType raceType;
private List<BoatSubMessage> boats;
private CRC32 crc;
/**
* A message containing the current status of the race
* @param raceId The ID of the current race
* @param raceStatus The status of the race
* @param expectedStartTime The expected start time
* @param raceWindDirection The wind direction (north, east, south)
* @param windSpeed The wind speed in mm/sec
* @param numBoatsInRace The number of boats in the race
* @param raceType The race type (Match/fleet)
* @param sourceId The source of this message
* @param boats A list of boat status sub messages
*/
public RaceStatusMessage(long raceId, RaceStatus raceStatus, long expectedStartTime, WindDirection raceWindDirection,
long windSpeed, long numBoatsInRace, RaceType raceType, long sourceId, List<BoatSubMessage> boats){
currentTime = System.currentTimeMillis() / 1000L;
this.raceId = raceId;
this.raceStatus = raceStatus;
this.expectedStartTime = expectedStartTime;
this.raceWindDirection = raceWindDirection;
this.windSpeed = windSpeed;
this.numBoatsInRace = numBoatsInRace;
this.raceType = raceType;
this.boats = boats;
crc = new CRC32();
setHeader(new Header(MESSAGE_TYPE, (int) sourceId, (short) getSize()));
}
/**
* @return the size of this message in bytes
*/
@Override
public int getSize() {
return MESSAGE_BASE_SIZE + (20 * (int) numBoatsInRace);
}
/**
* Send this message as a stream of bytes
* @param outputStream The output stream to send the message
*/
@Override
public void send(DataOutputStream outputStream) {
ByteBuffer buff = ByteBuffer.allocate(Header.getSize() + getSize() + 4/*CRC*/);
buff.put(getHeader().getByteBuffer());
buff.position(Header.getSize());
// Version Number, 1 byte
buff.put(ByteBuffer.allocate(1).put((byte)MESSAGE_VERSION).array());
buff.position(Header.getSize() + 1);
// Current time, 2 bytes
buff.put(ByteBuffer.allocate(6).putInt((int)currentTime).array());
buff.position(Header.getSize() + 7);
// Race id, 4 bytes
buff.put(ByteBuffer.allocate(4).putInt((int)raceId).array());
buff.position(Header.getSize() + 11);
// Race status, 1 byte
buff.put(ByteBuffer.allocate(1).put((byte)raceStatus.getCode()).array());
buff.position(Header.getSize() + 12);
// Expected start time, 6 bytes
buff.put(ByteBuffer.allocate(6).putInt((int)expectedStartTime).array());
buff.position(Header.getSize() + 18);
// Wind direction, 2 bytes
buff.put(ByteBuffer.allocate(2).putShort((short)raceWindDirection.getCode()).array());
buff.position(Header.getSize() + 20);
// Wind Speed, 2 bytes
buff.put(ByteBuffer.allocate(2).putShort((short)windSpeed).array());
buff.position(Header.getSize() + 22);
// Number of boats, 1 byte
buff.put(ByteBuffer.allocate(1).put((byte)numBoatsInRace).array());
buff.position(Header.getSize() + 23);
// Race Type, 1 byte
buff.put(ByteBuffer.allocate(1).put((byte)raceType.getCode()).array());
buff.position(Header.getSize() + 24);
int buffPosition = Header.getSize() + 24;
for (BoatSubMessage boatSubMessage : boats){
buff.put(boatSubMessage.getByteBuffer());
buffPosition += boatSubMessage.getSize();
buff.position(buffPosition);
}
// calculate CRC
crc.update(buff.array());
// Add CRC to message
buff.put(ByteBuffer.allocate(4).putInt((short)crc.getValue()).array());
// Send
try {
outputStream.write(buff.array());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,20 @@
package seng302.server.messages;
/**
* Enum containing the types of races
* sent by the server
*/
public enum RaceType {
MATCH_RACE(1),
FLEET_RACE(2);
private long code;
RaceType(long code){
this.code = code;
}
public long getCode(){
return code;
}
}
@@ -0,0 +1,20 @@
package seng302.server.messages;
/**
* Enum containing the supported wind directions
*/
public enum WindDirection {
NORTH(0x0000L),
EAST(0x4000L),
SOUTH(0x8000L);
private long code;
WindDirection(long code) {
this.code = code;
}
public long getCode() {
return code;
}
}