The message encoders and decoders now catch exceptions, and throw InvalidMessageException.
Removed the big switch statement from BinaryMessageDecoder - it now uses the decoder factory instead. issue #35 #36 #story[1095]
This commit is contained in:
@@ -17,42 +17,71 @@ import java.util.zip.CRC32;
|
|||||||
*/
|
*/
|
||||||
public class BinaryMessageDecoder {
|
public class BinaryMessageDecoder {
|
||||||
|
|
||||||
///Length of the header.
|
/**
|
||||||
|
* Length of the header.
|
||||||
|
*/
|
||||||
private static final int headerLength = 15;
|
private static final int headerLength = 15;
|
||||||
///Length of the CRC.
|
/**
|
||||||
private static final int CRCLength = 4;//TODO these should probably be static defined somewhere else to be shared.
|
* Length of the CRC.
|
||||||
|
*/
|
||||||
|
private static final int CRCLength = 4;
|
||||||
|
|
||||||
///The value the first sync byte should have.
|
/**
|
||||||
|
* The value the first sync byte should have.
|
||||||
|
*/
|
||||||
private static final byte syncByte1 = (byte) 0x47;
|
private static final byte syncByte1 = (byte) 0x47;
|
||||||
//The value the second sync byte should have.
|
/**
|
||||||
|
* The value the second sync byte should have.
|
||||||
|
*/
|
||||||
private static final byte syncByte2 = (byte) 0x83;
|
private static final byte syncByte2 = (byte) 0x83;
|
||||||
|
|
||||||
///The full message.
|
/**
|
||||||
|
* The full message.
|
||||||
|
*/
|
||||||
private byte[] fullMessage;
|
private byte[] fullMessage;
|
||||||
///The messageHeader.
|
/**
|
||||||
|
* The messageHeader.
|
||||||
|
*/
|
||||||
private byte[] messageHeader;
|
private byte[] messageHeader;
|
||||||
///The messageBody.
|
/**
|
||||||
|
* The messageBody.
|
||||||
|
*/
|
||||||
private byte[] messageBody;
|
private byte[] messageBody;
|
||||||
|
|
||||||
///The sync bytes from the header..
|
/**
|
||||||
|
* The sync bytes from the header.
|
||||||
|
*/
|
||||||
private byte headerSync1;
|
private byte headerSync1;
|
||||||
private byte headerSync2;
|
private byte headerSync2;
|
||||||
|
|
||||||
///The message type from the header.
|
/**
|
||||||
|
* The message type from the header.
|
||||||
|
*/
|
||||||
private byte headerMessageType;
|
private byte headerMessageType;
|
||||||
|
|
||||||
///The timestamp from the header.
|
/**
|
||||||
|
* The timestamp from the header.
|
||||||
|
*/
|
||||||
private long headerTimeStamp;
|
private long headerTimeStamp;
|
||||||
|
|
||||||
///The source ID from the header.
|
/**
|
||||||
|
* The source ID from the header.
|
||||||
|
*/
|
||||||
private int headerSourceID;
|
private int headerSourceID;
|
||||||
|
|
||||||
///The message body length from the header.
|
/**
|
||||||
|
* The message body length from the header.
|
||||||
|
*/
|
||||||
private int messageBodyLength;
|
private int messageBodyLength;
|
||||||
|
|
||||||
///CRC value read from message header.
|
/**
|
||||||
|
* CRC value read from message header.
|
||||||
|
*/
|
||||||
private long messageCRCValue;
|
private long messageCRCValue;
|
||||||
///Calculated CRC value from message.
|
|
||||||
|
/**
|
||||||
|
* Calculated CRC value from message.
|
||||||
|
*/
|
||||||
private long calculatedCRCValue;
|
private long calculatedCRCValue;
|
||||||
|
|
||||||
|
|
||||||
@@ -114,104 +143,34 @@ public class BinaryMessageDecoder {
|
|||||||
//Check the message body length.
|
//Check the message body length.
|
||||||
throw new InvalidMessageException("MessageBody length in header does not equal the messageBody length. MessageBody length in header is: " + messageBodyLength + ", should be: " + messageBody.length);
|
throw new InvalidMessageException("MessageBody length in header does not equal the messageBody length. MessageBody length in header is: " + messageBodyLength + ", should be: " + messageBody.length);
|
||||||
|
|
||||||
}else if (headerSync1 != syncByte1) {
|
} else if (headerSync1 != syncByte1) {
|
||||||
//Check the first sync byte.
|
//Check the first sync byte.
|
||||||
throw new InvalidMessageException("Sync byte 1 is wrong. Sync byte is: " + headerSync1 + ", should be: " + syncByte1);
|
throw new InvalidMessageException("Sync byte 1 is wrong. Sync byte is: " + headerSync1 + ", should be: " + syncByte1);
|
||||||
|
|
||||||
}else if (headerSync2 != syncByte2) {
|
} else if (headerSync2 != syncByte2) {
|
||||||
//Check the second sync byte.
|
//Check the second sync byte.
|
||||||
throw new InvalidMessageException("Sync byte 2 is wrong. Sync byte is: " + headerSync2 + ", should be: " + syncByte2);
|
throw new InvalidMessageException("Sync byte 2 is wrong. Sync byte is: " + headerSync2 + ", should be: " + syncByte2);
|
||||||
|
|
||||||
}else if (calculatedCRCValue != messageCRCValue) {
|
} else if (calculatedCRCValue != messageCRCValue) {
|
||||||
//Check the CRC value.
|
//Check the CRC value.
|
||||||
throw new InvalidMessageException("CRC value is wrong. The calculated value is: " + calculatedCRCValue + ", should be: " + messageCRCValue);
|
throw new InvalidMessageException("CRC value is wrong. The calculated value is: " + calculatedCRCValue + ", should be: " + messageCRCValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Now we create the message object based on what is actually in the message body.
|
//Now we create the message object based on what is actually in the message body.
|
||||||
MessageType mType = MessageType.fromByte(headerMessageType);
|
MessageType messageType = MessageType.fromByte(headerMessageType);
|
||||||
|
|
||||||
/*MessageDecoder decoder = null;
|
MessageDecoder decoder = null;
|
||||||
try {
|
try {
|
||||||
decoder = DecoderFactory.create(mType);
|
decoder = DecoderFactory.create(messageType);
|
||||||
|
|
||||||
} catch (InvalidMessageTypeException e) {
|
} catch (InvalidMessageTypeException e) {
|
||||||
throw new InvalidMessageException("Could not create decoder for MessageType: " + mType, e);
|
throw new InvalidMessageException("Could not create decoder for MessageType: " + messageType, e);
|
||||||
}
|
|
||||||
|
|
||||||
return decoder.decode(messageBody);*/
|
|
||||||
|
|
||||||
|
|
||||||
switch(mType) {
|
|
||||||
case HEARTBEAT:
|
|
||||||
//System.out.println("Decoding HeartBeat Message!");
|
|
||||||
HeartBeatDecoder heartBeatDecoder = new HeartBeatDecoder();
|
|
||||||
return heartBeatDecoder.decode(messageBody);
|
|
||||||
|
|
||||||
case RACESTATUS:
|
|
||||||
//System.out.println("Race Status Message");
|
|
||||||
RaceStatusDecoder rsdecoder = new RaceStatusDecoder();
|
|
||||||
return rsdecoder.decode(messageBody);
|
|
||||||
|
|
||||||
case DISPLAYTEXTMESSAGE:
|
|
||||||
//System.out.println("Display Text Message");
|
|
||||||
//No decoder for this.
|
|
||||||
//throw new InvalidMessageException("Cannot decode DISPLAYTEXTMESSAGE - no decoder.");
|
|
||||||
|
|
||||||
case XMLMESSAGE:
|
|
||||||
//System.out.println("XML Message!");
|
|
||||||
XMLMessageDecoder xmdecoder = new XMLMessageDecoder();
|
|
||||||
return xmdecoder.decode(messageBody);
|
|
||||||
|
|
||||||
case RACESTARTSTATUS:
|
|
||||||
//System.out.println("Race Start Status Message");
|
|
||||||
RaceStartStatusDecoder rssDecoder = new RaceStartStatusDecoder();
|
|
||||||
return rssDecoder.decode(messageBody);
|
|
||||||
|
|
||||||
case YACHTEVENTCODE:
|
|
||||||
//System.out.println("Yacht Action Code!");
|
|
||||||
//No decoder for this.
|
|
||||||
//throw new InvalidMessageException("Cannot decode YACHTEVENTCODE - no decoder.");
|
|
||||||
|
|
||||||
case YACHTACTIONCODE:
|
|
||||||
//System.out.println("Yacht Action Code!");
|
|
||||||
//No decoder for this.
|
|
||||||
//throw new InvalidMessageException("Cannot decode YACHTACTIONCODE - no decoder.");
|
|
||||||
|
|
||||||
case CHATTERTEXT:
|
|
||||||
//System.out.println("Chatter Text Message!");
|
|
||||||
//No decoder for this.
|
|
||||||
//throw new InvalidMessageException("Cannot decode CHATTERTEXT - no decoder.");
|
|
||||||
|
|
||||||
case BOATLOCATION:
|
|
||||||
//System.out.println("Boat Location Message!");
|
|
||||||
BoatLocationDecoder blDecoder = new BoatLocationDecoder();
|
|
||||||
return blDecoder.decode(messageBody);
|
|
||||||
|
|
||||||
case MARKROUNDING:
|
|
||||||
//System.out.println("Mark Rounding Message!");
|
|
||||||
MarkRoundingDecoder mrDecoder = new MarkRoundingDecoder();
|
|
||||||
return mrDecoder.decode(messageBody);
|
|
||||||
|
|
||||||
case COURSEWIND:
|
|
||||||
//System.out.println("Course Wind Message!");
|
|
||||||
CourseWindsDecoder cwDecoder = new CourseWindsDecoder();
|
|
||||||
return cwDecoder.decode(messageBody);
|
|
||||||
|
|
||||||
case AVGWIND:
|
|
||||||
//System.out.println("Average Wind Message!");
|
|
||||||
AverageWindDecoder awDecoder = new AverageWindDecoder();
|
|
||||||
return awDecoder.decode(messageBody);
|
|
||||||
|
|
||||||
case BOATACTION:
|
|
||||||
BoatActionDecoder baDecoder = new BoatActionDecoder();
|
|
||||||
return baDecoder.decode(messageBody);
|
|
||||||
|
|
||||||
default:
|
|
||||||
//System.out.println("Broken Message!");
|
|
||||||
//throw new InvalidMessageException("Broken message! Did not recognise message type: " + headerMessageType + ".");
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return decoder.decode(messageBody);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.AverageWind;
|
import network.Messages.AverageWind;
|
||||||
import network.Utils.ByteConverter;
|
import network.Utils.ByteConverter;
|
||||||
@@ -32,64 +33,67 @@ public class AverageWindDecoder implements MessageDecoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedMessage) {
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
byte messageVersionNumber = encodedMessage[0];
|
byte messageVersionNumber = encodedMessage[0];
|
||||||
|
|
||||||
|
|
||||||
byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7);
|
byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7);
|
||||||
long time = ByteConverter.bytesToLong(byteTime);
|
long time = ByteConverter.bytesToLong(byteTime);
|
||||||
|
|
||||||
byte[] byteRawPeriod = Arrays.copyOfRange(encodedMessage, 7, 9);
|
byte[] byteRawPeriod = Arrays.copyOfRange(encodedMessage, 7, 9);
|
||||||
int intRawPeriod = ByteConverter.bytesToInt(byteRawPeriod);
|
int intRawPeriod = ByteConverter.bytesToInt(byteRawPeriod);
|
||||||
long rawPeriod = unpackAverageWindPeriod(intRawPeriod);
|
long rawPeriod = unpackAverageWindPeriod(intRawPeriod);
|
||||||
|
|
||||||
byte[] byteRawSpeed = Arrays.copyOfRange(encodedMessage, 9, 11);
|
byte[] byteRawSpeed = Arrays.copyOfRange(encodedMessage, 9, 11);
|
||||||
int intRawSpeed = ByteConverter.bytesToInt(byteRawSpeed);
|
int intRawSpeed = ByteConverter.bytesToInt(byteRawSpeed);
|
||||||
double rawSpeedKnots = unpackMMperSecToKnots(intRawSpeed);
|
double rawSpeedKnots = unpackMMperSecToKnots(intRawSpeed);
|
||||||
|
|
||||||
byte[] bytePeriod2 = Arrays.copyOfRange(encodedMessage, 11, 13);
|
byte[] bytePeriod2 = Arrays.copyOfRange(encodedMessage, 11, 13);
|
||||||
int intPeriod2 = ByteConverter.bytesToInt(bytePeriod2);
|
int intPeriod2 = ByteConverter.bytesToInt(bytePeriod2);
|
||||||
long period2 = unpackAverageWindPeriod(intPeriod2);
|
long period2 = unpackAverageWindPeriod(intPeriod2);
|
||||||
|
|
||||||
byte[] byteSpeed2 = Arrays.copyOfRange(encodedMessage, 13, 15);
|
byte[] byteSpeed2 = Arrays.copyOfRange(encodedMessage, 13, 15);
|
||||||
int intSpeed2 = ByteConverter.bytesToInt(byteSpeed2);
|
int intSpeed2 = ByteConverter.bytesToInt(byteSpeed2);
|
||||||
double speed2Knots = unpackMMperSecToKnots(intSpeed2);
|
double speed2Knots = unpackMMperSecToKnots(intSpeed2);
|
||||||
|
|
||||||
byte[] bytePeriod3 = Arrays.copyOfRange(encodedMessage, 15, 17);
|
byte[] bytePeriod3 = Arrays.copyOfRange(encodedMessage, 15, 17);
|
||||||
int intPeriod3 = ByteConverter.bytesToInt(bytePeriod3);
|
int intPeriod3 = ByteConverter.bytesToInt(bytePeriod3);
|
||||||
long period3 = unpackAverageWindPeriod(intPeriod3);
|
long period3 = unpackAverageWindPeriod(intPeriod3);
|
||||||
|
|
||||||
byte[] byteSpeed3 = Arrays.copyOfRange(encodedMessage, 17, 19);
|
byte[] byteSpeed3 = Arrays.copyOfRange(encodedMessage, 17, 19);
|
||||||
int intSpeed3 = ByteConverter.bytesToInt(byteSpeed3);
|
int intSpeed3 = ByteConverter.bytesToInt(byteSpeed3);
|
||||||
double speed3Knots = unpackMMperSecToKnots(intSpeed3);
|
double speed3Knots = unpackMMperSecToKnots(intSpeed3);
|
||||||
|
|
||||||
byte[] bytePeriod4 = Arrays.copyOfRange(encodedMessage, 19, 21);
|
byte[] bytePeriod4 = Arrays.copyOfRange(encodedMessage, 19, 21);
|
||||||
int intPeriod4 = ByteConverter.bytesToInt(bytePeriod4);
|
int intPeriod4 = ByteConverter.bytesToInt(bytePeriod4);
|
||||||
long period4 = unpackAverageWindPeriod(intPeriod4);
|
long period4 = unpackAverageWindPeriod(intPeriod4);
|
||||||
|
|
||||||
byte[] byteSpeed4 = Arrays.copyOfRange(encodedMessage, 21, 23);
|
byte[] byteSpeed4 = Arrays.copyOfRange(encodedMessage, 21, 23);
|
||||||
int intSpeed4 = ByteConverter.bytesToInt(byteSpeed4);
|
int intSpeed4 = ByteConverter.bytesToInt(byteSpeed4);
|
||||||
double speed4Knots = unpackMMperSecToKnots(intSpeed4);
|
double speed4Knots = unpackMMperSecToKnots(intSpeed4);
|
||||||
|
|
||||||
|
|
||||||
|
message = new AverageWind(
|
||||||
|
messageVersionNumber,
|
||||||
|
time,
|
||||||
|
rawPeriod,
|
||||||
|
rawSpeedKnots,
|
||||||
|
period2,
|
||||||
|
speed2Knots,
|
||||||
|
period3,
|
||||||
|
speed3Knots,
|
||||||
|
period4,
|
||||||
|
speed4Knots);
|
||||||
|
|
||||||
|
return message;
|
||||||
|
|
||||||
message = new AverageWind(
|
} catch (Exception e) {
|
||||||
messageVersionNumber,
|
throw new InvalidMessageException("Could not decode AverageWind message.", e);
|
||||||
time,
|
}
|
||||||
rawPeriod,
|
|
||||||
rawSpeedKnots,
|
|
||||||
period2,
|
|
||||||
speed2Knots,
|
|
||||||
period3,
|
|
||||||
speed3Knots,
|
|
||||||
period4,
|
|
||||||
speed4Knots );
|
|
||||||
|
|
||||||
return message;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.BoatAction;
|
import network.Messages.BoatAction;
|
||||||
import network.Messages.Enums.BoatActionEnum;
|
import network.Messages.Enums.BoatActionEnum;
|
||||||
@@ -29,14 +30,19 @@ public class BoatActionDecoder implements MessageDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedMessage) {
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
BoatActionEnum boatActionEnum = BoatActionEnum.fromByte(encodedMessage[0]);
|
try {
|
||||||
|
BoatActionEnum boatActionEnum = BoatActionEnum.fromByte(encodedMessage[0]);
|
||||||
|
|
||||||
message = new BoatAction(boatActionEnum);
|
message = new BoatAction(boatActionEnum);
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode BoatAction message.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.BoatLocation;
|
import network.Messages.BoatLocation;
|
||||||
import network.Messages.Enums.BoatLocationDeviceEnum;
|
import network.Messages.Enums.BoatLocationDeviceEnum;
|
||||||
@@ -39,115 +40,121 @@ public class BoatLocationDecoder implements MessageDecoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedMessage) {
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
|
try {
|
||||||
byte messageVersionNumber = messageVersionNumberBytes[0];
|
|
||||||
|
|
||||||
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
|
byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
|
||||||
long time = bytesToLong(timeBytes);
|
byte messageVersionNumber = messageVersionNumberBytes[0];
|
||||||
|
|
||||||
byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11);
|
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
|
||||||
int sourceID = bytesToInt(sourceIDBytes);
|
long time = bytesToLong(timeBytes);
|
||||||
|
|
||||||
byte[] seqNumBytes = Arrays.copyOfRange(encodedMessage, 11, 15);
|
byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11);
|
||||||
int seqNum = bytesToInt(seqNumBytes);
|
int sourceID = bytesToInt(sourceIDBytes);
|
||||||
|
|
||||||
byte[] deviceTypeBytes = Arrays.copyOfRange(encodedMessage, 15, 16);
|
byte[] seqNumBytes = Arrays.copyOfRange(encodedMessage, 11, 15);
|
||||||
BoatLocationDeviceEnum deviceType = BoatLocationDeviceEnum.fromByte(deviceTypeBytes[0]);
|
int seqNum = bytesToInt(seqNumBytes);
|
||||||
|
|
||||||
byte[] latitudeBytes = Arrays.copyOfRange(encodedMessage, 16, 20);
|
byte[] deviceTypeBytes = Arrays.copyOfRange(encodedMessage, 15, 16);
|
||||||
int numLatitude = bytesToInt(latitudeBytes);
|
BoatLocationDeviceEnum deviceType = BoatLocationDeviceEnum.fromByte(deviceTypeBytes[0]);
|
||||||
double latitude = unpackGPS(numLatitude);
|
|
||||||
|
|
||||||
byte[] longitudeBytes = Arrays.copyOfRange(encodedMessage, 20, 24);
|
byte[] latitudeBytes = Arrays.copyOfRange(encodedMessage, 16, 20);
|
||||||
int numLongitude = bytesToInt(longitudeBytes);
|
int numLatitude = bytesToInt(latitudeBytes);
|
||||||
double longitude = unpackGPS(numLongitude);
|
double latitude = unpackGPS(numLatitude);
|
||||||
|
|
||||||
byte[] altitudeBytes = Arrays.copyOfRange(encodedMessage, 24, 28);
|
byte[] longitudeBytes = Arrays.copyOfRange(encodedMessage, 20, 24);
|
||||||
int numAltitude = bytesToInt(altitudeBytes);
|
int numLongitude = bytesToInt(longitudeBytes);
|
||||||
|
double longitude = unpackGPS(numLongitude);
|
||||||
|
|
||||||
byte[] headingBytes = Arrays.copyOfRange(encodedMessage, 28, 30);
|
byte[] altitudeBytes = Arrays.copyOfRange(encodedMessage, 24, 28);
|
||||||
int numHeading = bytesToInt(headingBytes);
|
int numAltitude = bytesToInt(altitudeBytes);
|
||||||
Bearing heading = Bearing.fromDegrees(unpackHeading(numHeading));
|
|
||||||
|
|
||||||
byte[] pitchBytes = Arrays.copyOfRange(encodedMessage, 30, 32);
|
byte[] headingBytes = Arrays.copyOfRange(encodedMessage, 28, 30);
|
||||||
short numPitch = bytesToShort(pitchBytes);
|
int numHeading = bytesToInt(headingBytes);
|
||||||
|
Bearing heading = Bearing.fromDegrees(unpackHeading(numHeading));
|
||||||
|
|
||||||
byte[] rollBytes = Arrays.copyOfRange(encodedMessage, 32, 34);
|
byte[] pitchBytes = Arrays.copyOfRange(encodedMessage, 30, 32);
|
||||||
short numRoll = bytesToShort(rollBytes);
|
short numPitch = bytesToShort(pitchBytes);
|
||||||
|
|
||||||
byte[] boatSpeedBytes = Arrays.copyOfRange(encodedMessage, 34, 36);
|
byte[] rollBytes = Arrays.copyOfRange(encodedMessage, 32, 34);
|
||||||
int numBoatSpeed = bytesToInt(boatSpeedBytes);
|
short numRoll = bytesToShort(rollBytes);
|
||||||
double boatSpeedKnots = unpackMMperSecToKnots(numBoatSpeed);
|
|
||||||
|
|
||||||
byte[] cogBytes = Arrays.copyOfRange(encodedMessage, 36, 38);
|
byte[] boatSpeedBytes = Arrays.copyOfRange(encodedMessage, 34, 36);
|
||||||
int numCog = bytesToInt(cogBytes);
|
int numBoatSpeed = bytesToInt(boatSpeedBytes);
|
||||||
Bearing cog = Bearing.fromDegrees(unpackHeading(numCog));
|
double boatSpeedKnots = unpackMMperSecToKnots(numBoatSpeed);
|
||||||
|
|
||||||
byte[] sogBytes = Arrays.copyOfRange(encodedMessage, 38, 40);
|
byte[] cogBytes = Arrays.copyOfRange(encodedMessage, 36, 38);
|
||||||
int numSog = bytesToInt(sogBytes);
|
int numCog = bytesToInt(cogBytes);
|
||||||
double sogKnots = unpackMMperSecToKnots(numSog);
|
Bearing cog = Bearing.fromDegrees(unpackHeading(numCog));
|
||||||
|
|
||||||
byte[] apparentWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 40, 42);
|
byte[] sogBytes = Arrays.copyOfRange(encodedMessage, 38, 40);
|
||||||
int numApparentWindSpeed = bytesToInt(apparentWindSpeedBytes);
|
int numSog = bytesToInt(sogBytes);
|
||||||
double apparentWindSpeedKnots = unpackMMperSecToKnots(numApparentWindSpeed);
|
double sogKnots = unpackMMperSecToKnots(numSog);
|
||||||
|
|
||||||
byte[] apparentWindAngleBytes = Arrays.copyOfRange(encodedMessage, 42, 44);
|
byte[] apparentWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 40, 42);
|
||||||
short numApparentWindAngle = bytesToShort(apparentWindAngleBytes);
|
int numApparentWindSpeed = bytesToInt(apparentWindSpeedBytes);
|
||||||
Azimuth apparentWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numApparentWindAngle));
|
double apparentWindSpeedKnots = unpackMMperSecToKnots(numApparentWindSpeed);
|
||||||
|
|
||||||
byte[] trueWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 44, 46);
|
byte[] apparentWindAngleBytes = Arrays.copyOfRange(encodedMessage, 42, 44);
|
||||||
int numTrueWindSpeed = bytesToInt(trueWindSpeedBytes);
|
short numApparentWindAngle = bytesToShort(apparentWindAngleBytes);
|
||||||
double trueWindSpeedKnots = unpackMMperSecToKnots(numTrueWindSpeed);
|
Azimuth apparentWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numApparentWindAngle));
|
||||||
|
|
||||||
byte[] trueWindDirectionBytes = Arrays.copyOfRange(encodedMessage, 46, 48);
|
byte[] trueWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 44, 46);
|
||||||
short numTrueWindDirection = bytesToShort(trueWindDirectionBytes);
|
int numTrueWindSpeed = bytesToInt(trueWindSpeedBytes);
|
||||||
Bearing trueWindDirection = Bearing.fromDegrees(unpackHeading(numTrueWindDirection));
|
double trueWindSpeedKnots = unpackMMperSecToKnots(numTrueWindSpeed);
|
||||||
|
|
||||||
byte[] trueWindAngleBytes = Arrays.copyOfRange(encodedMessage, 48, 50);
|
byte[] trueWindDirectionBytes = Arrays.copyOfRange(encodedMessage, 46, 48);
|
||||||
short numTrueWindAngle = bytesToShort(trueWindAngleBytes);
|
short numTrueWindDirection = bytesToShort(trueWindDirectionBytes);
|
||||||
Azimuth trueWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numTrueWindAngle));
|
Bearing trueWindDirection = Bearing.fromDegrees(unpackHeading(numTrueWindDirection));
|
||||||
|
|
||||||
byte[] currentDriftBytes = Arrays.copyOfRange(encodedMessage, 50, 52);
|
byte[] trueWindAngleBytes = Arrays.copyOfRange(encodedMessage, 48, 50);
|
||||||
int numCurrentDrift = bytesToInt(currentDriftBytes);
|
short numTrueWindAngle = bytesToShort(trueWindAngleBytes);
|
||||||
double currentDriftKnots = unpackMMperSecToKnots(numCurrentDrift);
|
Azimuth trueWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numTrueWindAngle));
|
||||||
|
|
||||||
byte[] currentSetBytes = Arrays.copyOfRange(encodedMessage, 52, 54);
|
byte[] currentDriftBytes = Arrays.copyOfRange(encodedMessage, 50, 52);
|
||||||
int numCurrentSet = bytesToShort(currentSetBytes);
|
int numCurrentDrift = bytesToInt(currentDriftBytes);
|
||||||
Bearing currentSet = Bearing.fromDegrees(unpackHeading(numCurrentSet));
|
double currentDriftKnots = unpackMMperSecToKnots(numCurrentDrift);
|
||||||
|
|
||||||
byte[] rudderAngleBytes = Arrays.copyOfRange(encodedMessage, 54, 56);
|
byte[] currentSetBytes = Arrays.copyOfRange(encodedMessage, 52, 54);
|
||||||
short numRudderAngle = bytesToShort(rudderAngleBytes);
|
int numCurrentSet = bytesToShort(currentSetBytes);
|
||||||
Azimuth rudderAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numRudderAngle));
|
Bearing currentSet = Bearing.fromDegrees(unpackHeading(numCurrentSet));
|
||||||
|
|
||||||
|
byte[] rudderAngleBytes = Arrays.copyOfRange(encodedMessage, 54, 56);
|
||||||
|
short numRudderAngle = bytesToShort(rudderAngleBytes);
|
||||||
|
Azimuth rudderAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numRudderAngle));
|
||||||
|
|
||||||
|
|
||||||
message = new BoatLocation(
|
message = new BoatLocation(
|
||||||
messageVersionNumber,
|
messageVersionNumber,
|
||||||
time,
|
time,
|
||||||
sourceID,
|
sourceID,
|
||||||
seqNum,
|
seqNum,
|
||||||
deviceType,
|
deviceType,
|
||||||
latitude,
|
latitude,
|
||||||
longitude,
|
longitude,
|
||||||
numAltitude,
|
numAltitude,
|
||||||
heading,
|
heading,
|
||||||
numPitch,
|
numPitch,
|
||||||
numRoll,
|
numRoll,
|
||||||
boatSpeedKnots,
|
boatSpeedKnots,
|
||||||
cog,
|
cog,
|
||||||
sogKnots,
|
sogKnots,
|
||||||
apparentWindSpeedKnots,
|
apparentWindSpeedKnots,
|
||||||
apparentWindAngle,
|
apparentWindAngle,
|
||||||
trueWindSpeedKnots,
|
trueWindSpeedKnots,
|
||||||
trueWindDirection,
|
trueWindDirection,
|
||||||
trueWindAngle,
|
trueWindAngle,
|
||||||
currentDriftKnots,
|
currentDriftKnots,
|
||||||
currentSet,
|
currentSet,
|
||||||
rudderAngle );
|
rudderAngle);
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode BoatLocation message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.BoatStatus;
|
import network.Messages.BoatStatus;
|
||||||
import network.Messages.Enums.BoatStatusEnum;
|
import network.Messages.Enums.BoatStatusEnum;
|
||||||
|
|
||||||
@@ -39,10 +40,12 @@ public class BoatStatusDecoder {
|
|||||||
* Decodes the contained message.
|
* Decodes the contained message.
|
||||||
* @param encodedMessage The message to decode.
|
* @param encodedMessage The message to decode.
|
||||||
* @return The decoded message.
|
* @return The decoded message.
|
||||||
|
* @throws InvalidMessageException Thrown if the encoded message is invalid in some way, or cannot be decoded.
|
||||||
*/
|
*/
|
||||||
public BoatStatus decode(byte[] encodedMessage) {
|
public BoatStatus decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 0, 4);
|
byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 0, 4);
|
||||||
int sourceID = bytesToInt(sourceIDBytes);
|
int sourceID = bytesToInt(sourceIDBytes);
|
||||||
@@ -76,6 +79,10 @@ public class BoatStatusDecoder {
|
|||||||
|
|
||||||
return message;
|
return message;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode BoatStatus message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.CourseWind;
|
import network.Messages.CourseWind;
|
||||||
import shared.model.Bearing;
|
import shared.model.Bearing;
|
||||||
|
|
||||||
@@ -38,49 +39,55 @@ public class CourseWindDecoder {
|
|||||||
* Decodes the contained message.
|
* Decodes the contained message.
|
||||||
* @param encodedMessage The message to decode.
|
* @param encodedMessage The message to decode.
|
||||||
* @return The decoded message.
|
* @return The decoded message.
|
||||||
|
* @throws InvalidMessageException Thrown if the encoded message is invalid in some way, or cannot be decoded.
|
||||||
*/
|
*/
|
||||||
public CourseWind decode(byte[] encodedMessage) {
|
public CourseWind decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
byte[] windId = Arrays.copyOfRange(encodedMessage, 0, 1);
|
try {
|
||||||
|
|
||||||
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
|
byte[] windId = Arrays.copyOfRange(encodedMessage, 0, 1);
|
||||||
long time = bytesToLong(timeBytes);
|
|
||||||
|
|
||||||
byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11);
|
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
|
||||||
int raceIDInt = bytesToInt(raceIDBytes);
|
long time = bytesToLong(timeBytes);
|
||||||
|
|
||||||
byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 11, 13);
|
byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11);
|
||||||
int windDirectionInt = bytesToInt(windDirectionBytes);
|
int raceIDInt = bytesToInt(raceIDBytes);
|
||||||
Bearing windDirection = Bearing.fromDegrees(unpackHeading(windDirectionInt));
|
|
||||||
|
|
||||||
byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 13, 15);
|
byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 11, 13);
|
||||||
int windSpeedInt = bytesToInt(windSpeedBytes);
|
int windDirectionInt = bytesToInt(windDirectionBytes);
|
||||||
double windSpeedKnots = unpackMMperSecToKnots(windSpeedInt);
|
Bearing windDirection = Bearing.fromDegrees(unpackHeading(windDirectionInt));
|
||||||
|
|
||||||
byte[] bestUpwindAngleBytes = Arrays.copyOfRange(encodedMessage, 15, 17);
|
byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 13, 15);
|
||||||
int bestUpwindAngleInt = bytesToInt(bestUpwindAngleBytes);
|
int windSpeedInt = bytesToInt(windSpeedBytes);
|
||||||
Bearing bestUpwindAngle = Bearing.fromDegrees(unpackHeading(bestUpwindAngleInt));
|
double windSpeedKnots = unpackMMperSecToKnots(windSpeedInt);
|
||||||
|
|
||||||
byte[] bestDownwindAngleBytes = Arrays.copyOfRange(encodedMessage, 17, 19);
|
byte[] bestUpwindAngleBytes = Arrays.copyOfRange(encodedMessage, 15, 17);
|
||||||
int bestDownwindAngleInt = bytesToInt(bestDownwindAngleBytes);
|
int bestUpwindAngleInt = bytesToInt(bestUpwindAngleBytes);
|
||||||
Bearing bestDownwindAngle = Bearing.fromDegrees(unpackHeading(bestDownwindAngleInt));
|
Bearing bestUpwindAngle = Bearing.fromDegrees(unpackHeading(bestUpwindAngleInt));
|
||||||
|
|
||||||
byte[] flags = Arrays.copyOfRange(encodedMessage, 19, 20);
|
byte[] bestDownwindAngleBytes = Arrays.copyOfRange(encodedMessage, 17, 19);
|
||||||
|
int bestDownwindAngleInt = bytesToInt(bestDownwindAngleBytes);
|
||||||
|
Bearing bestDownwindAngle = Bearing.fromDegrees(unpackHeading(bestDownwindAngleInt));
|
||||||
|
|
||||||
|
byte[] flags = Arrays.copyOfRange(encodedMessage, 19, 20);
|
||||||
|
|
||||||
|
|
||||||
|
message = new CourseWind(
|
||||||
|
windId[0],
|
||||||
|
time,
|
||||||
|
raceIDInt,
|
||||||
|
windDirection,
|
||||||
|
windSpeedKnots,
|
||||||
|
bestUpwindAngle,
|
||||||
|
bestDownwindAngle,
|
||||||
|
flags[0]);
|
||||||
|
|
||||||
message = new CourseWind(
|
return message;
|
||||||
windId[0],
|
|
||||||
time,
|
|
||||||
raceIDInt,
|
|
||||||
windDirection,
|
|
||||||
windSpeedKnots,
|
|
||||||
bestUpwindAngle,
|
|
||||||
bestDownwindAngle,
|
|
||||||
flags[0] );
|
|
||||||
|
|
||||||
return message;
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode CourseWind message.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.CourseWind;
|
import network.Messages.CourseWind;
|
||||||
import network.Messages.CourseWinds;
|
import network.Messages.CourseWinds;
|
||||||
@@ -38,41 +39,46 @@ public class CourseWindsDecoder implements MessageDecoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedMessage) {
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
//The header is three bytes.
|
try {
|
||||||
byte messageVersionNumber = encodedMessage[0];
|
|
||||||
byte byteWindID = encodedMessage[1];
|
//The header is three bytes.
|
||||||
byte loopCount = encodedMessage[2];
|
byte messageVersionNumber = encodedMessage[0];
|
||||||
|
byte byteWindID = encodedMessage[1];
|
||||||
|
byte loopCount = encodedMessage[2];
|
||||||
|
|
||||||
|
|
||||||
//A CourseWind object is 20 bytes.
|
//A CourseWind object is 20 bytes.
|
||||||
final int courseWindByteLength = 20;
|
final int courseWindByteLength = 20;
|
||||||
|
|
||||||
List<CourseWind> loopMessages = new ArrayList();
|
List<CourseWind> loopMessages = new ArrayList();
|
||||||
|
|
||||||
//The header is 3 bytes, so we need the remaining bytes.
|
//The header is 3 bytes, so we need the remaining bytes.
|
||||||
byte[] loopMessagesBytes = Arrays.copyOfRange(encodedMessage, 3, courseWindByteLength * loopCount + 3);
|
byte[] loopMessagesBytes = Arrays.copyOfRange(encodedMessage, 3, courseWindByteLength * loopCount + 3);
|
||||||
|
|
||||||
for (int messageLoopIndex = 0; messageLoopIndex < (loopCount * courseWindByteLength); messageLoopIndex += courseWindByteLength) {
|
for (int messageLoopIndex = 0; messageLoopIndex < (loopCount * courseWindByteLength); messageLoopIndex += courseWindByteLength) {
|
||||||
|
|
||||||
byte[] messageBytes = Arrays.copyOfRange(loopMessagesBytes, messageLoopIndex, messageLoopIndex + courseWindByteLength);
|
byte[] messageBytes = Arrays.copyOfRange(loopMessagesBytes, messageLoopIndex, messageLoopIndex + courseWindByteLength);
|
||||||
|
|
||||||
CourseWindDecoder courseWindDecoder = new CourseWindDecoder();
|
CourseWindDecoder courseWindDecoder = new CourseWindDecoder();
|
||||||
CourseWind courseWind = courseWindDecoder.decode(messageBytes);
|
CourseWind courseWind = courseWindDecoder.decode(messageBytes);
|
||||||
|
|
||||||
loopMessages.add(courseWind);
|
loopMessages.add(courseWind);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
message = new CourseWinds(
|
||||||
|
messageVersionNumber,
|
||||||
|
byteWindID,
|
||||||
|
loopMessages);
|
||||||
|
|
||||||
|
return message;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode CourseWinds message.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
message = new CourseWinds(
|
|
||||||
messageVersionNumber,
|
|
||||||
byteWindID,
|
|
||||||
loopMessages );
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.Enums.BoatActionEnum;
|
import network.Messages.Enums.BoatActionEnum;
|
||||||
import network.Messages.HeartBeat;
|
import network.Messages.HeartBeat;
|
||||||
@@ -30,12 +31,18 @@ public class HeartBeatDecoder implements MessageDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedMessage) {
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
message = new HeartBeat(bytesToLong(encodedMessage));
|
try {
|
||||||
|
|
||||||
return message;
|
message = new HeartBeat(bytesToLong(encodedMessage));
|
||||||
|
|
||||||
|
return message;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode HeartBeat message.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.Enums.JoinAcceptanceEnum;
|
import network.Messages.Enums.JoinAcceptanceEnum;
|
||||||
import network.Messages.JoinAcceptance;
|
import network.Messages.JoinAcceptance;
|
||||||
@@ -32,27 +33,32 @@ public class JoinAcceptanceDecoder implements MessageDecoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedMessage) {
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
//SourceID is first four bytes.
|
try {
|
||||||
byte[] sourceIdBytes = Arrays.copyOfRange(encodedMessage, 0, 4);
|
|
||||||
|
|
||||||
//Next byte is acceptance type.
|
//SourceID is first four bytes.
|
||||||
byte[] acceptanceBytes = Arrays.copyOfRange(encodedMessage, 4, 5);
|
byte[] sourceIdBytes = Arrays.copyOfRange(encodedMessage, 0, 4);
|
||||||
|
|
||||||
|
//Next byte is acceptance type.
|
||||||
|
byte[] acceptanceBytes = Arrays.copyOfRange(encodedMessage, 4, 5);
|
||||||
|
|
||||||
|
|
||||||
|
//SourceID is an int.
|
||||||
|
int sourceID = ByteConverter.bytesToInt(sourceIdBytes);
|
||||||
|
|
||||||
//SourceID is an int.
|
//Acceptance enum is a byte.
|
||||||
int sourceID = ByteConverter.bytesToInt(sourceIdBytes);
|
JoinAcceptanceEnum acceptanceType = JoinAcceptanceEnum.fromByte(acceptanceBytes[0]);
|
||||||
|
|
||||||
//Acceptance enum is a byte.
|
|
||||||
JoinAcceptanceEnum acceptanceType = JoinAcceptanceEnum.fromByte(acceptanceBytes[0]);
|
|
||||||
|
|
||||||
|
|
||||||
message = new JoinAcceptance(acceptanceType, sourceID);
|
message = new JoinAcceptance(acceptanceType, sourceID);
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode JoinAcceptance message.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.Enums.MarkRoundingBoatStatusEnum;
|
import network.Messages.Enums.MarkRoundingBoatStatusEnum;
|
||||||
import network.Messages.Enums.MarkRoundingSideEnum;
|
import network.Messages.Enums.MarkRoundingSideEnum;
|
||||||
@@ -33,48 +34,54 @@ public class MarkRoundingDecoder implements MessageDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedMessage) {
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
byte messageVersionNumber = encodedMessage[0];
|
try {
|
||||||
|
|
||||||
byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7);
|
byte messageVersionNumber = encodedMessage[0];
|
||||||
long time = ByteConverter.bytesToLong(byteTime);
|
|
||||||
|
|
||||||
byte[] byteAck = Arrays.copyOfRange(encodedMessage, 7, 9);
|
byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7);
|
||||||
int ackNumber = ByteConverter.bytesToInt(byteAck);
|
long time = ByteConverter.bytesToLong(byteTime);
|
||||||
|
|
||||||
byte[] byteRaceID = Arrays.copyOfRange(encodedMessage, 9, 13);
|
byte[] byteAck = Arrays.copyOfRange(encodedMessage, 7, 9);
|
||||||
int raceID = ByteConverter.bytesToInt(byteRaceID);
|
int ackNumber = ByteConverter.bytesToInt(byteAck);
|
||||||
|
|
||||||
byte[] byteSourceID = Arrays.copyOfRange(encodedMessage, 13, 17);
|
byte[] byteRaceID = Arrays.copyOfRange(encodedMessage, 9, 13);
|
||||||
int sourceID = ByteConverter.bytesToInt(byteSourceID);
|
int raceID = ByteConverter.bytesToInt(byteRaceID);
|
||||||
|
|
||||||
byte byteBoatStatus = encodedMessage[17];
|
byte[] byteSourceID = Arrays.copyOfRange(encodedMessage, 13, 17);
|
||||||
MarkRoundingBoatStatusEnum boatStatus = MarkRoundingBoatStatusEnum.fromByte(byteBoatStatus);
|
int sourceID = ByteConverter.bytesToInt(byteSourceID);
|
||||||
|
|
||||||
byte byteRoundingSide = encodedMessage[18];
|
byte byteBoatStatus = encodedMessage[17];
|
||||||
MarkRoundingSideEnum roundingSide = MarkRoundingSideEnum.fromByte(byteRoundingSide);
|
MarkRoundingBoatStatusEnum boatStatus = MarkRoundingBoatStatusEnum.fromByte(byteBoatStatus);
|
||||||
|
|
||||||
byte byteMarkType = encodedMessage[19];
|
byte byteRoundingSide = encodedMessage[18];
|
||||||
MarkRoundingTypeEnum markType = MarkRoundingTypeEnum.fromByte(byteMarkType);
|
MarkRoundingSideEnum roundingSide = MarkRoundingSideEnum.fromByte(byteRoundingSide);
|
||||||
|
|
||||||
byte byteMarkID = encodedMessage[20];
|
byte byteMarkType = encodedMessage[19];
|
||||||
|
MarkRoundingTypeEnum markType = MarkRoundingTypeEnum.fromByte(byteMarkType);
|
||||||
|
|
||||||
|
byte byteMarkID = encodedMessage[20];
|
||||||
|
|
||||||
|
|
||||||
message = new MarkRounding(
|
message = new MarkRounding(
|
||||||
messageVersionNumber,
|
messageVersionNumber,
|
||||||
time,
|
time,
|
||||||
ackNumber,
|
ackNumber,
|
||||||
raceID,
|
raceID,
|
||||||
sourceID,
|
sourceID,
|
||||||
boatStatus,
|
boatStatus,
|
||||||
roundingSide,
|
roundingSide,
|
||||||
markType,
|
markType,
|
||||||
byteMarkID);
|
byteMarkID);
|
||||||
|
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode AverageWind message.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
|
|
||||||
|
|
||||||
@@ -15,7 +16,8 @@ public interface MessageDecoder {
|
|||||||
* Decodes a given message.
|
* Decodes a given message.
|
||||||
* @param encodedMessage The message to decode.
|
* @param encodedMessage The message to decode.
|
||||||
* @return The decoded message.
|
* @return The decoded message.
|
||||||
|
* @throws InvalidMessageException Thrown if the encoded message is invalid in some way, or cannot be decoded.
|
||||||
*/
|
*/
|
||||||
public AC35Data decode(byte[] encodedMessage);
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.Enums.RaceStartTypeEnum;
|
import network.Messages.Enums.RaceStartTypeEnum;
|
||||||
import network.Messages.RaceStartStatus;
|
import network.Messages.RaceStartStatus;
|
||||||
@@ -35,38 +36,42 @@ public class RaceStartStatusDecoder implements MessageDecoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedMessage) {
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
byte messageVersion = encodedMessage[0];
|
byte messageVersion = encodedMessage[0];
|
||||||
|
|
||||||
byte[] timestamp = Arrays.copyOfRange(encodedMessage, 1, 7);
|
byte[] timestamp = Arrays.copyOfRange(encodedMessage, 1, 7);
|
||||||
long time = bytesToLong(timestamp);
|
long time = bytesToLong(timestamp);
|
||||||
|
|
||||||
byte[] ackNumber = Arrays.copyOfRange(encodedMessage, 7, 9);
|
byte[] ackNumber = Arrays.copyOfRange(encodedMessage, 7, 9);
|
||||||
short ack = bytesToShort(ackNumber);
|
short ack = bytesToShort(ackNumber);
|
||||||
|
|
||||||
byte[] raceStartTime = Arrays.copyOfRange(encodedMessage, 9, 15);
|
byte[] raceStartTime = Arrays.copyOfRange(encodedMessage, 9, 15);
|
||||||
long startTime = bytesToLong(raceStartTime);
|
long startTime = bytesToLong(raceStartTime);
|
||||||
|
|
||||||
byte[] raceIdentifier = Arrays.copyOfRange(encodedMessage, 15, 19);
|
byte[] raceIdentifier = Arrays.copyOfRange(encodedMessage, 15, 19);
|
||||||
int raceID = bytesToInt(raceIdentifier);
|
int raceID = bytesToInt(raceIdentifier);
|
||||||
|
|
||||||
byte notificationType = encodedMessage[19];
|
byte notificationType = encodedMessage[19];
|
||||||
|
|
||||||
|
|
||||||
|
message = new RaceStartStatus(
|
||||||
|
messageVersion,
|
||||||
|
time,
|
||||||
|
ack,
|
||||||
|
startTime,
|
||||||
|
raceID,
|
||||||
|
RaceStartTypeEnum.fromByte(notificationType)
|
||||||
|
);
|
||||||
|
|
||||||
message = new RaceStartStatus(
|
return message;
|
||||||
messageVersion,
|
|
||||||
time,
|
|
||||||
ack,
|
|
||||||
startTime,
|
|
||||||
raceID,
|
|
||||||
RaceStartTypeEnum.fromByte(notificationType)
|
|
||||||
);
|
|
||||||
|
|
||||||
return message;
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode RaceStartStatus message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.BoatStatus;
|
import network.Messages.BoatStatus;
|
||||||
import network.Messages.Enums.RaceStatusEnum;
|
import network.Messages.Enums.RaceStatusEnum;
|
||||||
@@ -43,70 +44,75 @@ public class RaceStatusDecoder implements MessageDecoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedMessage) {
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
byte[] versionNumBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
|
byte[] versionNumBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
|
||||||
byte versionNum = versionNumBytes[0];
|
byte versionNum = versionNumBytes[0];
|
||||||
|
|
||||||
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
|
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
|
||||||
long time = bytesToLong(timeBytes);
|
long time = bytesToLong(timeBytes);
|
||||||
|
|
||||||
byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11);
|
byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11);
|
||||||
int raceID = bytesToInt(raceIDBytes);
|
int raceID = bytesToInt(raceIDBytes);
|
||||||
|
|
||||||
byte[] raceStatusBytes = Arrays.copyOfRange(encodedMessage, 11, 12);
|
byte[] raceStatusBytes = Arrays.copyOfRange(encodedMessage, 11, 12);
|
||||||
RaceStatusEnum raceStatus = RaceStatusEnum.fromByte(raceStatusBytes[0]);
|
RaceStatusEnum raceStatus = RaceStatusEnum.fromByte(raceStatusBytes[0]);
|
||||||
|
|
||||||
byte[] expectedStartBytes = Arrays.copyOfRange(encodedMessage, 12, 18);
|
byte[] expectedStartBytes = Arrays.copyOfRange(encodedMessage, 12, 18);
|
||||||
long expectedStart = bytesToLong(expectedStartBytes);
|
long expectedStart = bytesToLong(expectedStartBytes);
|
||||||
|
|
||||||
byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 18, 20);
|
byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 18, 20);
|
||||||
int windDirectionInt = bytesToInt(windDirectionBytes);
|
int windDirectionInt = bytesToInt(windDirectionBytes);
|
||||||
Bearing windDirection = Bearing.fromDegrees(AC35UnitConverter.unpackHeading(windDirectionInt));
|
Bearing windDirection = Bearing.fromDegrees(AC35UnitConverter.unpackHeading(windDirectionInt));
|
||||||
|
|
||||||
byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 20, 22);
|
byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 20, 22);
|
||||||
int windSpeedInt = bytesToInt(windSpeedBytes);
|
int windSpeedInt = bytesToInt(windSpeedBytes);
|
||||||
double windSpeedKnots = AC35UnitConverter.unpackMMperSecToKnots(windSpeedInt);
|
double windSpeedKnots = AC35UnitConverter.unpackMMperSecToKnots(windSpeedInt);
|
||||||
|
|
||||||
byte[] numberOfBoatsBytes = Arrays.copyOfRange(encodedMessage, 22, 23);
|
byte[] numberOfBoatsBytes = Arrays.copyOfRange(encodedMessage, 22, 23);
|
||||||
int numberOfBoats = bytesToInt(numberOfBoatsBytes);
|
int numberOfBoats = bytesToInt(numberOfBoatsBytes);
|
||||||
|
|
||||||
byte[] raceTypeBytes = Arrays.copyOfRange(encodedMessage, 23, 24);
|
byte[] raceTypeBytes = Arrays.copyOfRange(encodedMessage, 23, 24);
|
||||||
RaceTypeEnum raceType = RaceTypeEnum.fromByte(raceTypeBytes[0]);
|
RaceTypeEnum raceType = RaceTypeEnum.fromByte(raceTypeBytes[0]);
|
||||||
|
|
||||||
byte[] boatStatusesBytes = Arrays.copyOfRange(encodedMessage, 24, 25 + 20 * numberOfBoats);
|
byte[] boatStatusesBytes = Arrays.copyOfRange(encodedMessage, 24, 25 + 20 * numberOfBoats);
|
||||||
List<BoatStatus> boatStatuses = new ArrayList<>();
|
List<BoatStatus> boatStatuses = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
//BoatStatus is 20 bytes.
|
//BoatStatus is 20 bytes.
|
||||||
int boatStatusByteLength = 20;
|
int boatStatusByteLength = 20;
|
||||||
|
|
||||||
|
|
||||||
//Decode each BoatStatus.
|
//Decode each BoatStatus.
|
||||||
for (int boatLoopIndex = 0; boatLoopIndex < (numberOfBoats * boatStatusByteLength); boatLoopIndex += boatStatusByteLength) {
|
for (int boatLoopIndex = 0; boatLoopIndex < (numberOfBoats * boatStatusByteLength); boatLoopIndex += boatStatusByteLength) {
|
||||||
|
|
||||||
byte[] boatStatusBytes = Arrays.copyOfRange(boatStatusesBytes, boatLoopIndex, boatLoopIndex + boatStatusByteLength);
|
byte[] boatStatusBytes = Arrays.copyOfRange(boatStatusesBytes, boatLoopIndex, boatLoopIndex + boatStatusByteLength);
|
||||||
|
|
||||||
BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder();
|
BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder();
|
||||||
|
|
||||||
boatStatuses.add(boatStatusDecoder.decode(boatStatusBytes));
|
boatStatuses.add(boatStatusDecoder.decode(boatStatusBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
message = new RaceStatus(
|
||||||
|
versionNum,
|
||||||
|
time,
|
||||||
|
raceID,
|
||||||
|
raceStatus,
|
||||||
|
expectedStart,
|
||||||
|
windDirection,
|
||||||
|
windSpeedKnots,
|
||||||
|
raceType,
|
||||||
|
boatStatuses);
|
||||||
|
|
||||||
|
return message;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode RaceStatus message.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
message = new RaceStatus(
|
|
||||||
versionNum,
|
|
||||||
time,
|
|
||||||
raceID,
|
|
||||||
raceStatus,
|
|
||||||
expectedStart,
|
|
||||||
windDirection,
|
|
||||||
windSpeedKnots,
|
|
||||||
raceType,
|
|
||||||
boatStatuses );
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.Enums.RequestToJoinEnum;
|
import network.Messages.Enums.RequestToJoinEnum;
|
||||||
import network.Messages.RequestToJoin;
|
import network.Messages.RequestToJoin;
|
||||||
@@ -31,20 +32,26 @@ public class RequestToJoinDecoder implements MessageDecoder{
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedRequest) {
|
public AC35Data decode(byte[] encodedRequest) throws InvalidMessageException {
|
||||||
this.encodedRequest = encodedRequest;
|
this.encodedRequest = encodedRequest;
|
||||||
|
|
||||||
//Request type is first four bytes.
|
try {
|
||||||
byte[] requestTypeBytes = Arrays.copyOfRange(encodedRequest, 0, 4);
|
|
||||||
|
|
||||||
//Request type is an integral type.
|
//Request type is first four bytes.
|
||||||
int requestTypeInt = ByteConverter.bytesToInt(requestTypeBytes);
|
byte[] requestTypeBytes = Arrays.copyOfRange(encodedRequest, 0, 4);
|
||||||
RequestToJoinEnum requestType = RequestToJoinEnum.fromInt(requestTypeInt);
|
|
||||||
|
//Request type is an integral type.
|
||||||
|
int requestTypeInt = ByteConverter.bytesToInt(requestTypeBytes);
|
||||||
|
RequestToJoinEnum requestType = RequestToJoinEnum.fromInt(requestTypeInt);
|
||||||
|
|
||||||
|
|
||||||
message = new RequestToJoin(requestType);
|
message = new RequestToJoin(requestType);
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode RequestToJoin message.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.Enums.XMLMessageType;
|
import network.Messages.Enums.XMLMessageType;
|
||||||
import network.Messages.XMLMessage;
|
import network.Messages.XMLMessage;
|
||||||
@@ -35,36 +36,42 @@ public class XMLMessageDecoder implements MessageDecoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AC35Data decode(byte[] encodedMessage) {
|
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
|
||||||
this.encodedMessage = encodedMessage;
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
|
try {
|
||||||
byte[] ackNumberBytes = Arrays.copyOfRange(encodedMessage, 1, 3);
|
|
||||||
byte[] timeStampBytes = Arrays.copyOfRange(encodedMessage, 3, 9);
|
byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
|
||||||
byte[] xmlMsgSubTypeBytes = Arrays.copyOfRange(encodedMessage, 9, 10);
|
byte[] ackNumberBytes = Arrays.copyOfRange(encodedMessage, 1, 3);
|
||||||
byte[] sequenceNumberBytes = Arrays.copyOfRange(encodedMessage, 10, 12);
|
byte[] timeStampBytes = Arrays.copyOfRange(encodedMessage, 3, 9);
|
||||||
byte[] xmlMsgLengthBytes = Arrays.copyOfRange(encodedMessage, 12, 14);
|
byte[] xmlMsgSubTypeBytes = Arrays.copyOfRange(encodedMessage, 9, 10);
|
||||||
byte[] xmlMessagebytes = Arrays.copyOfRange(encodedMessage, 14, encodedMessage.length);
|
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];
|
byte messageVersionNumber = messageVersionNumberBytes[0];
|
||||||
short ackNumber = bytesToShort(ackNumberBytes);
|
short ackNumber = bytesToShort(ackNumberBytes);
|
||||||
long timeStamp = bytesToLong(timeStampBytes);
|
long timeStamp = bytesToLong(timeStampBytes);
|
||||||
XMLMessageType xmlMsgSubType = XMLMessageType.fromByte(xmlMsgSubTypeBytes[0]);
|
XMLMessageType xmlMsgSubType = XMLMessageType.fromByte(xmlMsgSubTypeBytes[0]);
|
||||||
short sequenceNumber = bytesToShort(sequenceNumberBytes);
|
short sequenceNumber = bytesToShort(sequenceNumberBytes);
|
||||||
short xmlMsgLength = bytesToShort(xmlMsgLengthBytes);
|
short xmlMsgLength = bytesToShort(xmlMsgLengthBytes);
|
||||||
String xmlMessage = new String(xmlMessagebytes);
|
String xmlMessage = new String(xmlMessagebytes);
|
||||||
|
|
||||||
|
|
||||||
message = new XMLMessage(
|
message = new XMLMessage(
|
||||||
messageVersionNumber,
|
messageVersionNumber,
|
||||||
ackNumber,
|
ackNumber,
|
||||||
timeStamp,
|
timeStamp,
|
||||||
xmlMsgSubType,
|
xmlMsgSubType,
|
||||||
sequenceNumber,
|
sequenceNumber,
|
||||||
xmlMessage );
|
xmlMessage);
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not decode XMLMessage message.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.AverageWind;
|
import network.Messages.AverageWind;
|
||||||
|
|
||||||
@@ -24,63 +25,68 @@ public class AverageWindEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
AverageWind averageWind = (AverageWind) message;
|
|
||||||
|
//Downcast.
|
||||||
|
AverageWind averageWind = (AverageWind) message;
|
||||||
|
|
||||||
|
|
||||||
byte messageVersionNumber = averageWind.getMessageVersionNumber();
|
byte messageVersionNumber = averageWind.getMessageVersionNumber();
|
||||||
|
|
||||||
long time = averageWind.getTime();
|
long time = averageWind.getTime();
|
||||||
byte[] byteTime = longToBytes(time,6);
|
byte[] byteTime = longToBytes(time, 6);
|
||||||
|
|
||||||
long rawPeriod = averageWind.getRawPeriod();
|
long rawPeriod = averageWind.getRawPeriod();
|
||||||
int rawPeriodInt = packAverageWindPeriod(rawPeriod);
|
int rawPeriodInt = packAverageWindPeriod(rawPeriod);
|
||||||
byte[] byteRawPeriod = intToBytes(rawPeriodInt, 2);
|
byte[] byteRawPeriod = intToBytes(rawPeriodInt, 2);
|
||||||
|
|
||||||
double rawSampleSpeed = averageWind.getRawSpeedKnots();
|
double rawSampleSpeed = averageWind.getRawSpeedKnots();
|
||||||
int rawSampleSpeedInt = packKnotsToMMperSec(rawSampleSpeed);
|
int rawSampleSpeedInt = packKnotsToMMperSec(rawSampleSpeed);
|
||||||
byte[] byteRawSpeed = intToBytes(rawSampleSpeedInt, 2);
|
byte[] byteRawSpeed = intToBytes(rawSampleSpeedInt, 2);
|
||||||
|
|
||||||
long period2 = averageWind.getSampleTwoPeriod();
|
long period2 = averageWind.getSampleTwoPeriod();
|
||||||
int period2Int = packAverageWindPeriod(period2);
|
int period2Int = packAverageWindPeriod(period2);
|
||||||
byte[] bytePeriod2 = intToBytes(period2Int, 2);
|
byte[] bytePeriod2 = intToBytes(period2Int, 2);
|
||||||
|
|
||||||
double speed2 = averageWind.getSampleTwoSpeedKnots();
|
double speed2 = averageWind.getSampleTwoSpeedKnots();
|
||||||
int speed2Int = packKnotsToMMperSec(speed2);
|
int speed2Int = packKnotsToMMperSec(speed2);
|
||||||
byte[] byteSpeed2 = intToBytes(speed2Int, 2);
|
byte[] byteSpeed2 = intToBytes(speed2Int, 2);
|
||||||
|
|
||||||
long period3 = averageWind.getSampleThreePeriod();
|
long period3 = averageWind.getSampleThreePeriod();
|
||||||
int period3Int = packAverageWindPeriod(period3);
|
int period3Int = packAverageWindPeriod(period3);
|
||||||
byte[] bytePeriod3 = intToBytes(period3Int, 2);
|
byte[] bytePeriod3 = intToBytes(period3Int, 2);
|
||||||
|
|
||||||
double speed3 = averageWind.getSampleThreeSpeedKnots();
|
double speed3 = averageWind.getSampleThreeSpeedKnots();
|
||||||
int speed3Int = packKnotsToMMperSec(speed3);
|
int speed3Int = packKnotsToMMperSec(speed3);
|
||||||
byte[] byteSpeed3 = intToBytes(speed3Int, 2);
|
byte[] byteSpeed3 = intToBytes(speed3Int, 2);
|
||||||
|
|
||||||
long period4 = averageWind.getSampleFourPeriod();
|
long period4 = averageWind.getSampleFourPeriod();
|
||||||
int period4Int = packAverageWindPeriod(period4);
|
int period4Int = packAverageWindPeriod(period4);
|
||||||
byte[] bytePeriod4 = intToBytes(period4Int, 2);
|
byte[] bytePeriod4 = intToBytes(period4Int, 2);
|
||||||
|
|
||||||
double speed4 = averageWind.getSampleFourSpeedKnots();
|
double speed4 = averageWind.getSampleFourSpeedKnots();
|
||||||
int speed4Int = packKnotsToMMperSec(speed4);
|
int speed4Int = packKnotsToMMperSec(speed4);
|
||||||
byte[] byteSpeed4 = intToBytes(speed4Int, 2);
|
byte[] byteSpeed4 = intToBytes(speed4Int, 2);
|
||||||
|
|
||||||
|
|
||||||
|
ByteBuffer result = ByteBuffer.allocate(23);
|
||||||
|
result.put(messageVersionNumber);
|
||||||
|
result.put(byteTime);
|
||||||
|
result.put(byteRawPeriod);
|
||||||
|
result.put(byteRawSpeed);
|
||||||
|
result.put(bytePeriod2);
|
||||||
|
result.put(byteSpeed2);
|
||||||
|
result.put(bytePeriod3);
|
||||||
|
result.put(byteSpeed3);
|
||||||
|
result.put(bytePeriod4);
|
||||||
|
result.put(byteSpeed4);
|
||||||
|
return result.array();
|
||||||
|
|
||||||
ByteBuffer result = ByteBuffer.allocate(23);
|
} catch (Exception e) {
|
||||||
result.put(messageVersionNumber);
|
throw new InvalidMessageException("Could not encode AverageWind message.", e);
|
||||||
result.put(byteTime);
|
}
|
||||||
result.put(byteRawPeriod);
|
|
||||||
result.put(byteRawSpeed);
|
|
||||||
result.put(bytePeriod2);
|
|
||||||
result.put(byteSpeed2);
|
|
||||||
result.put(bytePeriod3);
|
|
||||||
result.put(byteSpeed3);
|
|
||||||
result.put(bytePeriod4);
|
|
||||||
result.put(byteSpeed4);
|
|
||||||
return result.array();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.BoatAction;
|
import network.Messages.BoatAction;
|
||||||
|
|
||||||
@@ -22,19 +23,25 @@ public class BoatActionEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
BoatAction boatAction = (BoatAction) message;
|
|
||||||
|
|
||||||
//Message is 1 byte.
|
//Downcast.
|
||||||
ByteBuffer boatActionMessage = ByteBuffer.allocate(1);
|
BoatAction boatAction = (BoatAction) message;
|
||||||
|
|
||||||
boatActionMessage.put(intToBytes(boatAction.getBoatAction().getValue(), 1));
|
//Message is 1 byte.
|
||||||
|
ByteBuffer boatActionMessage = ByteBuffer.allocate(1);
|
||||||
|
|
||||||
byte [] result = boatActionMessage.array();
|
boatActionMessage.put(intToBytes(boatAction.getBoatAction().getValue(), 1));
|
||||||
|
|
||||||
return result;
|
byte[] result = boatActionMessage.array();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode BoatAction message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.BoatLocation;
|
import network.Messages.BoatLocation;
|
||||||
|
|
||||||
@@ -24,61 +25,67 @@ public class BoatLocationEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
BoatLocation boatLocation = (BoatLocation) message;
|
|
||||||
|
//Downcast.
|
||||||
|
BoatLocation boatLocation = (BoatLocation) message;
|
||||||
|
|
||||||
|
|
||||||
int messageVersionNumber = 0b1;
|
int messageVersionNumber = 0b1;
|
||||||
byte[] messageVersionBytes = intToBytes(messageVersionNumber, 1);
|
byte[] messageVersionBytes = intToBytes(messageVersionNumber, 1);
|
||||||
byte[] time = longToBytes(boatLocation.getTime(), 6);
|
byte[] time = longToBytes(boatLocation.getTime(), 6);
|
||||||
byte[] sourceID = intToBytes(boatLocation.getSourceID(), 4);
|
byte[] sourceID = intToBytes(boatLocation.getSourceID(), 4);
|
||||||
byte[] seqNum = longToBytes(boatLocation.getSequenceNumber(), 4);
|
byte[] seqNum = longToBytes(boatLocation.getSequenceNumber(), 4);
|
||||||
byte[] deviceType = intToBytes(boatLocation.getDeviceType().getValue(), 1);
|
byte[] deviceType = intToBytes(boatLocation.getDeviceType().getValue(), 1);
|
||||||
byte[] latitude = intToBytes(packGPS(boatLocation.getLatitude()), 4);
|
byte[] latitude = intToBytes(packGPS(boatLocation.getLatitude()), 4);
|
||||||
byte[] longitude = intToBytes(packGPS(boatLocation.getLongitude()), 4);
|
byte[] longitude = intToBytes(packGPS(boatLocation.getLongitude()), 4);
|
||||||
byte[] altitude = intToBytes(boatLocation.getAltitude(), 4);
|
byte[] altitude = intToBytes(boatLocation.getAltitude(), 4);
|
||||||
byte[] heading = intToBytes(packHeading(boatLocation.getHeading().degrees()), 2);
|
byte[] heading = intToBytes(packHeading(boatLocation.getHeading().degrees()), 2);
|
||||||
byte[] pitch = intToBytes(boatLocation.getPitch(), 2);
|
byte[] pitch = intToBytes(boatLocation.getPitch(), 2);
|
||||||
byte[] roll = intToBytes(boatLocation.getRoll(), 2);
|
byte[] roll = intToBytes(boatLocation.getRoll(), 2);
|
||||||
byte[] boatSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSpeedKnots()), 2);
|
byte[] boatSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSpeedKnots()), 2);
|
||||||
byte[] cog = intToBytes(packHeading(boatLocation.getBoatCOG().degrees()), 2);
|
byte[] cog = intToBytes(packHeading(boatLocation.getBoatCOG().degrees()), 2);
|
||||||
byte[] sog = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSOGKnots()), 2);
|
byte[] sog = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSOGKnots()), 2);
|
||||||
byte[] apparentWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getApparentWindSpeedKnots()), 2);
|
byte[] apparentWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getApparentWindSpeedKnots()), 2);
|
||||||
byte[] apparentWindAngle = intToBytes(packTrueWindAngle(boatLocation.getApparentWindAngle().degrees()), 2);
|
byte[] apparentWindAngle = intToBytes(packTrueWindAngle(boatLocation.getApparentWindAngle().degrees()), 2);
|
||||||
byte[] trueWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getTrueWindSpeedKnots()), 2);
|
byte[] trueWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getTrueWindSpeedKnots()), 2);
|
||||||
byte[] trueWindDirection = intToBytes(packHeading(boatLocation.getTrueWindDirection().degrees()), 2);
|
byte[] trueWindDirection = intToBytes(packHeading(boatLocation.getTrueWindDirection().degrees()), 2);
|
||||||
byte[] trueWindAngle = intToBytes(packTrueWindAngle(boatLocation.getTrueWindAngle().degrees()), 2);
|
byte[] trueWindAngle = intToBytes(packTrueWindAngle(boatLocation.getTrueWindAngle().degrees()), 2);
|
||||||
byte[] currentDrift = intToBytes(packKnotsToMMperSec(boatLocation.getCurrentDriftKnots()), 2);
|
byte[] currentDrift = intToBytes(packKnotsToMMperSec(boatLocation.getCurrentDriftKnots()), 2);
|
||||||
byte[] currentSet = intToBytes(packHeading(boatLocation.getCurrentSet().degrees()), 2);
|
byte[] currentSet = intToBytes(packHeading(boatLocation.getCurrentSet().degrees()), 2);
|
||||||
byte[] rudderAngle = intToBytes(packTrueWindAngle(boatLocation.getRudderAngle().degrees()), 2);
|
byte[] rudderAngle = intToBytes(packTrueWindAngle(boatLocation.getRudderAngle().degrees()), 2);
|
||||||
|
|
||||||
ByteBuffer result = ByteBuffer.allocate(56);
|
ByteBuffer result = ByteBuffer.allocate(56);
|
||||||
result.put(messageVersionBytes);
|
result.put(messageVersionBytes);
|
||||||
result.put(time);
|
result.put(time);
|
||||||
result.put(sourceID);
|
result.put(sourceID);
|
||||||
result.put(seqNum);
|
result.put(seqNum);
|
||||||
result.put(deviceType);
|
result.put(deviceType);
|
||||||
result.put(latitude);
|
result.put(latitude);
|
||||||
result.put(longitude);
|
result.put(longitude);
|
||||||
result.put(altitude);
|
result.put(altitude);
|
||||||
result.put(heading);
|
result.put(heading);
|
||||||
result.put(pitch);
|
result.put(pitch);
|
||||||
result.put(roll);
|
result.put(roll);
|
||||||
result.put(boatSpeed);
|
result.put(boatSpeed);
|
||||||
result.put(cog);
|
result.put(cog);
|
||||||
result.put(sog);
|
result.put(sog);
|
||||||
result.put(apparentWindSpeed);
|
result.put(apparentWindSpeed);
|
||||||
result.put(apparentWindAngle);
|
result.put(apparentWindAngle);
|
||||||
result.put(trueWindSpeed);
|
result.put(trueWindSpeed);
|
||||||
result.put(trueWindDirection);
|
result.put(trueWindDirection);
|
||||||
result.put(trueWindAngle);
|
result.put(trueWindAngle);
|
||||||
result.put(currentDrift);
|
result.put(currentDrift);
|
||||||
result.put(currentSet);
|
result.put(currentSet);
|
||||||
result.put(rudderAngle);
|
result.put(rudderAngle);
|
||||||
|
|
||||||
return result.array();
|
return result.array();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode BoatLocation message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.BoatStatus;
|
import network.Messages.BoatStatus;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@@ -25,32 +26,40 @@ public class BoatStatusEncoder {
|
|||||||
* Encodes a given BoatStatus message.
|
* Encodes a given BoatStatus message.
|
||||||
* @param message The message to encode.
|
* @param message The message to encode.
|
||||||
* @return The encoded message.
|
* @return The encoded message.
|
||||||
|
* @throws InvalidMessageException Thrown if the message is invalid in some way, or cannot be encoded.
|
||||||
*/
|
*/
|
||||||
public byte[] encode(BoatStatus message) {
|
public byte[] encode(BoatStatus message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
BoatStatus boatStatus = (BoatStatus) message;
|
|
||||||
|
|
||||||
//BoatStatus is 20 bytes.
|
|
||||||
ByteBuffer boatStatusBuffer = ByteBuffer.allocate(20);
|
|
||||||
|
|
||||||
byte[] sourceID = intToBytes(boatStatus.getSourceID());
|
//Downcast.
|
||||||
byte[] boatStatusBytes = intToBytes(boatStatus.getBoatStatus().getValue(), 1);
|
BoatStatus boatStatus = (BoatStatus) message;
|
||||||
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);
|
//BoatStatus is 20 bytes.
|
||||||
boatStatusBuffer.put(boatStatusBytes);
|
ByteBuffer boatStatusBuffer = ByteBuffer.allocate(20);
|
||||||
boatStatusBuffer.put(legNum);
|
|
||||||
boatStatusBuffer.put(numPenalties);
|
|
||||||
boatStatusBuffer.put(numPenaltiesServed);
|
|
||||||
boatStatusBuffer.put(estNextMarkTime);
|
|
||||||
boatStatusBuffer.put(estFinishTime);
|
|
||||||
|
|
||||||
return boatStatusBuffer.array();
|
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();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode BoatStatus message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.CourseWind;
|
import network.Messages.CourseWind;
|
||||||
import shared.model.Bearing;
|
import shared.model.Bearing;
|
||||||
|
|
||||||
@@ -28,46 +29,53 @@ public class CourseWindEncoder {
|
|||||||
* Encodes a given CourseWind message.
|
* Encodes a given CourseWind message.
|
||||||
* @param message The message to encode.
|
* @param message The message to encode.
|
||||||
* @return The encoded message.
|
* @return The encoded message.
|
||||||
|
* @throws InvalidMessageException Thrown if the message is invalid in some way, or cannot be encoded.
|
||||||
*/
|
*/
|
||||||
public byte[] encode(CourseWind message) {
|
public byte[] encode(CourseWind message) throws InvalidMessageException {
|
||||||
|
|
||||||
CourseWind courseWind = message;
|
try {
|
||||||
|
|
||||||
|
CourseWind courseWind = message;
|
||||||
|
|
||||||
|
|
||||||
//CourseWind is 20 bytes.
|
//CourseWind is 20 bytes.
|
||||||
ByteBuffer courseWindBuffer = ByteBuffer.allocate(20);
|
ByteBuffer courseWindBuffer = ByteBuffer.allocate(20);
|
||||||
|
|
||||||
|
|
||||||
byte[] windId = intToBytes(courseWind.getID(), 1);
|
byte[] windId = intToBytes(courseWind.getID(), 1);
|
||||||
|
|
||||||
byte[] timeBytes = longToBytes(courseWind.getTime(), 6);
|
byte[] timeBytes = longToBytes(courseWind.getTime(), 6);
|
||||||
|
|
||||||
byte[] raceIDBytes = intToBytes(courseWind.getRaceID(), 4);
|
byte[] raceIDBytes = intToBytes(courseWind.getRaceID(), 4);
|
||||||
|
|
||||||
int windDirectionInt = packHeading(courseWind.getWindDirection().degrees());
|
int windDirectionInt = packHeading(courseWind.getWindDirection().degrees());
|
||||||
byte[] windDirectionBytes = intToBytes(windDirectionInt, 2);
|
byte[] windDirectionBytes = intToBytes(windDirectionInt, 2);
|
||||||
|
|
||||||
int windSpeedInt = packKnotsToMMperSec(courseWind.getWindSpeedKnots());
|
int windSpeedInt = packKnotsToMMperSec(courseWind.getWindSpeedKnots());
|
||||||
byte[] windSpeedBytes = intToBytes(windSpeedInt, 2);
|
byte[] windSpeedBytes = intToBytes(windSpeedInt, 2);
|
||||||
|
|
||||||
int bestUpwindAngleInt = packHeading(courseWind.getBestUpwindAngle().degrees());
|
int bestUpwindAngleInt = packHeading(courseWind.getBestUpwindAngle().degrees());
|
||||||
byte[] bestUpwindAngleBytes = intToBytes(bestUpwindAngleInt, 2);
|
byte[] bestUpwindAngleBytes = intToBytes(bestUpwindAngleInt, 2);
|
||||||
|
|
||||||
int bestDownwindAngleInt = packHeading(courseWind.getBestDownwindAngle().degrees());
|
int bestDownwindAngleInt = packHeading(courseWind.getBestDownwindAngle().degrees());
|
||||||
byte[] bestDownwindAngleBytes = intToBytes(bestDownwindAngleInt, 2);
|
byte[] bestDownwindAngleBytes = intToBytes(bestDownwindAngleInt, 2);
|
||||||
|
|
||||||
byte[] flags = intToBytes(courseWind.getFlags(), 1);
|
byte[] flags = intToBytes(courseWind.getFlags(), 1);
|
||||||
|
|
||||||
courseWindBuffer.put(windId);
|
courseWindBuffer.put(windId);
|
||||||
courseWindBuffer.put(timeBytes);
|
courseWindBuffer.put(timeBytes);
|
||||||
courseWindBuffer.put(raceIDBytes);
|
courseWindBuffer.put(raceIDBytes);
|
||||||
courseWindBuffer.put(windDirectionBytes);
|
courseWindBuffer.put(windDirectionBytes);
|
||||||
courseWindBuffer.put(windSpeedBytes);
|
courseWindBuffer.put(windSpeedBytes);
|
||||||
courseWindBuffer.put(bestUpwindAngleBytes);
|
courseWindBuffer.put(bestUpwindAngleBytes);
|
||||||
courseWindBuffer.put(bestDownwindAngleBytes);
|
courseWindBuffer.put(bestDownwindAngleBytes);
|
||||||
courseWindBuffer.put(flags);
|
courseWindBuffer.put(flags);
|
||||||
|
|
||||||
return courseWindBuffer.array();
|
return courseWindBuffer.array();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode CourseWind message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.BoatAction;
|
import network.Messages.BoatAction;
|
||||||
import network.Messages.CourseWind;
|
import network.Messages.CourseWind;
|
||||||
@@ -24,33 +25,39 @@ public class CourseWindsEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
CourseWinds courseWinds = (CourseWinds) message;
|
|
||||||
|
//Downcast.
|
||||||
|
CourseWinds courseWinds = (CourseWinds) message;
|
||||||
|
|
||||||
|
|
||||||
byte messageVersionNumber = CourseWinds.currentMessageVersionNumber;
|
byte messageVersionNumber = CourseWinds.currentMessageVersionNumber;
|
||||||
|
|
||||||
byte byteWindID = courseWinds.getSelectedWindID();
|
byte byteWindID = courseWinds.getSelectedWindID();
|
||||||
|
|
||||||
byte[] loopcount = intToBytes(courseWinds.getCourseWinds().size(), 1);
|
byte[] loopcount = intToBytes(courseWinds.getCourseWinds().size(), 1);
|
||||||
|
|
||||||
ByteBuffer result = ByteBuffer.allocate(3 + 20 * courseWinds.getCourseWinds().size());
|
ByteBuffer result = ByteBuffer.allocate(3 + 20 * courseWinds.getCourseWinds().size());
|
||||||
|
|
||||||
result.put(messageVersionNumber);
|
result.put(messageVersionNumber);
|
||||||
result.put(byteWindID);
|
result.put(byteWindID);
|
||||||
result.put(loopcount);
|
result.put(loopcount);
|
||||||
|
|
||||||
//Encode each CourseWind.
|
//Encode each CourseWind.
|
||||||
for (CourseWind wind: courseWinds.getCourseWinds()){
|
for (CourseWind wind : courseWinds.getCourseWinds()) {
|
||||||
|
|
||||||
CourseWindEncoder courseWindEncoder = new CourseWindEncoder();
|
CourseWindEncoder courseWindEncoder = new CourseWindEncoder();
|
||||||
byte[] encodedCourseWind = courseWindEncoder.encode(wind);
|
byte[] encodedCourseWind = courseWindEncoder.encode(wind);
|
||||||
|
|
||||||
result.put(encodedCourseWind);
|
result.put(encodedCourseWind);
|
||||||
|
}
|
||||||
|
return result.array();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode CourseWinds message.", e);
|
||||||
}
|
}
|
||||||
return result.array();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.HeartBeat;
|
import network.Messages.HeartBeat;
|
||||||
|
|
||||||
@@ -22,18 +23,24 @@ public class HeartBeatEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
HeartBeat heartbeat = (HeartBeat) message;
|
|
||||||
|
|
||||||
//Message is 4 bytes.
|
//Downcast.
|
||||||
ByteBuffer heartBeat = ByteBuffer.allocate(4);
|
HeartBeat heartbeat = (HeartBeat) message;
|
||||||
heartBeat.put(longToBytes(heartbeat.getSequenceNumber(), 4));
|
|
||||||
|
|
||||||
byte[] result = heartBeat.array();
|
//Message is 4 bytes.
|
||||||
|
ByteBuffer heartBeat = ByteBuffer.allocate(4);
|
||||||
|
heartBeat.put(longToBytes(heartbeat.getSequenceNumber(), 4));
|
||||||
|
|
||||||
return result;
|
byte[] result = heartBeat.array();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode HeartBeat message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.JoinAcceptance;
|
import network.Messages.JoinAcceptance;
|
||||||
import network.Utils.ByteConverter;
|
import network.Utils.ByteConverter;
|
||||||
@@ -23,22 +24,28 @@ public class JoinAcceptanceEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
JoinAcceptance joinAcceptance = (JoinAcceptance) message;
|
|
||||||
|
|
||||||
//Message is 5 bytes.
|
//Downcast.
|
||||||
ByteBuffer joinAcceptanceBuffer = ByteBuffer.allocate(5);
|
JoinAcceptance joinAcceptance = (JoinAcceptance) message;
|
||||||
|
|
||||||
//Source ID is first four bytes.
|
//Message is 5 bytes.
|
||||||
joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getSourceID(), 4));
|
ByteBuffer joinAcceptanceBuffer = ByteBuffer.allocate(5);
|
||||||
//Acceptance type is next byte.
|
|
||||||
joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getAcceptanceType().getValue(), 1));
|
|
||||||
|
|
||||||
byte [] result = joinAcceptanceBuffer.array();
|
//Source ID is first four bytes.
|
||||||
|
joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getSourceID(), 4));
|
||||||
|
//Acceptance type is next byte.
|
||||||
|
joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getAcceptanceType().getValue(), 1));
|
||||||
|
|
||||||
return result;
|
byte[] result = joinAcceptanceBuffer.array();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode JoinAcceptance message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.MarkRounding;
|
import network.Messages.MarkRounding;
|
||||||
|
|
||||||
@@ -23,35 +24,41 @@ public class MarkRoundingEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
MarkRounding markRounding = (MarkRounding) message;
|
|
||||||
|
|
||||||
byte messageVersionNumber = markRounding.getMessageVersionNumber();
|
//Downcast.
|
||||||
byte[] byteTime = longToBytes(markRounding.getTime(), 6);
|
MarkRounding markRounding = (MarkRounding) message;
|
||||||
byte[] byteAck = intToBytes(markRounding.getAckNum(), 2);
|
|
||||||
byte[] byteRaceID = intToBytes(markRounding.getRaceID(), 4);
|
byte messageVersionNumber = markRounding.getMessageVersionNumber();
|
||||||
byte[] byteSourceID = intToBytes(markRounding.getSourceID(), 4);
|
byte[] byteTime = longToBytes(markRounding.getTime(), 6);
|
||||||
byte[] byteBoatStatus = intToBytes(markRounding.getBoatStatus().getValue(), 1);
|
byte[] byteAck = intToBytes(markRounding.getAckNum(), 2);
|
||||||
byte[] byteRoundingSide = intToBytes(markRounding.getRoundingSide().getValue(), 1);
|
byte[] byteRaceID = intToBytes(markRounding.getRaceID(), 4);
|
||||||
byte[] byteMarkType = intToBytes(markRounding.getMarkType().getValue(), 1);
|
byte[] byteSourceID = intToBytes(markRounding.getSourceID(), 4);
|
||||||
byte[] byteMarkID = intToBytes(markRounding.getMarkID(), 1);
|
byte[] byteBoatStatus = intToBytes(markRounding.getBoatStatus().getValue(), 1);
|
||||||
|
byte[] byteRoundingSide = intToBytes(markRounding.getRoundingSide().getValue(), 1);
|
||||||
|
byte[] byteMarkType = intToBytes(markRounding.getMarkType().getValue(), 1);
|
||||||
|
byte[] byteMarkID = intToBytes(markRounding.getMarkID(), 1);
|
||||||
|
|
||||||
|
|
||||||
ByteBuffer result = ByteBuffer.allocate(21);
|
ByteBuffer result = ByteBuffer.allocate(21);
|
||||||
|
|
||||||
result.put(messageVersionNumber);
|
result.put(messageVersionNumber);
|
||||||
result.put(byteTime);
|
result.put(byteTime);
|
||||||
result.put(byteAck);
|
result.put(byteAck);
|
||||||
result.put(byteRaceID);
|
result.put(byteRaceID);
|
||||||
result.put(byteSourceID);
|
result.put(byteSourceID);
|
||||||
result.put(byteBoatStatus);
|
result.put(byteBoatStatus);
|
||||||
result.put(byteRoundingSide);
|
result.put(byteRoundingSide);
|
||||||
result.put(byteMarkType);
|
result.put(byteMarkType);
|
||||||
result.put(byteMarkID);
|
result.put(byteMarkID);
|
||||||
|
|
||||||
return result.array();
|
return result.array();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode MarkRounding message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
|
|
||||||
|
|
||||||
@@ -15,7 +16,8 @@ public interface MessageEncoder {
|
|||||||
* Encodes a given message.
|
* Encodes a given message.
|
||||||
* @param message The message to encode.
|
* @param message The message to encode.
|
||||||
* @return Message in byte encoded form.
|
* @return Message in byte encoded form.
|
||||||
|
* @throws InvalidMessageException Thrown if the message is invalid in some way, or cannot be encoded.
|
||||||
*/
|
*/
|
||||||
public byte[] encode(AC35Data message);
|
public byte[] encode(AC35Data message) throws InvalidMessageException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.RaceStartStatus;
|
import network.Messages.RaceStartStatus;
|
||||||
import network.Utils.ByteConverter;
|
import network.Utils.ByteConverter;
|
||||||
@@ -24,28 +25,34 @@ public class RaceStartStatusEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
RaceStartStatus raceStartStatus = (RaceStartStatus) message;
|
|
||||||
|
//Downcast.
|
||||||
|
RaceStartStatus raceStartStatus = (RaceStartStatus) message;
|
||||||
|
|
||||||
|
|
||||||
byte messageVersion = raceStartStatus.getMessageVersionNumber();
|
byte messageVersion = raceStartStatus.getMessageVersionNumber();
|
||||||
byte[] timestamp = longToBytes(raceStartStatus.getTimestamp(), 6);
|
byte[] timestamp = longToBytes(raceStartStatus.getTimestamp(), 6);
|
||||||
byte[] ackNumber = intToBytes(raceStartStatus.getAckNum(), 2);
|
byte[] ackNumber = intToBytes(raceStartStatus.getAckNum(), 2);
|
||||||
byte[] raceStartTime = longToBytes(raceStartStatus.getRaceStartTime(), 6);
|
byte[] raceStartTime = longToBytes(raceStartStatus.getRaceStartTime(), 6);
|
||||||
byte[] raceIdentifier = intToBytes(raceStartStatus.getRaceID());
|
byte[] raceIdentifier = intToBytes(raceStartStatus.getRaceID());
|
||||||
byte[] notificationType = intToBytes(raceStartStatus.getNotificationType().getValue(), 1);
|
byte[] notificationType = intToBytes(raceStartStatus.getNotificationType().getValue(), 1);
|
||||||
|
|
||||||
ByteBuffer result = ByteBuffer.allocate(20);
|
ByteBuffer result = ByteBuffer.allocate(20);
|
||||||
result.put(messageVersion);
|
result.put(messageVersion);
|
||||||
result.put(timestamp);
|
result.put(timestamp);
|
||||||
result.put(ackNumber);
|
result.put(ackNumber);
|
||||||
result.put(raceStartTime);
|
result.put(raceStartTime);
|
||||||
result.put(raceIdentifier);
|
result.put(raceIdentifier);
|
||||||
result.put(notificationType);
|
result.put(notificationType);
|
||||||
|
|
||||||
return result.array();
|
return result.array();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode RaceStartStatus message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.BoatStatus;
|
import network.Messages.BoatStatus;
|
||||||
import network.Messages.RaceStatus;
|
import network.Messages.RaceStatus;
|
||||||
@@ -28,68 +29,74 @@ public class RaceStatusEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
RaceStatus raceStatus = (RaceStatus) message;
|
|
||||||
|
//Downcast.
|
||||||
|
RaceStatus raceStatus = (RaceStatus) message;
|
||||||
|
|
||||||
|
|
||||||
List<BoatStatus> boatStatuses = raceStatus.getBoatStatuses();
|
List<BoatStatus> boatStatuses = raceStatus.getBoatStatuses();
|
||||||
|
|
||||||
//24 byte header, plus 20 bytes per boat status.
|
//24 byte header, plus 20 bytes per boat status.
|
||||||
ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20 * boatStatuses.size());
|
ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20 * boatStatuses.size());
|
||||||
|
|
||||||
//Version Number 1 bytes. this changes with the pdf. (2)
|
//Version Number 1 bytes. this changes with the pdf. (2)
|
||||||
byte versionNum = 0b10;
|
byte versionNum = 0b10;
|
||||||
|
|
||||||
//time (6 bytes)
|
//time (6 bytes)
|
||||||
byte[] timeBytes = longToBytes(raceStatus.getCurrentTime(), 6);
|
byte[] timeBytes = longToBytes(raceStatus.getCurrentTime(), 6);
|
||||||
|
|
||||||
//race identifier in case multiple races are going at once.
|
//race identifier in case multiple races are going at once.
|
||||||
byte[] raceID = intToBytes(raceStatus.getRaceID());
|
byte[] raceID = intToBytes(raceStatus.getRaceID());
|
||||||
|
|
||||||
//race status 0 - 10
|
//race status 0 - 10
|
||||||
byte[] raceStatusByte = intToBytes(raceStatus.getRaceStatus().getValue(), 1);
|
byte[] raceStatusByte = intToBytes(raceStatus.getRaceStatus().getValue(), 1);
|
||||||
|
|
||||||
//number of milliseconds from Jan 1, 1970 for when the data is valid
|
//number of milliseconds from Jan 1, 1970 for when the data is valid
|
||||||
byte[] expectedStart = longToBytes(raceStatus.getExpectedStartTime(), 6);
|
byte[] expectedStart = longToBytes(raceStatus.getExpectedStartTime(), 6);
|
||||||
|
|
||||||
//North = 0x0000 East = 0x4000 South = 0x8000.
|
//North = 0x0000 East = 0x4000 South = 0x8000.
|
||||||
int windDirectionInt = AC35UnitConverter.packHeading(raceStatus.getWindDirection().degrees());
|
int windDirectionInt = AC35UnitConverter.packHeading(raceStatus.getWindDirection().degrees());
|
||||||
byte[] raceWind = intToBytes(windDirectionInt, 2);
|
byte[] raceWind = intToBytes(windDirectionInt, 2);
|
||||||
|
|
||||||
//mm/sec
|
//mm/sec
|
||||||
int windSpeedInt = AC35UnitConverter.packKnotsToMMperSec(raceStatus.getWindSpeed());
|
int windSpeedInt = AC35UnitConverter.packKnotsToMMperSec(raceStatus.getWindSpeed());
|
||||||
byte[] windSpeed = intToBytes(windSpeedInt, 2);
|
byte[] windSpeed = intToBytes(windSpeedInt, 2);
|
||||||
|
|
||||||
|
|
||||||
byte[] numBoats = intToBytes(boatStatuses.size(), 1);
|
byte[] numBoats = intToBytes(boatStatuses.size(), 1);
|
||||||
|
|
||||||
//1 match race, 2 fleet race
|
//1 match race, 2 fleet race
|
||||||
byte[] bytesRaceType = intToBytes(raceStatus.getRaceType().getValue(), 1);
|
byte[] bytesRaceType = intToBytes(raceStatus.getRaceType().getValue(), 1);
|
||||||
|
|
||||||
|
|
||||||
raceStatusMessage.put(versionNum);
|
raceStatusMessage.put(versionNum);
|
||||||
raceStatusMessage.put(timeBytes);
|
raceStatusMessage.put(timeBytes);
|
||||||
raceStatusMessage.put(raceID);
|
raceStatusMessage.put(raceID);
|
||||||
raceStatusMessage.put(raceStatusByte);
|
raceStatusMessage.put(raceStatusByte);
|
||||||
raceStatusMessage.put(expectedStart);
|
raceStatusMessage.put(expectedStart);
|
||||||
raceStatusMessage.put(raceWind);
|
raceStatusMessage.put(raceWind);
|
||||||
raceStatusMessage.put(windSpeed);
|
raceStatusMessage.put(windSpeed);
|
||||||
raceStatusMessage.put(numBoats);
|
raceStatusMessage.put(numBoats);
|
||||||
raceStatusMessage.put(bytesRaceType);
|
raceStatusMessage.put(bytesRaceType);
|
||||||
|
|
||||||
//Encode each BoatStatus.
|
//Encode each BoatStatus.
|
||||||
for (BoatStatus boatStatus : boatStatuses) {
|
for (BoatStatus boatStatus : boatStatuses) {
|
||||||
|
|
||||||
BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder();
|
BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder();
|
||||||
|
|
||||||
byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus);
|
byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus);
|
||||||
|
|
||||||
raceStatusMessage.put(boatStatusEncoded);
|
raceStatusMessage.put(boatStatusEncoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
return raceStatusMessage.array();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode RaceStatus message.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return raceStatusMessage.array();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,8 +113,10 @@ public class RaceVisionByteEncoder {
|
|||||||
MessageEncoder encoder = null;
|
MessageEncoder encoder = null;
|
||||||
try {
|
try {
|
||||||
encoder = EncoderFactory.create(message.getType());
|
encoder = EncoderFactory.create(message.getType());
|
||||||
|
|
||||||
} catch (InvalidMessageTypeException e) {
|
} catch (InvalidMessageTypeException e) {
|
||||||
throw new InvalidMessageException("Could not create encoder for MessageType: " + message.getType(), e);
|
throw new InvalidMessageException("Could not create encoder for MessageType: " + message.getType(), e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] encodedMessage = encoder.encode(message);
|
byte[] encodedMessage = encoder.encode(message);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.RequestToJoin;
|
import network.Messages.RequestToJoin;
|
||||||
import network.Utils.ByteConverter;
|
import network.Utils.ByteConverter;
|
||||||
@@ -21,19 +22,25 @@ public class RequestToJoinEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
RequestToJoin requestToJoin = (RequestToJoin) message;
|
|
||||||
|
//Downcast.
|
||||||
|
RequestToJoin requestToJoin = (RequestToJoin) message;
|
||||||
|
|
||||||
|
|
||||||
ByteBuffer requestToJoinBuffer = ByteBuffer.allocate(4);
|
ByteBuffer requestToJoinBuffer = ByteBuffer.allocate(4);
|
||||||
|
|
||||||
requestToJoinBuffer.put(ByteConverter.intToBytes(requestToJoin.getRequestType().getValue(), 4));
|
requestToJoinBuffer.put(ByteConverter.intToBytes(requestToJoin.getRequestType().getValue(), 4));
|
||||||
|
|
||||||
byte [] result = requestToJoinBuffer.array();
|
byte[] result = requestToJoinBuffer.array();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode RequestToJoin message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package network.MessageEncoders;
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.AC35Data;
|
import network.Messages.AC35Data;
|
||||||
import network.Messages.XMLMessage;
|
import network.Messages.XMLMessage;
|
||||||
|
|
||||||
@@ -24,39 +25,45 @@ public class XMLMessageEncoder implements MessageEncoder {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] encode(AC35Data message) {
|
public byte[] encode(AC35Data message) throws InvalidMessageException {
|
||||||
|
|
||||||
//Downcast.
|
try {
|
||||||
XMLMessage xmlMessage = (XMLMessage) message;
|
|
||||||
|
//Downcast.
|
||||||
|
XMLMessage xmlMessage = (XMLMessage) message;
|
||||||
|
|
||||||
|
|
||||||
byte[] messageBytes = xmlMessage.getXmlMessage().getBytes(StandardCharsets.UTF_8);
|
byte[] messageBytes = xmlMessage.getXmlMessage().getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
//Message is 14 + xmlMessage.length bytes.
|
//Message is 14 + xmlMessage.length bytes.
|
||||||
ByteBuffer tempOutputByteBuffer = ByteBuffer.allocate(14 + messageBytes.length);
|
ByteBuffer tempOutputByteBuffer = ByteBuffer.allocate(14 + messageBytes.length);
|
||||||
|
|
||||||
//ackNumber converted to bytes
|
//ackNumber converted to bytes
|
||||||
byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2);
|
byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2);
|
||||||
|
|
||||||
//Timestamp converted to bytes.
|
//Timestamp converted to bytes.
|
||||||
byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6);
|
byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6);
|
||||||
|
|
||||||
//sequenceNumber converted to bytes
|
//sequenceNumber converted to bytes
|
||||||
byte[] sequenceNumberBytes = intToBytes(xmlMessage.getSequenceNumber(), 2);
|
byte[] sequenceNumberBytes = intToBytes(xmlMessage.getSequenceNumber(), 2);
|
||||||
|
|
||||||
//xmlMsgLength converted to bytes
|
//xmlMsgLength converted to bytes
|
||||||
byte[] xmlMsgLengthBytes = intToBytes(xmlMessage.getXmlMsgLength(), 2);
|
byte[] xmlMsgLengthBytes = intToBytes(xmlMessage.getXmlMsgLength(), 2);
|
||||||
|
|
||||||
|
|
||||||
tempOutputByteBuffer.put(xmlMessage.getVersionNumber());
|
tempOutputByteBuffer.put(xmlMessage.getVersionNumber());
|
||||||
tempOutputByteBuffer.put(ackNumberBytes);
|
tempOutputByteBuffer.put(ackNumberBytes);
|
||||||
tempOutputByteBuffer.put(timestampBytes);
|
tempOutputByteBuffer.put(timestampBytes);
|
||||||
tempOutputByteBuffer.put(xmlMessage.getXmlMsgSubType().getValue());
|
tempOutputByteBuffer.put(xmlMessage.getXmlMsgSubType().getValue());
|
||||||
tempOutputByteBuffer.put(sequenceNumberBytes);
|
tempOutputByteBuffer.put(sequenceNumberBytes);
|
||||||
tempOutputByteBuffer.put(xmlMsgLengthBytes);
|
tempOutputByteBuffer.put(xmlMsgLengthBytes);
|
||||||
tempOutputByteBuffer.put(messageBytes);
|
tempOutputByteBuffer.put(messageBytes);
|
||||||
|
|
||||||
return tempOutputByteBuffer.array();
|
return tempOutputByteBuffer.array();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidMessageException("Could not encode XMLMessage message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,18 +56,21 @@ public class ControllerClient {
|
|||||||
BoatAction boatAction = new BoatAction(protocolCode);
|
BoatAction boatAction = new BoatAction(protocolCode);
|
||||||
|
|
||||||
//Encode BoatAction.
|
//Encode BoatAction.
|
||||||
byte[] encodedBoatAction = new byte[0];
|
|
||||||
try {
|
try {
|
||||||
encodedBoatAction = RaceVisionByteEncoder.encode(boatAction);
|
byte[] encodedBoatAction = RaceVisionByteEncoder.encode(boatAction);
|
||||||
|
|
||||||
|
BinaryMessageEncoder binaryMessage = new BinaryMessageEncoder(MessageType.BOATACTION, System.currentTimeMillis(), 0,
|
||||||
|
(short) encodedBoatAction.length, encodedBoatAction);
|
||||||
|
|
||||||
|
System.out.println("Sending out key: " + protocolCode);
|
||||||
|
outputStream.write(binaryMessage.getFullMessage());
|
||||||
|
|
||||||
} catch (InvalidMessageException e) {
|
} catch (InvalidMessageException e) {
|
||||||
Logger.getGlobal().log(Level.WARNING, "Could not encode BoatAction: " + boatAction, e);
|
Logger.getGlobal().log(Level.WARNING, "Could not encode BoatAction: " + boatAction, e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryMessageEncoder binaryMessage = new BinaryMessageEncoder(MessageType.BOATACTION, System.currentTimeMillis(), 0,
|
|
||||||
(short) encodedBoatAction.length, encodedBoatAction);
|
|
||||||
|
|
||||||
System.out.println("Sending out key: " + protocolCode);
|
|
||||||
outputStream.write(binaryMessage.getFullMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package visualiser.gameController;
|
package visualiser.gameController;
|
||||||
|
|
||||||
import network.BinaryMessageDecoder;
|
import network.BinaryMessageDecoder;
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.MessageDecoders.BoatActionDecoder;
|
import network.MessageDecoders.BoatActionDecoder;
|
||||||
import network.Messages.BoatAction;
|
import network.Messages.BoatAction;
|
||||||
import network.Messages.Enums.BoatActionEnum;
|
import network.Messages.Enums.BoatActionEnum;
|
||||||
@@ -10,6 +11,8 @@ import visualiser.gameController.Keys.KeyFactory;
|
|||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for dispatching key press data to race from client
|
* Service for dispatching key press data to race from client
|
||||||
@@ -46,12 +49,22 @@ public class ControllerServer implements Runnable {
|
|||||||
byte[] message = new byte[20];
|
byte[] message = new byte[20];
|
||||||
try {
|
try {
|
||||||
if (inputStream.available() > 0) {
|
if (inputStream.available() > 0) {
|
||||||
|
|
||||||
inputStream.read(message);
|
inputStream.read(message);
|
||||||
|
|
||||||
BinaryMessageDecoder encodedMessage = new BinaryMessageDecoder(message);
|
BinaryMessageDecoder encodedMessage = new BinaryMessageDecoder(message);
|
||||||
BoatActionDecoder boatActionDecoder = new BoatActionDecoder();
|
BoatActionDecoder boatActionDecoder = new BoatActionDecoder();
|
||||||
boatActionDecoder.decode(encodedMessage.getMessageBody());
|
|
||||||
BoatAction boatAction = boatActionDecoder.getMessage();
|
try {
|
||||||
System.out.println("Received key: " + boatAction.getBoatAction());
|
boatActionDecoder.decode(encodedMessage.getMessageBody());
|
||||||
|
BoatAction boatAction = boatActionDecoder.getMessage();
|
||||||
|
System.out.println("Received key: " + boatAction.getBoatAction());
|
||||||
|
|
||||||
|
} catch (InvalidMessageException e) {
|
||||||
|
Logger.getGlobal().log(Level.WARNING, "Could not decode BoatAction message.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.MessageEncoders.BoatStatusEncoder;
|
import network.MessageEncoders.BoatStatusEncoder;
|
||||||
import network.MessageEncoders.RaceVisionByteEncoder;
|
import network.MessageEncoders.RaceVisionByteEncoder;
|
||||||
import network.Messages.BoatStatus;
|
import network.Messages.BoatStatus;
|
||||||
@@ -55,8 +56,9 @@ public class BoatStatusDecoderTest {
|
|||||||
* Encodes and decodes a BoatStatus, and returns it.
|
* Encodes and decodes a BoatStatus, and returns it.
|
||||||
* @param boatStatus The BoatStatus to encode and decode.
|
* @param boatStatus The BoatStatus to encode and decode.
|
||||||
* @return The decoded BoatStatus.
|
* @return The decoded BoatStatus.
|
||||||
|
* @throws InvalidMessageException Thrown if message cannot be encoded or decoded.
|
||||||
*/
|
*/
|
||||||
private static BoatStatus encodeDecodeBoatStatus(BoatStatus boatStatus) {
|
private static BoatStatus encodeDecodeBoatStatus(BoatStatus boatStatus) throws InvalidMessageException {
|
||||||
|
|
||||||
BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder();
|
BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder();
|
||||||
byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus);
|
byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package network.MessageDecoders;
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.MessageEncoders.CourseWindEncoder;
|
import network.MessageEncoders.CourseWindEncoder;
|
||||||
import network.Messages.BoatStatus;
|
import network.Messages.BoatStatus;
|
||||||
import network.Messages.CourseWind;
|
import network.Messages.CourseWind;
|
||||||
@@ -43,8 +44,9 @@ public class CourseWindDecoderTest {
|
|||||||
* Encodes and decodes a CourseWind, and returns it.
|
* Encodes and decodes a CourseWind, and returns it.
|
||||||
* @param courseWind The CourseWind to encode and decode.
|
* @param courseWind The CourseWind to encode and decode.
|
||||||
* @return The decoded CourseWind.
|
* @return The decoded CourseWind.
|
||||||
|
* @throws InvalidMessageException Thrown if message cannot be encoded or decoded.
|
||||||
*/
|
*/
|
||||||
private static CourseWind encodeDecodeCourseWind(CourseWind courseWind) {
|
private static CourseWind encodeDecodeCourseWind(CourseWind courseWind) throws InvalidMessageException {
|
||||||
|
|
||||||
CourseWindEncoder courseWindEncoder = new CourseWindEncoder();
|
CourseWindEncoder courseWindEncoder = new CourseWindEncoder();
|
||||||
byte[] courseWindEncoded = courseWindEncoder.encode(courseWind);
|
byte[] courseWindEncoded = courseWindEncoder.encode(courseWind);
|
||||||
|
|||||||
Reference in New Issue
Block a user