WIP adding race status messages

#story[778]
main
Erika Savell 9 years ago
parent 5a972c855e
commit e2f3abffc6

@ -72,51 +72,15 @@ public class Event {
RaceData raceData = new RaceData(raceDataSource);
//Serialize race data to an XML as a string.
String xmlString = raceData.createXML();
System.out.println("working");
mockOutput.parseXMLString(xmlString, 26);
System.out.println("working");
}
public void sendBoatData() throws InvalidBoatDataException {
BoatData boatData = new BoatData(raceDataSource.getBoats());
//Serialize race data to an XML as a string.
String xmlString = boatData.createXML();
System.out.println("working");
mockOutput.parseXMLString(xmlString, 26);
System.out.println("working");
}
/**
* Returns the next sequence number to be used for regatta XML messages.
* @return
*/
public short getNextRegattaXMLSequenceNumber()
{
short currentNumber = regattaXMLSequenceNumber;
regattaXMLSequenceNumber += 1;
return currentNumber;
}
/**
* Returns the next sequence number to be used for race XML messages.
* @return
*/
public short getNextRaceXMLSequenceNumber()
{
short currentNumber = raceXMLSequenceNumber;
raceXMLSequenceNumber += 1;
return currentNumber;
}
/**
* Returns the next sequence number to be used for boat XML messages.
* @return
*/
public short getNextBoatXMLSequenceNumber()
{
short currentNumber = boatXMLSequenceNumber;
boatXMLSequenceNumber += 1;
return currentNumber;
}
}

