Added XMLMessageEncoder.
Refactored XMLMessageDecoder to be consistent with other decoders - only needs to expose the XMLMessage. Refactored BoatLocationDecoder to be consistent with other decoders - only needs to expose the BoatLocation. Updated XMLMessageDecoderTest to use new encoder/decoder. Also tests all three message types. Removed XMLMessageEncoderTest as it was redundant. Updated BinaryMessageDecoderTest.xmlMessageTest() to use updated XMLMessage encoder/decoder. issue #35 #36 #story[1095]
This commit is contained in:
@@ -134,11 +134,12 @@ public class MockOutput implements Runnable
|
|||||||
* Encodes/serialises a XMLMessage message, and returns it.
|
* Encodes/serialises a XMLMessage message, and returns it.
|
||||||
* @param xmlMessage The XMLMessage message to serialise.
|
* @param xmlMessage The XMLMessage message to serialise.
|
||||||
* @return The XMLMessage message in a serialised form.
|
* @return The XMLMessage message in a serialised form.
|
||||||
|
* @throws InvalidMessageException Thrown if the message cannot be encoded.
|
||||||
*/
|
*/
|
||||||
private synchronized byte[] parseXMLMessage(XMLMessage xmlMessage) {
|
private synchronized byte[] parseXMLMessage(XMLMessage xmlMessage) throws InvalidMessageException {
|
||||||
|
|
||||||
//Serialize the xml message.
|
//Serialize the xml message.
|
||||||
byte[] encodedXML = RaceVisionByteEncoder.xmlMessage(xmlMessage);
|
byte[] encodedXML = RaceVisionByteEncoder.encode(xmlMessage);
|
||||||
|
|
||||||
//Place the message in a packet.
|
//Place the message in a packet.
|
||||||
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
|
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
|
||||||
@@ -262,15 +263,23 @@ public class MockOutput implements Runnable
|
|||||||
//Send XML messages.
|
//Send XML messages.
|
||||||
if (!sentXMLs) {
|
if (!sentXMLs) {
|
||||||
//Serialise them.
|
//Serialise them.
|
||||||
byte[] raceXMLBlob = parseXMLMessage(latestMessages.getRaceXMLMessage());
|
|
||||||
byte[] regattaXMLBlob = parseXMLMessage(latestMessages.getRegattaXMLMessage());
|
|
||||||
byte[] boatsXMLBlob = parseXMLMessage(latestMessages.getBoatXMLMessage());
|
|
||||||
|
|
||||||
//Send them.
|
try {
|
||||||
outToVisualiser.write(raceXMLBlob);
|
byte[] raceXMLBlob = parseXMLMessage(latestMessages.getRaceXMLMessage());
|
||||||
outToVisualiser.write(regattaXMLBlob);
|
byte[] regattaXMLBlob = parseXMLMessage(latestMessages.getRegattaXMLMessage());
|
||||||
outToVisualiser.write(boatsXMLBlob);
|
byte[] boatsXMLBlob = parseXMLMessage(latestMessages.getBoatXMLMessage());
|
||||||
sentXMLs = true;
|
|
||||||
|
//Send them.
|
||||||
|
outToVisualiser.write(raceXMLBlob);
|
||||||
|
outToVisualiser.write(regattaXMLBlob);
|
||||||
|
outToVisualiser.write(boatsXMLBlob);
|
||||||
|
sentXMLs = true;
|
||||||
|
|
||||||
|
} catch (InvalidMessageException e) {
|
||||||
|
Logger.getGlobal().log(Level.WARNING, "Could not encode XMLMessage: " + latestMessages.getRaceXMLMessage(), e);
|
||||||
|
continue; //Go to next iteration.
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Sends the RaceStatus message.
|
//Sends the RaceStatus message.
|
||||||
|
|||||||
@@ -149,8 +149,7 @@ public class BinaryMessageDecoder {
|
|||||||
case XMLMESSAGE:
|
case XMLMESSAGE:
|
||||||
//System.out.println("XML Message!");
|
//System.out.println("XML Message!");
|
||||||
XMLMessageDecoder xmdecoder = new XMLMessageDecoder(messageBody);
|
XMLMessageDecoder xmdecoder = new XMLMessageDecoder(messageBody);
|
||||||
xmdecoder.decode();
|
return xmdecoder.getMessage();
|
||||||
return new XMLMessage(XMLMessage.currentVersionNumber, xmdecoder.getAckNumber(), xmdecoder.getTimeStamp(), xmdecoder.getXmlMsgSubType(), xmdecoder.getSequenceNumber(), xmdecoder.getXmlMessageContents());
|
|
||||||
|
|
||||||
case RACESTARTSTATUS:
|
case RACESTARTSTATUS:
|
||||||
//System.out.println("Race Start Status Message");
|
//System.out.println("Race Start Status Message");
|
||||||
|
|||||||
@@ -11,132 +11,138 @@ import static network.Utils.ByteConverter.bytesToShort;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by hba56 on 21/04/17.
|
* Decodes {@link BoatLocation} messages.
|
||||||
*/
|
*/
|
||||||
public class BoatLocationDecoder {
|
public class BoatLocationDecoder {
|
||||||
private byte messageVersionNumber;
|
|
||||||
private byte[] time;
|
|
||||||
private byte[] sourceID;
|
|
||||||
private byte[] seqNum;
|
|
||||||
private byte deviceType;
|
|
||||||
private byte[] latitude;
|
|
||||||
private byte[] longitude;
|
|
||||||
private byte[] altitude;
|
|
||||||
private byte[] heading;
|
|
||||||
private byte[] pitch;
|
|
||||||
private byte[] roll;
|
|
||||||
private byte[] boatSpeed;
|
|
||||||
private byte[] cog;
|
|
||||||
private byte[] sog;
|
|
||||||
private byte[] apparentWindSpeed;
|
|
||||||
private byte[] apparentWindAngle;
|
|
||||||
private byte[] trueWindSpeed;
|
|
||||||
private byte[] trueWindDirection;
|
|
||||||
private byte[] trueWindAngle;
|
|
||||||
private byte[] currentDrift;
|
|
||||||
private byte[] currentSet;
|
|
||||||
private byte[] rudderAngle;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encoded message.
|
||||||
|
*/
|
||||||
|
private byte[] encodedMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decoded message.
|
||||||
|
*/
|
||||||
private BoatLocation message;
|
private BoatLocation message;
|
||||||
|
|
||||||
public BoatLocationDecoder(byte[] encodedBoatLocation) {
|
|
||||||
byte numMessageVersionNumber = 0;
|
|
||||||
long numTime = 0;
|
|
||||||
int numSourceID = 0;
|
|
||||||
int numSeqNum = 0;
|
|
||||||
byte numDeviceType = 0;
|
|
||||||
int numLatitude = 0;
|
|
||||||
int numLongitude = 0;
|
|
||||||
int numAltitude = 0;
|
|
||||||
int numHeading = 0;
|
|
||||||
short numPitch = 0;
|
|
||||||
short numRoll = 0;
|
|
||||||
int numBoatSpeed = 0;
|
|
||||||
int numCog = 0;
|
|
||||||
int numSog = 0;
|
|
||||||
int numApparentWindSpeed = 0;
|
|
||||||
short numApparentWindAngle = 0;
|
|
||||||
int numTrueWindSpeed = 0;
|
|
||||||
short numTrueWindDirection = 0;
|
|
||||||
short numTrueWindAngle = 0;
|
|
||||||
int numCurrentDrift = 0;
|
|
||||||
int numCurrentSet = 0;
|
|
||||||
short numRudderAngle = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
messageVersionNumber = encodedBoatLocation[0];
|
|
||||||
numMessageVersionNumber = messageVersionNumber;
|
|
||||||
time = Arrays.copyOfRange(encodedBoatLocation, 1, 7);
|
|
||||||
numTime = bytesToLong(time);
|
|
||||||
sourceID = Arrays.copyOfRange(encodedBoatLocation, 7, 11);
|
|
||||||
numSourceID = bytesToInt(sourceID);
|
|
||||||
seqNum = Arrays.copyOfRange(encodedBoatLocation, 11, 15);
|
|
||||||
numSeqNum = bytesToInt(seqNum);
|
|
||||||
deviceType = encodedBoatLocation[15];
|
|
||||||
numDeviceType = deviceType;
|
|
||||||
latitude = Arrays.copyOfRange(encodedBoatLocation, 16, 20);
|
|
||||||
numLatitude = bytesToInt(latitude);
|
|
||||||
longitude = Arrays.copyOfRange(encodedBoatLocation, 20, 24);
|
|
||||||
numLongitude = bytesToInt(longitude);
|
|
||||||
altitude = Arrays.copyOfRange(encodedBoatLocation, 24, 28);
|
|
||||||
numAltitude = bytesToInt(altitude);
|
|
||||||
heading = Arrays.copyOfRange(encodedBoatLocation, 28, 30);
|
|
||||||
numHeading = bytesToInt(heading);
|
|
||||||
pitch = Arrays.copyOfRange(encodedBoatLocation, 30, 32);
|
|
||||||
numPitch = bytesToShort(pitch);
|
|
||||||
roll = Arrays.copyOfRange(encodedBoatLocation, 32, 34);
|
|
||||||
numRoll = bytesToShort(roll);
|
|
||||||
boatSpeed = Arrays.copyOfRange(encodedBoatLocation, 34, 36);
|
|
||||||
numBoatSpeed = bytesToInt(boatSpeed);
|
|
||||||
cog = Arrays.copyOfRange(encodedBoatLocation, 36, 38);
|
|
||||||
numCog = bytesToInt(cog);
|
|
||||||
sog = Arrays.copyOfRange(encodedBoatLocation, 38, 40);
|
|
||||||
numSog = bytesToInt(sog);
|
|
||||||
apparentWindSpeed = Arrays.copyOfRange(encodedBoatLocation, 40, 42);
|
|
||||||
numApparentWindSpeed = bytesToInt(apparentWindSpeed);
|
|
||||||
apparentWindAngle = Arrays.copyOfRange(encodedBoatLocation, 42, 44);
|
|
||||||
numApparentWindAngle = bytesToShort(apparentWindAngle);
|
|
||||||
trueWindSpeed = Arrays.copyOfRange(encodedBoatLocation, 44, 46);
|
|
||||||
numTrueWindSpeed = bytesToInt(trueWindSpeed);
|
|
||||||
trueWindDirection = Arrays.copyOfRange(encodedBoatLocation, 46, 48);
|
|
||||||
numTrueWindDirection = bytesToShort(trueWindDirection);
|
|
||||||
trueWindAngle = Arrays.copyOfRange(encodedBoatLocation, 48, 50);
|
|
||||||
numTrueWindAngle = bytesToShort(trueWindAngle);
|
|
||||||
currentDrift = Arrays.copyOfRange(encodedBoatLocation, 50, 52);
|
|
||||||
numCurrentDrift = bytesToInt(currentDrift);
|
|
||||||
currentSet = Arrays.copyOfRange(encodedBoatLocation, 52, 54);
|
|
||||||
numCurrentSet = bytesToShort(currentSet);
|
|
||||||
rudderAngle = Arrays.copyOfRange(encodedBoatLocation, 54, 56);
|
|
||||||
numRudderAngle = bytesToShort(rudderAngle);
|
|
||||||
} catch(ArrayIndexOutOfBoundsException e){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
message = new BoatLocation(numMessageVersionNumber, numTime,
|
/**
|
||||||
numSourceID, numSeqNum, numDeviceType, numLatitude,
|
* Constructs a decoder to decode a given message.
|
||||||
numLongitude, numAltitude, numHeading, numPitch,
|
* @param encodedMessage The message to decode.
|
||||||
numRoll, numBoatSpeed, numCog, numSog, numApparentWindSpeed,
|
*/
|
||||||
numApparentWindAngle, numTrueWindSpeed, numTrueWindDirection,
|
public BoatLocationDecoder(byte[] encodedMessage) {
|
||||||
numTrueWindAngle, numCurrentDrift, numCurrentSet, numRudderAngle
|
|
||||||
);/*
|
|
||||||
message = new BoatLocation(messageVersionNumber, bytesToLong(time),
|
|
||||||
bytesToInt(sourceID), bytesToInt(seqNum),
|
|
||||||
deviceType, bytesToInt(latitude),
|
|
||||||
bytesToInt(longitude), bytesToInt(altitude),
|
|
||||||
bytesToInt(heading), bytesToShort(pitch),
|
|
||||||
bytesToShort(roll), bytesToInt(boatSpeed),
|
|
||||||
bytesToInt(cog), bytesToInt(sog),
|
|
||||||
bytesToInt(apparentWindSpeed), bytesToShort(apparentWindAngle),
|
|
||||||
bytesToInt(trueWindSpeed), bytesToShort(trueWindDirection),
|
|
||||||
bytesToShort(trueWindAngle), bytesToInt(currentDrift),
|
|
||||||
bytesToInt(currentSet), bytesToShort(rudderAngle)
|
|
||||||
);*/
|
|
||||||
|
|
||||||
// System.out.println(bytesToInt(sourceID));
|
this.encodedMessage = encodedMessage;
|
||||||
// System.out.println(bytesToInt(boatSpeed));
|
|
||||||
|
decode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the contained message.
|
||||||
|
*/
|
||||||
|
private void decode() {
|
||||||
|
|
||||||
|
byte[] messageVersionNumber = Arrays.copyOfRange(encodedMessage, 0, 1);
|
||||||
|
byte numMessageVersionNumber = messageVersionNumber[0];
|
||||||
|
|
||||||
|
byte[] time = Arrays.copyOfRange(encodedMessage, 1, 7);
|
||||||
|
long numTime = bytesToLong(time);
|
||||||
|
|
||||||
|
byte[] sourceID = Arrays.copyOfRange(encodedMessage, 7, 11);
|
||||||
|
int numSourceID = bytesToInt(sourceID);
|
||||||
|
|
||||||
|
byte[] seqNum = Arrays.copyOfRange(encodedMessage, 11, 15);
|
||||||
|
int numSeqNum = bytesToInt(seqNum);
|
||||||
|
|
||||||
|
byte[] deviceType = Arrays.copyOfRange(encodedMessage, 15, 16);
|
||||||
|
byte numDeviceType = deviceType[0];
|
||||||
|
|
||||||
|
byte[] latitude = Arrays.copyOfRange(encodedMessage, 16, 20);
|
||||||
|
int numLatitude = bytesToInt(latitude);
|
||||||
|
|
||||||
|
byte[] longitude = Arrays.copyOfRange(encodedMessage, 20, 24);
|
||||||
|
int numLongitude = bytesToInt(longitude);
|
||||||
|
|
||||||
|
byte[] altitude = Arrays.copyOfRange(encodedMessage, 24, 28);
|
||||||
|
int numAltitude = bytesToInt(altitude);
|
||||||
|
|
||||||
|
byte[] heading = Arrays.copyOfRange(encodedMessage, 28, 30);
|
||||||
|
int numHeading = bytesToInt(heading);
|
||||||
|
|
||||||
|
byte[] pitch = Arrays.copyOfRange(encodedMessage, 30, 32);
|
||||||
|
short numPitch = bytesToShort(pitch);
|
||||||
|
|
||||||
|
byte[] roll = Arrays.copyOfRange(encodedMessage, 32, 34);
|
||||||
|
short numRoll = bytesToShort(roll);
|
||||||
|
|
||||||
|
byte[] boatSpeed = Arrays.copyOfRange(encodedMessage, 34, 36);
|
||||||
|
int numBoatSpeed = bytesToInt(boatSpeed);
|
||||||
|
|
||||||
|
byte[] cog = Arrays.copyOfRange(encodedMessage, 36, 38);
|
||||||
|
int numCog = bytesToInt(cog);
|
||||||
|
|
||||||
|
byte[] sog = Arrays.copyOfRange(encodedMessage, 38, 40);
|
||||||
|
int numSog = bytesToInt(sog);
|
||||||
|
|
||||||
|
byte[] apparentWindSpeed = Arrays.copyOfRange(encodedMessage, 40, 42);
|
||||||
|
int numApparentWindSpeed = bytesToInt(apparentWindSpeed);
|
||||||
|
|
||||||
|
byte[] apparentWindAngle = Arrays.copyOfRange(encodedMessage, 42, 44);
|
||||||
|
short numApparentWindAngle = bytesToShort(apparentWindAngle);
|
||||||
|
|
||||||
|
byte[] trueWindSpeed = Arrays.copyOfRange(encodedMessage, 44, 46);
|
||||||
|
int numTrueWindSpeed = bytesToInt(trueWindSpeed);
|
||||||
|
|
||||||
|
byte[] trueWindDirection = Arrays.copyOfRange(encodedMessage, 46, 48);
|
||||||
|
short numTrueWindDirection = bytesToShort(trueWindDirection);
|
||||||
|
|
||||||
|
byte[] trueWindAngle = Arrays.copyOfRange(encodedMessage, 48, 50);
|
||||||
|
short numTrueWindAngle = bytesToShort(trueWindAngle);
|
||||||
|
|
||||||
|
byte[] currentDrift = Arrays.copyOfRange(encodedMessage, 50, 52);
|
||||||
|
int numCurrentDrift = bytesToInt(currentDrift);
|
||||||
|
|
||||||
|
byte[] currentSet = Arrays.copyOfRange(encodedMessage, 52, 54);
|
||||||
|
int numCurrentSet = bytesToShort(currentSet);
|
||||||
|
|
||||||
|
byte[] rudderAngle = Arrays.copyOfRange(encodedMessage, 54, 56);
|
||||||
|
short numRudderAngle = bytesToShort(rudderAngle);
|
||||||
|
|
||||||
|
|
||||||
|
message = new BoatLocation(
|
||||||
|
numMessageVersionNumber,
|
||||||
|
numTime,
|
||||||
|
numSourceID,
|
||||||
|
numSeqNum,
|
||||||
|
numDeviceType,
|
||||||
|
numLatitude,
|
||||||
|
numLongitude,
|
||||||
|
numAltitude,
|
||||||
|
numHeading,
|
||||||
|
numPitch,
|
||||||
|
numRoll,
|
||||||
|
numBoatSpeed,
|
||||||
|
numCog,
|
||||||
|
numSog,
|
||||||
|
numApparentWindSpeed,
|
||||||
|
numApparentWindAngle,
|
||||||
|
numTrueWindSpeed,
|
||||||
|
numTrueWindDirection,
|
||||||
|
numTrueWindAngle,
|
||||||
|
numCurrentDrift,
|
||||||
|
numCurrentSet,
|
||||||
|
numRudderAngle );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the decoded message.
|
||||||
|
* @return The decoded message.
|
||||||
|
*/
|
||||||
public BoatLocation getMessage() {
|
public BoatLocation getMessage() {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
import network.Messages.Enums.XMLMessageType;
|
import network.Messages.Enums.XMLMessageType;
|
||||||
|
import network.Messages.XMLMessage;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static network.Utils.ByteConverter.bytesToLong;
|
import static network.Utils.ByteConverter.bytesToLong;
|
||||||
@@ -12,73 +10,70 @@ import static network.Utils.ByteConverter.bytesToShort;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by hba56 on 20/04/17.
|
* Decodes {@link network.Messages.XMLMessage} messages.
|
||||||
*/
|
*/
|
||||||
public class XMLMessageDecoder {
|
public class XMLMessageDecoder {
|
||||||
private byte messageVersionNumber;
|
|
||||||
private short ackNumber;
|
|
||||||
private long timeStamp;
|
|
||||||
private byte xmlMsgSubType;
|
|
||||||
private short sequenceNumber;
|
|
||||||
private short xmlMsgLength;
|
|
||||||
private String xmlMessage;
|
|
||||||
|
|
||||||
private byte[] bytes;
|
/**
|
||||||
|
* The encoded message.
|
||||||
|
*/
|
||||||
|
private byte[] encodedMessage;
|
||||||
|
|
||||||
public XMLMessageDecoder(byte[] bytes) {
|
/**
|
||||||
this.bytes = bytes;
|
* The decoded message.
|
||||||
}
|
*/
|
||||||
|
private XMLMessage message;
|
||||||
public void decode(){
|
|
||||||
byte[] ackNumberBytes = Arrays.copyOfRange(bytes, 1, 3);
|
|
||||||
byte[] timeStampBytes = Arrays.copyOfRange(bytes, 3, 9);
|
|
||||||
byte[] sequenceNumberBytes = Arrays.copyOfRange(bytes, 10, 12);
|
|
||||||
byte[] xmlMsgLengthBytes = Arrays.copyOfRange(bytes, 12, 14);
|
|
||||||
byte[] xmlMessagebytes = Arrays.copyOfRange(bytes, 14, bytes.length);
|
|
||||||
|
|
||||||
this.xmlMsgSubType = bytes[9];
|
|
||||||
this.messageVersionNumber = bytes[0];
|
|
||||||
this.ackNumber = bytesToShort(ackNumberBytes);
|
|
||||||
|
|
||||||
this.timeStamp = bytesToLong(timeStampBytes);
|
|
||||||
|
|
||||||
this.sequenceNumber = bytesToShort(sequenceNumberBytes);
|
|
||||||
this.xmlMsgLength = bytesToShort(xmlMsgLengthBytes);
|
|
||||||
this.xmlMessage = new String(xmlMessagebytes).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getMessageVersionNumber() {
|
|
||||||
return messageVersionNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getAckNumber() {
|
|
||||||
return ackNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimeStamp() {
|
|
||||||
return timeStamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public XMLMessageType getXmlMsgSubType() {
|
|
||||||
return XMLMessageType.fromByte(xmlMsgSubType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getSequenceNumber() {
|
|
||||||
return sequenceNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getXmlMsgLength() {
|
|
||||||
return xmlMsgLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the contents of the XML message (e.g., the contents of a race.xml file).
|
* Constructs a decoder to decode a given message.
|
||||||
* @return The contents of the XML message.
|
* @param encodedMessage The message to decode.
|
||||||
*/
|
*/
|
||||||
public String getXmlMessageContents() {
|
public XMLMessageDecoder(byte[] encodedMessage) {
|
||||||
return xmlMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
|
decode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the contained message.
|
||||||
|
*/
|
||||||
|
private void decode() {
|
||||||
|
|
||||||
|
byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
|
||||||
|
byte[] ackNumberBytes = Arrays.copyOfRange(encodedMessage, 1, 3);
|
||||||
|
byte[] timeStampBytes = Arrays.copyOfRange(encodedMessage, 3, 9);
|
||||||
|
byte[] xmlMsgSubTypeBytes = Arrays.copyOfRange(encodedMessage, 9, 10);
|
||||||
|
byte[] sequenceNumberBytes = Arrays.copyOfRange(encodedMessage, 10, 12);
|
||||||
|
byte[] xmlMsgLengthBytes = Arrays.copyOfRange(encodedMessage, 12, 14);
|
||||||
|
byte[] xmlMessagebytes = Arrays.copyOfRange(encodedMessage, 14, encodedMessage.length);
|
||||||
|
|
||||||
|
|
||||||
|
byte messageVersionNumber = messageVersionNumberBytes[0];
|
||||||
|
short ackNumber = bytesToShort(ackNumberBytes);
|
||||||
|
long timeStamp = bytesToLong(timeStampBytes);
|
||||||
|
XMLMessageType xmlMsgSubType = XMLMessageType.fromByte(xmlMsgSubTypeBytes[0]);
|
||||||
|
short sequenceNumber = bytesToShort(sequenceNumberBytes);
|
||||||
|
short xmlMsgLength = bytesToShort(xmlMsgLengthBytes);
|
||||||
|
String xmlMessage = new String(xmlMessagebytes);
|
||||||
|
|
||||||
|
|
||||||
|
message = new XMLMessage(
|
||||||
|
messageVersionNumber,
|
||||||
|
ackNumber,
|
||||||
|
timeStamp,
|
||||||
|
xmlMsgSubType,
|
||||||
|
sequenceNumber,
|
||||||
|
xmlMessage );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the decoded message.
|
||||||
|
* @return The decoded message.
|
||||||
|
*/
|
||||||
|
public XMLMessage getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ public class EncoderFactory {
|
|||||||
|
|
||||||
case HEARTBEAT: return new HeartBeatEncoder();
|
case HEARTBEAT: return new HeartBeatEncoder();
|
||||||
|
|
||||||
|
case XMLMESSAGE: return new XMLMessageEncoder();
|
||||||
|
|
||||||
case BOATLOCATION: return new BoatLocationEncoder();
|
case BOATLOCATION: return new BoatLocationEncoder();
|
||||||
|
|
||||||
case REQUEST_TO_JOIN: return new RequestToJoinEncoder();
|
case REQUEST_TO_JOIN: return new RequestToJoinEncoder();
|
||||||
|
|||||||
@@ -170,43 +170,6 @@ public class RaceVisionByteEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes an xml message into a byte array.
|
|
||||||
* @param xmlMessage The message to serialize.
|
|
||||||
* @return byte array contaning serialized message.
|
|
||||||
*/
|
|
||||||
public static byte[] xmlMessage(XMLMessage xmlMessage) {
|
|
||||||
|
|
||||||
|
|
||||||
byte[] messageBytes = xmlMessage.getXmlMessage().getBytes(StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
ByteBuffer tempOutputByteBuffer = ByteBuffer.allocate(14 + messageBytes.length);
|
|
||||||
|
|
||||||
//ackNumber converted to bytes
|
|
||||||
byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2);
|
|
||||||
|
|
||||||
//Timestamp converted to bytes.
|
|
||||||
byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6);
|
|
||||||
|
|
||||||
//sequenceNumber converted to bytes
|
|
||||||
byte[] sequenceNumberBytes = intToBytes(xmlMessage.getSequenceNumber(), 2);
|
|
||||||
|
|
||||||
//xmlMsgLength converted to bytes
|
|
||||||
byte[] xmlMsgLengthBytes = intToBytes(xmlMessage.getXmlMsgLength(), 2);
|
|
||||||
|
|
||||||
|
|
||||||
tempOutputByteBuffer.put(xmlMessage.getVersionNumber());
|
|
||||||
tempOutputByteBuffer.put(ackNumberBytes);
|
|
||||||
tempOutputByteBuffer.put(timestampBytes);
|
|
||||||
tempOutputByteBuffer.put(xmlMessage.getXmlMsgSubType().getValue());
|
|
||||||
tempOutputByteBuffer.put(sequenceNumberBytes);
|
|
||||||
tempOutputByteBuffer.put(xmlMsgLengthBytes);
|
|
||||||
tempOutputByteBuffer.put(messageBytes);
|
|
||||||
|
|
||||||
return tempOutputByteBuffer.array();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] markRounding(int time, int ackNumber, int raceID, int sourceID, int boatStatus, int roundingSide, int markType, int markID){
|
public static byte[] markRounding(int time, int ackNumber, int raceID, int sourceID, int boatStatus, int roundingSide, int markType, int markID){
|
||||||
int messageVersionNumber = 0b1;
|
int messageVersionNumber = 0b1;
|
||||||
byte[] byteTime = longToBytes(time, 6);
|
byte[] byteTime = longToBytes(time, 6);
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Messages.AC35Data;
|
||||||
|
import network.Messages.XMLMessage;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import static network.Utils.ByteConverter.intToBytes;
|
||||||
|
import static network.Utils.ByteConverter.longToBytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This encoder can encode a {@link XMLMessage} message.
|
||||||
|
*/
|
||||||
|
public class XMLMessageEncoder implements MessageEncoder {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
public XMLMessageEncoder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encode(AC35Data message) {
|
||||||
|
|
||||||
|
//Downcast.
|
||||||
|
XMLMessage xmlMessage = (XMLMessage) message;
|
||||||
|
|
||||||
|
|
||||||
|
byte[] messageBytes = xmlMessage.getXmlMessage().getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
//Message is 14 + xmlMessage.length bytes.
|
||||||
|
ByteBuffer tempOutputByteBuffer = ByteBuffer.allocate(14 + messageBytes.length);
|
||||||
|
|
||||||
|
//ackNumber converted to bytes
|
||||||
|
byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2);
|
||||||
|
|
||||||
|
//Timestamp converted to bytes.
|
||||||
|
byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6);
|
||||||
|
|
||||||
|
//sequenceNumber converted to bytes
|
||||||
|
byte[] sequenceNumberBytes = intToBytes(xmlMessage.getSequenceNumber(), 2);
|
||||||
|
|
||||||
|
//xmlMsgLength converted to bytes
|
||||||
|
byte[] xmlMsgLengthBytes = intToBytes(xmlMessage.getXmlMsgLength(), 2);
|
||||||
|
|
||||||
|
|
||||||
|
tempOutputByteBuffer.put(xmlMessage.getVersionNumber());
|
||||||
|
tempOutputByteBuffer.put(ackNumberBytes);
|
||||||
|
tempOutputByteBuffer.put(timestampBytes);
|
||||||
|
tempOutputByteBuffer.put(xmlMessage.getXmlMsgSubType().getValue());
|
||||||
|
tempOutputByteBuffer.put(sequenceNumberBytes);
|
||||||
|
tempOutputByteBuffer.put(xmlMsgLengthBytes);
|
||||||
|
tempOutputByteBuffer.put(messageBytes);
|
||||||
|
|
||||||
|
return tempOutputByteBuffer.array();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package network;
|
|||||||
|
|
||||||
import network.Exceptions.InvalidMessageException;
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.MessageDecoders.XMLMessageDecoder;
|
import network.MessageDecoders.XMLMessageDecoder;
|
||||||
|
import network.MessageDecoders.XMLMessageDecoderTest;
|
||||||
import network.MessageEncoders.RaceVisionByteEncoder;
|
import network.MessageEncoders.RaceVisionByteEncoder;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.Enums.MessageType;
|
import network.Messages.Enums.MessageType;
|
||||||
@@ -21,29 +22,46 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by hba56 on 21/04/17.
|
* Tests the binary message decoder and encoder for a variety of messages.
|
||||||
*/
|
*/
|
||||||
public class BinaryMessageDecoderTest {
|
public class BinaryMessageDecoderTest {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if an XMLMessage can be encoded and decoded correctly.
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void decodeTest(){
|
public void xmlMessageTest() throws Exception {
|
||||||
try{
|
|
||||||
String xmlString = XMLReader.readXMLFileToString("network/raceXML/Regatta.xml", StandardCharsets.UTF_8);
|
try {
|
||||||
|
|
||||||
|
String filePath = "network/raceXML/Regatta.xml";
|
||||||
|
XMLMessageType messageType = XMLMessageType.REGATTA;
|
||||||
|
|
||||||
|
String xmlString = XMLReader.readXMLFileToString(filePath, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
|
|
||||||
XMLMessage xmlMessagePre = new XMLMessage(
|
XMLMessage xmlMessage = new XMLMessage(
|
||||||
(byte)1,
|
(byte)1,
|
||||||
1,
|
1,
|
||||||
time,
|
time,
|
||||||
XMLMessageType.REGATTA,
|
messageType,
|
||||||
(short)1,
|
(short)1,
|
||||||
xmlString );
|
xmlString );
|
||||||
|
|
||||||
byte[] encodedMessage = RaceVisionByteEncoder.xmlMessage(xmlMessagePre);
|
byte[] encodedMessage = RaceVisionByteEncoder.encode(xmlMessage);
|
||||||
|
|
||||||
BinaryMessageEncoder testMessage = new BinaryMessageEncoder(MessageType.XMLMESSAGE, time, 1, (short)encodedMessage.length, encodedMessage);
|
|
||||||
|
|
||||||
BinaryMessageDecoder decoder = new BinaryMessageDecoder(testMessage.getFullMessage());
|
BinaryMessageEncoder encoder = new BinaryMessageEncoder(
|
||||||
|
xmlMessage.getType(),
|
||||||
|
time,
|
||||||
|
1,
|
||||||
|
(short)encodedMessage.length,
|
||||||
|
encodedMessage );
|
||||||
|
|
||||||
|
BinaryMessageDecoder decoder = new BinaryMessageDecoder(encoder.getFullMessage());
|
||||||
|
|
||||||
|
|
||||||
AC35Data message = null;
|
AC35Data message = null;
|
||||||
try {
|
try {
|
||||||
@@ -56,7 +74,7 @@ public class BinaryMessageDecoderTest {
|
|||||||
if (!(message instanceof XMLMessage)){
|
if (!(message instanceof XMLMessage)){
|
||||||
Assert.assertFalse(true);
|
Assert.assertFalse(true);
|
||||||
}
|
}
|
||||||
XMLMessage xmlMessage = (XMLMessage) message;
|
XMLMessage xmlMessageDecoded = (XMLMessage) message;
|
||||||
|
|
||||||
|
|
||||||
//message length
|
//message length
|
||||||
@@ -66,29 +84,17 @@ public class BinaryMessageDecoderTest {
|
|||||||
//source ID
|
//source ID
|
||||||
Assert.assertEquals((short) 1, decoder.getHeaderSourceID());
|
Assert.assertEquals((short) 1, decoder.getHeaderSourceID());
|
||||||
//message type
|
//message type
|
||||||
Assert.assertEquals(26, decoder.getHeaderMessageType());
|
Assert.assertEquals(MessageType.XMLMESSAGE.getValue(), decoder.getHeaderMessageType());
|
||||||
|
|
||||||
XMLMessageDecoder decoderXML = new XMLMessageDecoder(decoder.getMessageBody());
|
|
||||||
decoderXML.decode();
|
|
||||||
|
|
||||||
//tests from seng302.Networking.MessageDecoders.XMLMessageDecoderTest to make sure the file is still good
|
XMLMessageDecoderTest.compareXMLMessages(xmlMessage, xmlMessageDecoded);
|
||||||
Assert.assertEquals((byte)1, decoderXML.getMessageVersionNumber());
|
|
||||||
Assert.assertEquals((short)1, decoderXML.getAckNumber());
|
|
||||||
Assert.assertEquals(time, decoderXML.getTimeStamp());
|
|
||||||
Assert.assertEquals(XMLMessageType.REGATTA, decoderXML.getXmlMsgSubType());
|
|
||||||
Assert.assertEquals((short)1, decoderXML.getSequenceNumber());
|
|
||||||
Assert.assertEquals((short)xmlString.length(), decoderXML.getXmlMsgLength());
|
|
||||||
|
|
||||||
// Reader reader = decoderXML.getXmlMessageInputStream().getCharacterStream();
|
|
||||||
// int c;
|
|
||||||
// String contents = "";
|
|
||||||
// while((c = reader.read()) != -1) {
|
|
||||||
// contents += (char)c;
|
|
||||||
// }
|
|
||||||
// Assert.assertEquals(xmlString.toString(), contents);
|
|
||||||
|
|
||||||
} catch (XMLReaderException | TransformerException e){
|
} catch (XMLReaderException | TransformerException e){
|
||||||
fail("couldn't read file" + e.getMessage());
|
fail("couldn't read file" + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO add some tests for more messages types.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public class BoatLocationDecoderTest {
|
|||||||
* Creates a BoatLocation message, encodes it, decodes it, and checks that the result matches the starting message.
|
* Creates a BoatLocation message, encodes it, decodes it, and checks that the result matches the starting message.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void getByteArrayTest() throws Exception {
|
public void boatLocationEncodeDecodeTest() throws Exception {
|
||||||
|
|
||||||
//Create message.
|
//Create message.
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.MessageEncoders.RaceVisionByteEncoder;
|
import network.MessageEncoders.RaceVisionByteEncoder;
|
||||||
import network.Messages.Enums.XMLMessageType;
|
import network.Messages.Enums.XMLMessageType;
|
||||||
import network.Messages.XMLMessage;
|
import network.Messages.XMLMessage;
|
||||||
@@ -14,13 +15,21 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by hba56 on 20/04/17.
|
* Test for the XMLMessage encoder and decoder
|
||||||
*/
|
*/
|
||||||
public class XMLMessageDecoderTest {
|
public class XMLMessageDecoderTest {
|
||||||
@Test
|
|
||||||
public void getByteArrayTest(){
|
|
||||||
try{
|
/**
|
||||||
String xmlString = XMLReader.readXMLFileToString("network/raceXML/Regatta.xml", StandardCharsets.UTF_8);
|
* Creates an XML message of the given type, using the specified filePath, encodes it, decodes it, and checks that the result matches the starting message.
|
||||||
|
* @param filePath The file path for xml file.
|
||||||
|
* @param type The type of xml file.
|
||||||
|
* @throws InvalidMessageException Thrown if message cannot be encoded.
|
||||||
|
*/
|
||||||
|
private void xmlMessageTest(String filePath, XMLMessageType type) throws InvalidMessageException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
String xmlString = XMLReader.readXMLFileToString(filePath, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
|
|
||||||
@@ -28,27 +37,67 @@ public class XMLMessageDecoderTest {
|
|||||||
(byte)1,
|
(byte)1,
|
||||||
1,
|
1,
|
||||||
time,
|
time,
|
||||||
XMLMessageType.REGATTA,
|
type,
|
||||||
(short)1,
|
(short)1,
|
||||||
xmlString );
|
xmlString );
|
||||||
|
|
||||||
byte[] encodedXML = RaceVisionByteEncoder.xmlMessage(message);
|
byte[] encodedXML = RaceVisionByteEncoder.encode(message);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
XMLMessageDecoder decoderXML = new XMLMessageDecoder(encodedXML);
|
XMLMessageDecoder decoderXML = new XMLMessageDecoder(encodedXML);
|
||||||
decoderXML.decode();
|
XMLMessage decodedMessage = decoderXML.getMessage();
|
||||||
|
|
||||||
|
|
||||||
Assert.assertEquals((byte)1, decoderXML.getMessageVersionNumber());
|
compareXMLMessages(message, decodedMessage);
|
||||||
Assert.assertEquals((short)1, decoderXML.getAckNumber());
|
|
||||||
Assert.assertEquals(time, decoderXML.getTimeStamp());
|
|
||||||
Assert.assertEquals(XMLMessageType.REGATTA, decoderXML.getXmlMsgSubType());
|
|
||||||
Assert.assertEquals((short)1, decoderXML.getSequenceNumber());
|
|
||||||
Assert.assertEquals((short)xmlString.length(), decoderXML.getXmlMsgLength());
|
|
||||||
|
|
||||||
} catch (XMLReaderException | TransformerException e){
|
} catch (XMLReaderException | TransformerException e){
|
||||||
fail("couldn't read file" + e.getMessage());
|
fail("couldn't read file" + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two XML messages to check that they are the same.
|
||||||
|
* @param originalMessage The first message to test.
|
||||||
|
* @param decodedMessage The second message to test.
|
||||||
|
*/
|
||||||
|
public static void compareXMLMessages(XMLMessage originalMessage, XMLMessage decodedMessage) {
|
||||||
|
|
||||||
|
Assert.assertEquals(originalMessage.getVersionNumber(), decodedMessage.getVersionNumber());
|
||||||
|
Assert.assertEquals(originalMessage.getAckNumber(), decodedMessage.getAckNumber());
|
||||||
|
Assert.assertEquals(originalMessage.getTimeStamp(), decodedMessage.getTimeStamp());
|
||||||
|
Assert.assertEquals(originalMessage.getXmlMsgSubType(), decodedMessage.getXmlMsgSubType());
|
||||||
|
Assert.assertEquals(originalMessage.getSequenceNumber(), decodedMessage.getSequenceNumber());
|
||||||
|
Assert.assertEquals(originalMessage.getXmlMsgLength(), decodedMessage.getXmlMsgLength());
|
||||||
|
Assert.assertEquals(originalMessage.getXmlMessage(), decodedMessage.getXmlMessage());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if a regatta.xml message can be encoded and decoded.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void regattaXMLMessageTest() throws Exception {
|
||||||
|
xmlMessageTest("network/raceXML/Regatta.xml", XMLMessageType.REGATTA);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if a race.xml message can be encoded and decoded.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void raceXMLMessageTest() throws Exception {
|
||||||
|
xmlMessageTest("network/raceXML/Race.xml", XMLMessageType.RACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if a boat.xml message can be encoded and decoded.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void boatXMLMessageTest() throws Exception {
|
||||||
|
xmlMessageTest("network/raceXML/Boats.xml", XMLMessageType.BOAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
package network;
|
|
||||||
|
|
||||||
import network.MessageEncoders.RaceVisionByteEncoder;
|
|
||||||
import network.Messages.Enums.XMLMessageType;
|
|
||||||
import network.Messages.XMLMessage;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
import shared.dataInput.XMLReader;
|
|
||||||
import shared.exceptions.XMLReaderException;
|
|
||||||
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by hba56 on 19/04/17.
|
|
||||||
*/
|
|
||||||
public class XMLMessageEncoderTest {
|
|
||||||
@Test
|
|
||||||
public void getByteArrayTest() {
|
|
||||||
try {
|
|
||||||
|
|
||||||
String xmlString = XMLReader.readXMLFileToString("network/raceXML/Regatta.xml", StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
|
|
||||||
XMLMessage message = new XMLMessage(
|
|
||||||
(byte)1,
|
|
||||||
1,
|
|
||||||
System.currentTimeMillis(),
|
|
||||||
XMLMessageType.REGATTA,
|
|
||||||
(short)1,
|
|
||||||
xmlString );
|
|
||||||
|
|
||||||
int xmlMessageLength = xmlString.getBytes().length;
|
|
||||||
|
|
||||||
byte[] encodedXML = RaceVisionByteEncoder.xmlMessage(message);
|
|
||||||
|
|
||||||
//1 + 2 + 6 + 1 + 2 + 2 + xml.byteLength
|
|
||||||
Assert.assertEquals(14 + xmlMessageLength, encodedXML.length);
|
|
||||||
|
|
||||||
} catch (XMLReaderException | TransformerException e){
|
|
||||||
fail("couldn't read file" + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<BoatConfig>
|
||||||
|
<Modified>2017-04-19T15:49:40+1200</Modified>
|
||||||
|
<Version>1</Version>
|
||||||
|
<Settings>
|
||||||
|
<RaceBoatType Type="AC45" />
|
||||||
|
<BoatDimension BoatLength="14.019" HullLength="13.449" />
|
||||||
|
<ZoneSize MarkZoneSize="40.347" CourseZoneSize="40.347" />
|
||||||
|
<ZoneLimits Limit1="200" Limit2="100" Limit3="40.347" Limit4="0" Limit5="-100" />
|
||||||
|
</Settings>
|
||||||
|
<BoatShapes>
|
||||||
|
<BoatShape ShapeID="0">
|
||||||
|
<Vertices>
|
||||||
|
<Vtx Seq="1" Y="0" X="-2.659" />
|
||||||
|
<Vtx Seq="2" Y="18.359" X="-2.659" />
|
||||||
|
<Vtx Seq="3" Y="18.359" X="2.659" />
|
||||||
|
<Vtx Seq="4" Y="0" X="2.659" />
|
||||||
|
</Vertices>
|
||||||
|
</BoatShape>
|
||||||
|
<BoatShape ShapeID="1">
|
||||||
|
<Vertices>
|
||||||
|
<Vtx Seq="1" Y="0" X="-1.278" />
|
||||||
|
<Vtx Seq="2" Y="8.876" X="-1.278" />
|
||||||
|
<Vtx Seq="3" Y="8.876" X="1.278" />
|
||||||
|
<Vtx Seq="4" Y="0" X="1.278" />
|
||||||
|
</Vertices>
|
||||||
|
</BoatShape>
|
||||||
|
<BoatShape ShapeID="2">
|
||||||
|
<Vertices>
|
||||||
|
<Vtx Seq="1" Y="0" X="-1.1" />
|
||||||
|
<Vtx Seq="2" Y="8.3" X="-1.1" />
|
||||||
|
<Vtx Seq="3" Y="8.3" X="1.1" />
|
||||||
|
<Vtx Seq="4" Y="0" X="1.1" />
|
||||||
|
</Vertices>
|
||||||
|
</BoatShape>
|
||||||
|
<BoatShape ShapeID="3">
|
||||||
|
<Vertices>
|
||||||
|
<Vtx Seq="1" Y="0" X="-0.75" />
|
||||||
|
<Vtx Seq="2" Y="3" X="-0.75" />
|
||||||
|
<Vtx Seq="3" Y="3" X="0.75" />
|
||||||
|
<Vtx Seq="4" Y="0" X="0.75" />
|
||||||
|
</Vertices>
|
||||||
|
</BoatShape>
|
||||||
|
<BoatShape ShapeID="4">
|
||||||
|
<Vertices>
|
||||||
|
<Vtx Seq="1" Y="0" X="-3.46" />
|
||||||
|
<Vtx Seq="2" Y="13.449" X="-3.46" />
|
||||||
|
<Vtx Seq="3" Y="14.019" X="0" />
|
||||||
|
<Vtx Seq="4" Y="13.449" X="3.46" />
|
||||||
|
<Vtx Seq="5" Y="0" X="3.46" />
|
||||||
|
</Vertices>
|
||||||
|
<Catamaran>
|
||||||
|
<Vtx Seq="1" Y="1.769" X="-2.752" />
|
||||||
|
<Vtx Seq="2" Y="0" X="-2.813" />
|
||||||
|
<Vtx Seq="3" Y="0" X="-3.34" />
|
||||||
|
<Vtx Seq="4" Y="5.351" X="-3.46" />
|
||||||
|
<Vtx Seq="5" Y="10.544" X="-3.387" />
|
||||||
|
<Vtx Seq="6" Y="13.449" X="-3.075" />
|
||||||
|
<Vtx Seq="7" Y="10.851" X="-2.793" />
|
||||||
|
<Vtx Seq="8" Y="6.669" X="-2.699" />
|
||||||
|
<Vtx Seq="9" Y="6.669" X="2.699" />
|
||||||
|
<Vtx Seq="10" Y="10.851" X="2.793" />
|
||||||
|
<Vtx Seq="11" Y="13.449" X="3.075" />
|
||||||
|
<Vtx Seq="12" Y="10.544" X="3.387" />
|
||||||
|
<Vtx Seq="13" Y="5.351" X="3.46" />
|
||||||
|
<Vtx Seq="14" Y="0" X="3.34" />
|
||||||
|
<Vtx Seq="15" Y="0" X="2.813" />
|
||||||
|
<Vtx Seq="16" Y="1.769" X="2.752" />
|
||||||
|
</Catamaran>
|
||||||
|
<Bowsprit>
|
||||||
|
<Vtx Seq="1" Y="6.669" X="-0.2" />
|
||||||
|
<Vtx Seq="2" Y="11.377" X="-0.2" />
|
||||||
|
<Vtx Seq="3" Y="14.019" X="0" />
|
||||||
|
<Vtx Seq="4" Y="11.377" X="0.2" />
|
||||||
|
<Vtx Seq="5" Y="6.669" X="0.2" />
|
||||||
|
</Bowsprit>
|
||||||
|
<Trampoline>
|
||||||
|
<Vtx Seq="1" Y="2" X="-2.699" />
|
||||||
|
<Vtx Seq="2" Y="6.438" X="-2.699" />
|
||||||
|
<Vtx Seq="3" Y="6.438" X="2.699" />
|
||||||
|
<Vtx Seq="4" Y="2" X="2.699" />
|
||||||
|
</Trampoline>
|
||||||
|
</BoatShape>
|
||||||
|
<BoatShape ShapeID="5" />
|
||||||
|
</BoatShapes>
|
||||||
|
<Boats>>
|
||||||
|
<Boat Type="Yacht" SourceID="101" ShapeID="4" HullNum="AC4501" ShortName="USA"
|
||||||
|
BoatName="ORACLE TEAM USA" Country="USA">
|
||||||
|
<GPSposition Z="1.738" Y="0.625" X="0.001" />
|
||||||
|
<MastTop Z="21.496" Y="4.233" X="0.000" />
|
||||||
|
</Boat>
|
||||||
|
<Boat Type="Yacht" SourceID="102" ShapeID="4" HullNum="AC4502" ShortName="GBR"
|
||||||
|
BoatName="Land Rover BAR" Country="United Kingdom">
|
||||||
|
<GPSposition Z="1.738" Y="0.625" X="0.001" />
|
||||||
|
<MastTop Z="21.496" Y="4.233" X="0.000" />
|
||||||
|
</Boat>
|
||||||
|
<Boat Type="Yacht" SourceID="103" ShapeID="4" HullNum="AC4503" ShortName="JPN"
|
||||||
|
BoatName="SoftBank Team Japan" Country="Japan">
|
||||||
|
<GPSposition Z="1.738" Y="0.625" X="0.001" />
|
||||||
|
<MastTop Z="21.496" Y="4.233" X="0.000" />
|
||||||
|
</Boat>
|
||||||
|
<Boat Type="Yacht" SourceID="104" ShapeID="4" HullNum="AC4504" ShortName="FRA"
|
||||||
|
BoatName="Groupama Team France" Country="France">
|
||||||
|
<GPSposition Z="1.738" Y="0.625" X="0.001" />
|
||||||
|
<MastTop Z="21.496" Y="4.233" X="0.000" />
|
||||||
|
</Boat>
|
||||||
|
<Boat Type="Yacht" SourceID="105" ShapeID="4" HullNum="AC4505" ShortName="SWE"
|
||||||
|
BoatName="Artemis Racing" Country="Sweden">
|
||||||
|
<GPSposition Z="1.738" Y="0.625" X="0.001" />
|
||||||
|
<MastTop Z="21.496" Y="4.233" X="0.000" />
|
||||||
|
</Boat>
|
||||||
|
<Boat Type="Yacht" SourceID="106" ShapeID="4" HullNum="AC4506" ShortName="NZL"
|
||||||
|
BoatName="Emirates Team New Zealand" Country="New Zealand">
|
||||||
|
<GPSposition Z="1.738" Y="0.625" X="0.001" />
|
||||||
|
<MastTop Z="21.496" Y="4.233" X="0.000" />
|
||||||
|
</Boat>
|
||||||
|
</Boats>
|
||||||
|
</BoatConfig>
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Race>
|
||||||
|
<RaceID>17041901</RaceID>
|
||||||
|
<RaceType>Fleet</RaceType>
|
||||||
|
<CreationTimeDate>2017-04-19T15:30:00+1200</CreationTimeDate >
|
||||||
|
<RaceStartTime Time="2019-06-01T13:30:00-0400" Postpone="false" />
|
||||||
|
<Participants>
|
||||||
|
<Yacht SourceID="001" Entry="Port" />
|
||||||
|
<Yacht SourceID="002" Entry="Port" />
|
||||||
|
<Yacht SourceID="003" Entry="Port" />
|
||||||
|
<Yacht SourceID="004" Entry="Port" />
|
||||||
|
<Yacht SourceID="005" Entry="Port" />
|
||||||
|
<Yacht SourceID="006" Entry="Port" />
|
||||||
|
</Participants>
|
||||||
|
<Course>
|
||||||
|
<CompoundMark CompoundMarkID="1" Name="StartLine">
|
||||||
|
<Mark SeqID="1" Name="PRO" TargetLat="32.296577" TargetLng="-64.854304" SourceID="101" />
|
||||||
|
<Mark SeqID="2" Name="PIN" TargetLat="32.293771" TargetLng="-64.855242" SourceID="102" />
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="2" Name="M1">
|
||||||
|
<Mark Name="M1" TargetLat="32.293039" TargetLng="-64.843983" SourceID="103" />
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="3" Name="WindwardGate">
|
||||||
|
<Mark SeqID="1" Name="G1" TargetLat="32.284680" TargetLng="-64.850045" SourceID="104" />
|
||||||
|
<Mark SeqID="2" Name="G2" TargetLat="32.280164" TargetLng="-64.847591" SourceID="105" />
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="4" Name="LeewardGate">
|
||||||
|
<Mark SeqID="1" Name="G1" TargetLat="32.309693" TargetLng="-64.835249" SourceID="106" />
|
||||||
|
<Mark SeqID="2" Name="G2" TargetLat="32.308046" TargetLng="-64.831785" SourceID="107" />
|
||||||
|
</CompoundMark>
|
||||||
|
<CompoundMark CompoundMarkID="5" Name="FinishLine">
|
||||||
|
<Mark SeqID="1" Name="PRO" TargetLat="32.317379" TargetLng="-64.839291" SourceID="108" />
|
||||||
|
<Mark SeqID="2" Name="PIN" TargetLat="32.317257" TargetLng="-64.836260" SourceID="109" />
|
||||||
|
</CompoundMark>
|
||||||
|
</Course>
|
||||||
|
<CompoundMarkSequence>
|
||||||
|
<Corner SeqID="1" CompoundMarkID="1" Rounding="SP" ZoneSize="3" />
|
||||||
|
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3" />
|
||||||
|
<Corner SeqID="3" CompoundMarkID="3" Rounding="Port" ZoneSize="3" />
|
||||||
|
<Corner SeqID="4" CompoundMarkID="4" Rounding="Port" ZoneSize="3" />
|
||||||
|
<Corner SeqID="3" CompoundMarkID="3" Rounding="Port" ZoneSize="3" />
|
||||||
|
<Corner SeqID="5" CompoundMarkID="5" Rounding="SP" ZoneSize="3"/>
|
||||||
|
</CompoundMarkSequence>
|
||||||
|
<CourseLimit>
|
||||||
|
<Limit SeqID="1" Lat="32.313922" Lon="-64.837168"/>
|
||||||
|
<Limit SeqID="2" Lat="32.317379" Lon="-64.839291"/>
|
||||||
|
<Limit SeqID="3" Lat="32.317911" Lon="-64.836996"/>
|
||||||
|
<Limit SeqID="4" Lat="32.317257" Lon="-64.836260"/>
|
||||||
|
<Limit SeqID="5" Lat="32.304273" Lon="-64.822834"/>
|
||||||
|
|
||||||
|
<Limit SeqID="6" Lat="32.279097" Lon="-64.841545"/>
|
||||||
|
<Limit SeqID="7" Lat="32.279604" Lon="-64.849871"/>
|
||||||
|
<Limit SeqID="8" Lat="32.289545" Lon="-64.854162"/>
|
||||||
|
<Limit SeqID="9" Lat="32.290198" Lon="-64.858711"/>
|
||||||
|
<Limit SeqID="10" Lat="32.297164" Lon="-64.856394"/>
|
||||||
|
<Limit SeqID="11" Lat="32.296148" Lon="-64.849184"/>
|
||||||
|
</CourseLimit>
|
||||||
|
</Race>
|
||||||
Reference in New Issue
Block a user