@ -8,13 +8,12 @@ import org.geotools.referencing.GeodeticCalculator;
import seng302.DataInput.RaceDataSource;
import SharedModel.*;
import seng302.Networking.MessageEncoders.RaceVisionByteEncoder;
import seng302.Networking.MockOutput;
import seng302.Networking.Utils.BoatLocationMessage;
import seng302.Networking.Utils.BoatStatusMessage;
import seng302.Networking.Utils.Enums.BoatStatus;
import seng302.Networking.Utils.RaceStatus;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@ -30,10 +29,10 @@ public class Race implements Runnable {
protected List<Leg> legs;
protected int boatsFinished = 0;
protected long totalTimeElapsed;
protected int heartbeat = 0;
protected int scaleFactor;
protected int PRERACE_TIME = 120000; //time in milliseconds to pause during pre-race
protected int PRERACE_TIME = 12; //time in milliseconds to pause during pre-race
private int lastFPS = 20;
private int raceId;
private int dnfChance = 0; //percentage chance a boat fails at each checkpoint
private MockOutput mockOutput;
@ -64,6 +63,10 @@ public class Race implements Runnable {
this(raceData.getBoats(), raceData.getLegs(), scaleFactor, mockOutput);
}
public void setRaceId(int raceId) {
this.raceId = raceId;
}
/**
* Calculates the boats next GPS position based on its distance travelled and heading
*
@ -131,25 +134,6 @@ public class Race implements Runnable {
timer.start();
}
/**
* Takes total time elapsed and format to hour:minute:second
*
* @return Formatted time as string
*/
protected String calcTimer() {
long minutes;
long currentTimeInSeconds;
long remainingSeconds;
long hours;
currentTimeInSeconds = (totalTimeElapsed * scaleFactor) / 1000;
minutes = currentTimeInSeconds / 60;
remainingSeconds = currentTimeInSeconds % 60;
hours = minutes / 60;
minutes = minutes % 60;
return String.format("Race clock: %02d:%02d:%02d", hours, minutes, remainingSeconds);
}
/**
* Starts the Race Simulation, playing the race start to finish with the timescale.
* This prints the boats participating, the order that the events occur in time order, and the respective information of the events.
@ -173,6 +157,7 @@ public class Race implements Runnable {
long currentTime = System.currentTimeMillis();
//Update the total elapsed time.
totalTimeElapsed = currentTime - timeRaceStarted;
ArrayList<BoatStatusMessage> boatStatusMessages = new ArrayList<BoatStatusMessage>();
//For each boat, we update it's position, and generate a BoatLocationMessage.
for (BoatInRace boat : startingBoats) {
@ -180,47 +165,15 @@ public class Race implements Runnable {
//Update position.
updatePosition(boat, Math.round(1000 / lastFPS) > 20 ? 15 : Math.round(1000 / lastFPS));
checkPosition(boat, totalTimeElapsed);
//Generate a boat location message for the updated boat.
BoatLocationMessage boatLocationMessage = new BoatLocationMessage();
boatLocationMessage.setTime(currentTime);
boatLocationMessage.setSourceID(boat.getSourceID());
boatLocationMessage.setSequenceNumber(boat.getNextSequenceNumber());
boatLocationMessage.setDeviceType(BoatLocationMessage.RacingYacht);
boatLocationMessage.setLatitude(BoatLocationMessage.convertCoordinateDoubleToInt(boat.getCurrentPosition().getLatitude()));
boatLocationMessage.setLongitude(BoatLocationMessage.convertCoordinateDoubleToInt(boat.getCurrentPosition().getLongitude()));
boatLocationMessage.setAltitude(0);//Junk value.
boatLocationMessage.setHeading(BoatLocationMessage.convertHeadingDoubleToInt(boat.getHeading()));
boatLocationMessage.setPitch((short) 0);//Junk value.
boatLocationMessage.setRoll((short) 0);//Junk value.
boatLocationMessage.setBoatSpeed(BoatLocationMessage.convertBoatSpeedDoubleToInt(boat.getVelocity()));
boatLocationMessage.setBoatCOG(0);//Junk value.
boatLocationMessage.setBoatSOG(0);//Junk value.
boatLocationMessage.setApparentWindSpeed(0);//Junk value.
boatLocationMessage.setApparentWindAngle((short) 0);//Junk value.
boatLocationMessage.setTrueWindSpeed(0);//Junk value.
boatLocationMessage.setTrueWindDirection(0);//Junk value.
boatLocationMessage.setTrueWindAngle((short) 0);//Junk value.
boatLocationMessage.setCurrentDrift(0);//Junk value.
boatLocationMessage.setCurrentSet(0);//Junk value.
boatLocationMessage.setRudderAngle((short) 0);//Junk value.
//We have finished creating the message.
mockOutput.parseBoatLocation();
mockOutput.parseBoatLocation(boat);
boatStatusMessages.add(new BoatStatusMessage(boat.getSourceID(),
boat.getCurrentLeg().getLegNumber() >= 0 ? BoatStatus.RACING : BoatStatus.DNF, boat.getCurrentLeg().getLegNumber()));
} else {
stop();
}
}
RaceStatus raceStatus = new RaceStatus(totalTimeElapsed, raceId, 3, 2, boatStatusMessages);
mockOutput.parseRaceStatus();
}
}
}.start();

@ -1,9 +1,7 @@
package seng302.Networking.MessageDecoders;
import seng302.Networking.Utils.BoatStatus;
import seng302.Networking.Utils.BoatStatusMessage;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
@ -32,7 +30,7 @@ public class RaceStatusDecoder {
private short raceWindSpeed;
private int numberOfBoats;
private int raceType;
private ArrayList<BoatStatus> boats = new ArrayList<>();
private ArrayList<BoatStatusMessage> boats = new ArrayList<>();
public RaceStatusDecoder(byte[] encodedRaceStatus){
@ -68,7 +66,7 @@ public class RaceStatusDecoder {
byte[] estTimeAtNextMark = Arrays.copyOfRange(boatBytes, 8, 14);
byte[] estTimeAtFinish = Arrays.copyOfRange(boatBytes, 14, 20);
BoatStatus boat = new BoatStatus(bytesToInt(sourceID),boatStatus,
BoatStatusMessage boat = new BoatStatusMessage(bytesToInt(sourceID),boatStatus,
legNumber, numPenaltiesAwarded, numPenaltiesServed,
bytesToLong(estTimeAtNextMark), bytesToLong(estTimeAtFinish));
@ -113,7 +111,7 @@ public class RaceStatusDecoder {
return raceType;
}
public ArrayList<BoatStatus> getBoats() {
public ArrayList<BoatStatusMessage> getBoats() {
return boats;
}
}

@ -4,9 +4,7 @@ package seng302.Networking.MessageEncoders;
import seng302.Networking.Utils.*;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import static seng302.Networking.Utils.ByteConverter.*;
@ -34,9 +32,9 @@ public class RaceVisionByteEncoder {
*/
public static byte[] raceStatus(RaceStatus raceStatus){
ArrayList<BoatStatus> boatStatuses = raceStatus.getBoatStatuses();
ArrayList<BoatStatusMessage> boatStatusMessages = raceStatus.getBoatStatusMessages();
ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20*boatStatuses.size());
ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20* boatStatusMessages.size());
//Version Number 1 bytes
byte versionNum = 0b10; //this changes with the pdf. (2)
byte[] timeBytes = longToBytes(raceStatus.getCurrentTime(), 6);//time (6 bytes)
@ -45,7 +43,7 @@ public class RaceVisionByteEncoder {
byte[] expectedStart = longToBytes(raceStatus.getExpectedStartTime(), 6);//number of milliseconds from Jan 1, 1970 for when the data is valid
byte[] raceWind = ByteBuffer.allocate(2).put(intToBytes(raceStatus.getWindDirection(), 2)).array();//North = 0x0000 East = 0x4000 South = 0x8000.
byte[] windSpeed = ByteBuffer.allocate(2).put(intToBytes(raceStatus.getWindSpeed(), 2)).array();//mm/sec
byte[] numBoats = intToBytes(boatStatuses.size(), 1);
byte[] numBoats = intToBytes(boatStatusMessages.size(), 1);
byte[] bytesRaceType = intToBytes(raceStatus.getRaceType(), 1);//1 match race, 2 fleet race
raceStatusMessage.put(versionNum);
@ -58,14 +56,14 @@ public class RaceVisionByteEncoder {
raceStatusMessage.put(numBoats);
raceStatusMessage.put(bytesRaceType);
for (int i = 0; i < boatStatuses.size(); i++){
byte[] sourceID = intToBytes(boatStatuses.get(i).getSourceID());
byte[] boatStatus = intToBytes(boatStatuses.get(i).getBoatStatus(), 1);
byte[] legNum = intToBytes(boatStatuses.get(i).getLegNumber(), 1);
byte[] numPenalties = intToBytes(boatStatuses.get(i).getNumPenaltiesAwarded(), 1);
byte[] numPenaltiesServed = intToBytes(boatStatuses.get(i).getNumPenaltiesServed(), 1);
byte[] estNextMarkTime = longToBytes(boatStatuses.get(i).getEstTimeAtNextMark(), 6);
byte[] estFinishTime = longToBytes( boatStatuses.get(i).getEstTimeAtFinish(), 6);
for (int i = 0; i < boatStatusMessages.size(); i++){
byte[] sourceID = intToBytes(boatStatusMessages.get(i).getSourceID());
byte[] boatStatus = intToBytes(boatStatusMessages.get(i).getBoatStatus(), 1);
byte[] legNum = intToBytes(boatStatusMessages.get(i).getLegNumber(), 1);
byte[] numPenalties = intToBytes(boatStatusMessages.get(i).getNumPenaltiesAwarded(), 1);
byte[] numPenaltiesServed = intToBytes(boatStatusMessages.get(i).getNumPenaltiesServed(), 1);
byte[] estNextMarkTime = longToBytes(boatStatusMessages.get(i).getEstTimeAtNextMark(), 6);
byte[] estFinishTime = longToBytes( boatStatusMessages.get(i).getEstTimeAtFinish(), 6);
raceStatusMessage.put(sourceID);
raceStatusMessage.put(boatStatus);

@ -1,14 +1,17 @@
package seng302.Networking;
import SharedModel.BoatInRace;
import com.sun.jmx.remote.internal.ArrayQueue;
import seng302.Networking.MessageEncoders.RaceVisionByteEncoder;
import seng302.Networking.MessageEncoders.XMLMessageEncoder;
import seng302.Networking.Utils.BoatLocationMessage;
import seng302.Networking.Utils.MessageType;
import seng302.Networking.Utils.RaceStatus;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
/**
* TCP client to recive information from AC35 data source
@ -18,23 +21,26 @@ public class MockOutput implements Runnable
private long lastHeartbeatTime;
private RaceVisionByteEncoder messageEncoder = new RaceVisionByteEncoder();
//socket port 4942 as 4940 is ac35 live port and 4941 is ac35 test port
//socket port 5003 as 4940 is ac35 live port and 4941 is ac35 test port
private ServerSocket serverSocket;
private Socket mockSocket;
private DataOutputStream outToVisualiser;
//a buffer that contains items that are waiting to be sent
private ArrayList<byte[]> messagesToSendBuffer = new ArrayList<>();
private ArrayBlockingQueue<byte[]> messagesToSendBuffer = new ArrayBlockingQueue<>(99999999);
private short messageNumber = 1;
private short xmlSequenceNumber = 1;
private int heartbeatSequenceNum = 1;
private int boatLocationSequenceNumber = 1;
private int raceStatusSequenceNumber = 1;
public MockOutput() throws IOException {
//start Time
lastHeartbeatTime = System.currentTimeMillis();
serverSocket = new ServerSocket(4942);
serverSocket = new ServerSocket(5003);
}
@ -61,7 +67,7 @@ public class MockOutput implements Runnable
* @param xmlString the xml string to send
* @param messageType the kind of xml string, values given in AC35 spec (5 regatta, 6 race, 7 boat)
*/
public void parseXMLString(String xmlString, int messageType){
public synchronized void parseXMLString(String xmlString, int messageType){
XMLMessageEncoder encoder = new XMLMessageEncoder(messageNumber, System.currentTimeMillis(), messageType, xmlSequenceNumber,(short) xmlString.length(), xmlString);
//iterates the sequence numbers
xmlSequenceNumber++;
@ -77,7 +83,7 @@ public class MockOutput implements Runnable
/**
* Used to give the mocOutput information about boat location to be made into a message and sent
*/
public void parseBoatLocation(BoatInRace boat){
public synchronized void parseBoatLocation(BoatInRace boat){
BoatLocationMessage boatLocationMessage = new BoatLocationMessage(boat, boatLocationSequenceNumber);
//iterates the sequence number
boatLocationSequenceNumber++;
@ -95,7 +101,15 @@ public class MockOutput implements Runnable
addMessageToBufferToSend(binaryMessageEncoder.getFullMessage());
}
private void addMessageToBufferToSend(byte[] messagesToSendBuffer) {
public synchronized void parseRaceStatus(RaceStatus raceStatus) {
}
private synchronized void addMessageToBufferToSend(byte[] messagesToSendBuffer) {
this.messagesToSendBuffer.add(messagesToSendBuffer);
}

@ -1,9 +1,11 @@
package seng302.Networking.Utils;
import seng302.Networking.Utils.Enums.BoatStatus;
/**
* Created by hba56 on 23/04/17.
*/
public class BoatStatus{
public class BoatStatusMessage {
private int sourceID;
private byte boatStatus;
private byte legNumber;
@ -12,7 +14,7 @@ public class BoatStatus{
private long estTimeAtNextMark;
private long estTimeAtFinish;
public BoatStatus(int sourceID, byte boatStatus, byte legNumber, byte numPenaltiesAwarded, byte numPenaltiesServed, long estTimeAtNextMark, long estTimeAtFinish) {
public BoatStatusMessage(int sourceID, byte boatStatus, byte legNumber, byte numPenaltiesAwarded, byte numPenaltiesServed, long estTimeAtNextMark, long estTimeAtFinish) {
this.sourceID = sourceID;
this.boatStatus = boatStatus;
this.legNumber = legNumber;
@ -22,6 +24,18 @@ public class BoatStatus{
this.estTimeAtFinish = estTimeAtFinish;
}
public BoatStatusMessage(int sourceID, BoatStatus boatStatus, int legNum) {
this.sourceID = sourceID;
this.boatStatus = boatStatus.getValue();
this.legNumber = ByteConverter.intToBytes(legNum)[0];
numPenaltiesAwarded = 0;
numPenaltiesServed = 0;
estTimeAtFinish = 0;
estTimeAtNextMark = 0;
}
public int getSourceID() {
return sourceID;
}

@ -0,0 +1,41 @@
package seng302.Networking.Utils.Enums;
/**
* Created by esa46 on 28/04/17.
*/
public enum BoatStatus {
UNDEFINED(0), PRESTART(1), RACING(2), FINISHED(3), DNS(4), DNF(5), DSQ(6), OCS(7), NOT_A_STATUS(-1);
private byte value;
private BoatStatus(int value) { this.value = (byte)value; }
public byte getValue() {
return value;
}
public static BoatStatus valueOf(byte bite){
switch(bite){
case 0:
return UNDEFINED;
case 1:
return PRESTART;
case 2:
return RACING;
case 3:
return FINISHED;
case 4:
return DNS;
case 5:
return DNF;
case 6:
return DSQ;
case 7:
return OCS;
default:
return NOT_A_STATUS;
}
}
}

@ -13,9 +13,9 @@ public class RaceStatus extends AC35Data{
private int windDirection;
private int windSpeed;
private int raceType;
private ArrayList<BoatStatus> boatStatuses;
private ArrayList<BoatStatusMessage> boatStatusMessages;
public RaceStatus(long currentTime, int raceID, int raceStatus, long expectedStartTime, int windDirection, int windSpeed, int raceType, ArrayList<BoatStatus> boatStatuses){
public RaceStatus(long currentTime, int raceID, int raceStatus, long expectedStartTime, int windDirection, int windSpeed, int raceType, ArrayList<BoatStatusMessage> boatStatusMessages){
super(MessageType.RACESTATUS);
this.currentTime = currentTime;
this.raceID = raceID;
@ -24,10 +24,17 @@ public class RaceStatus extends AC35Data{
this.windDirection = windDirection;
this.windSpeed = windSpeed;
this.raceType = raceType;
this.boatStatuses = boatStatuses;//note this is a copy so any alterations to the parent will affect this.
this.boatStatusMessages = boatStatusMessages;//note this is a copy so any alterations to the parent will affect this.
}
public RaceStatus( long currentTime, int raceID, int raceStatus, int raceType, ArrayList<BoatStatusMessage> boatStatusMessages) {
super(MessageType.RACESTATUS);
this.currentTime = currentTime;
this.raceID = raceID;
this.raceStatus = raceStatus;
this.raceType = raceType;
this.boatStatusMessages = boatStatusMessages;
}
///Getters.
public long getCurrentTime()
@ -65,8 +72,8 @@ public class RaceStatus extends AC35Data{
return raceType;
}
public ArrayList<BoatStatus> getBoatStatuses()
public ArrayList<BoatStatusMessage> getBoatStatusMessages()
{
return boatStatuses;
return boatStatusMessages;
}
}

@ -31,10 +31,10 @@ public class VisualiserInput implements Runnable
VisualiserInput() throws IOException{
// connectionSocket = new Socket(InetAddress.getLocalHost(), 4942);
connectionSocket = new Socket(InetAddress.getLocalHost(), 5003);
//this is the test data that streams form the AC35 website
connectionSocket = new Socket("livedata.americascup.com",4941);
// connectionSocket = new Socket("livedata.americascup.com",4941);
//start Time
@ -98,18 +98,17 @@ public class VisualiserInput implements Runnable
System.out.println("HeartBeat Message! " + heartbeatSeqNum);
break;
case RACESTATUS:
// System.out.println("Race Status Message");
System.out.println("Race Status Message");
break;
case DISPLAYTEXTMESSAGE:
// System.out.println("Display Text Message");
//no decoder for this.
break;
case XMLMESSAGE:
// System.out.println("XML Message!");
System.out.println(((XMLMessage)data).getXmlMessage());
System.out.println("XML Message!");
break;
case RACESTARTSTATUS:
// System.out.println("Race Start Status Message");
System.out.println("Race Start Status Message");
break;
case YACHTEVENTCODE:
// System.out.println("Yacht Action Code!");
@ -124,7 +123,7 @@ public class VisualiserInput implements Runnable
//no decoder
break;
case BOATLOCATION:
// System.out.println("Boat Location Message!");
System.out.println("Boat Location Message!");
break;
case MARKROUNDING:
// System.out.println("Mark Rounding Message!");
@ -136,7 +135,7 @@ public class VisualiserInput implements Runnable
// System.out.println("Average Wind Message!");
break;
default:
// System.out.println("Broken Message!");
System.out.println("Broken Message!");
break;
}

@ -3,7 +3,7 @@ package seng302.Networking.MessageDecoders;
import org.junit.Assert;
import org.junit.Test;
import seng302.Networking.MessageEncoders.RaceVisionByteEncoder;
import seng302.Networking.Utils.BoatStatus;
import seng302.Networking.Utils.BoatStatusMessage;
import seng302.Networking.Utils.RaceStatus;
import java.util.ArrayList;
@ -32,8 +32,8 @@ public class RaceStatusDecoderTest {
long boat1TimeAtFinish = boat1TimeAtNextMark + (1000 * 15);
long boat2TimeAtFinish = boat2TimeAtNextMark + (1000 * 7);
BoatStatus boatStatus1 = new BoatStatus(boat1SourceID, boat1Status, boat1LegNumber, boat1PenaltiesAwarded, boat1PenaltiesServed, boat1TimeAtNextMark, boat1TimeAtFinish);
BoatStatus boatStatus2 = new BoatStatus(boat2SourceID, boat2Status, boat2LegNumber, boat2PenaltiesAwarded, boat2PenaltiesServed, boat2TimeAtNextMark, boat2TimeAtFinish);
BoatStatusMessage boatStatusMessage1 = new BoatStatusMessage(boat1SourceID, boat1Status, boat1LegNumber, boat1PenaltiesAwarded, boat1PenaltiesServed, boat1TimeAtNextMark, boat1TimeAtFinish);
BoatStatusMessage boatStatusMessage2 = new BoatStatusMessage(boat2SourceID, boat2Status, boat2LegNumber, boat2PenaltiesAwarded, boat2PenaltiesServed, boat2TimeAtNextMark, boat2TimeAtFinish);
int raceID = 585;
int raceStatus = 3;
@ -41,11 +41,11 @@ public class RaceStatusDecoderTest {
int windDirection = 2341;
int windSpeed = 10201;
int raceType = 1;
ArrayList<BoatStatus> boatStatuses = new ArrayList<>(2);
boatStatuses.add(boatStatus1);
boatStatuses.add(boatStatus2);
ArrayList<BoatStatusMessage> boatStatusMessages = new ArrayList<>(2);
boatStatusMessages.add(boatStatusMessage1);
boatStatusMessages.add(boatStatusMessage2);
RaceStatus raceStatusObject = new RaceStatus(time, raceID, raceStatus, raceStartTime, windDirection, windSpeed, raceType, boatStatuses);
RaceStatus raceStatusObject = new RaceStatus(time, raceID, raceStatus, raceStartTime, windDirection, windSpeed, raceType, boatStatusMessages);
byte[] encodedRaceStatus = RaceVisionByteEncoder.raceStatus(raceStatusObject);
@ -61,7 +61,7 @@ public class RaceStatusDecoderTest {
Assert.assertEquals(windSpeed, decoderTest.getRaceWindSpeed());
BoatStatus boat1 = decoderTest.getBoats().get(0);
BoatStatusMessage boat1 = decoderTest.getBoats().get(0);
Assert.assertEquals(boat1SourceID, boat1.getSourceID());
Assert.assertEquals(boat1Status, boat1.getBoatStatus());

Loading…
Cancel
Save