package network.MessageEncoders; import network.Messages.*; import static network.Utils.ByteConverter.*; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; /** * Created by fwy13 on 19/04/17. */ public class RaceVisionByteEncoder { /** * Serializes a heartbeat message. * @param heartbeat Heartbeat message. * @return Serialized message. */ public static byte[] heartBeat(Heartbeat heartbeat) { ByteBuffer heartBeat = ByteBuffer.allocate(4); heartBeat.put(longToBytes(heartbeat.getSequenceNumber(), 4)); byte[] result = heartBeat.array(); return result; } /** * Serializes a RaceStatus message. * @param raceStatus Message to serialize. * @return Serialized (byte array) message, ready to be written to a socket. */ public static byte[] raceStatus(RaceStatus raceStatus){ List boatStatuses = raceStatus.getBoatStatuses(); ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20* boatStatuses.size()); //Version Number 1 bytes byte versionNum = 0b10; //this changes with the pdf. (2) byte[] timeBytes = longToBytes(raceStatus.getCurrentTime(), 6);//time (6 bytes) byte[] raceID = ByteBuffer.allocate(4).put(intToBytes(raceStatus.getRaceID())).array();//race identifier incase multiple races are going at once. byte[] raceStatusByte = intToBytes(raceStatus.getRaceStatus(), 1);//race status 0 - 10 byte[] expectedStart = longToBytes(raceStatus.getExpectedStartTime(), 6);//number of milliseconds from Jan 1, 1970 for when the data is valid byte[] raceWind = ByteBuffer.allocate(2).put(intToBytes(raceStatus.getWindDirection(), 2)).array();//North = 0x0000 East = 0x4000 South = 0x8000. byte[] windSpeed = ByteBuffer.allocate(2).put(intToBytes(raceStatus.getWindSpeed(), 2)).array();//mm/sec byte[] numBoats = intToBytes(boatStatuses.size(), 1); byte[] bytesRaceType = intToBytes(raceStatus.getRaceType(), 1);//1 match race, 2 fleet race raceStatusMessage.put(versionNum); raceStatusMessage.put(timeBytes); raceStatusMessage.put(raceID); raceStatusMessage.put(raceStatusByte); raceStatusMessage.put(expectedStart); raceStatusMessage.put(raceWind); raceStatusMessage.put(windSpeed); raceStatusMessage.put(numBoats); raceStatusMessage.put(bytesRaceType); for (int i = 0; i < boatStatuses.size(); i++){ byte[] sourceID = intToBytes(boatStatuses.get(i).getSourceID()); byte[] boatStatus = intToBytes(boatStatuses.get(i).getBoatStatus(), 1); byte[] legNum = intToBytes(boatStatuses.get(i).getLegNumber(), 1); byte[] numPenalties = intToBytes(boatStatuses.get(i).getNumPenaltiesAwarded(), 1); byte[] numPenaltiesServed = intToBytes(boatStatuses.get(i).getNumPenaltiesServed(), 1); byte[] estNextMarkTime = longToBytes(boatStatuses.get(i).getEstTimeAtNextMark(), 6); byte[] estFinishTime = longToBytes( boatStatuses.get(i).getEstTimeAtFinish(), 6); raceStatusMessage.put(sourceID); raceStatusMessage.put(boatStatus); raceStatusMessage.put(legNum); raceStatusMessage.put(numPenalties); raceStatusMessage.put(numPenaltiesServed); raceStatusMessage.put(estNextMarkTime); raceStatusMessage.put(estFinishTime); } return raceStatusMessage.array(); } public static byte[] displayTextMessage(RaceMessage[] message){ //ByteBuffer result = ByteBuffer.allocate(4 + numLines * 32); int messageVersionNumber = 0b1;//version number short ackNum = 0;//no clue what this does just a placeholder for 2 bytes. byte[] messLines = intToBytes(message.length, 1); // result.putInt(messageVersionNumber); // result.putShort(ackNum); // result.put(messLines); ArrayList messages = new ArrayList(); int size = 4; for (int i = 0; i < message.length; i ++){ int messageLen = message[i].getMessageText().getBytes().length; byte[] messageAsBytes = message[i].getMessageText().getBytes(); if (messageLen < 30){ messageLen = 30; } ByteBuffer mess = ByteBuffer.allocate(2 + messageLen); mess.put(intToBytes(message[i].getLineNumber(), 1)); mess.put(intToBytes(messageLen, 1)); for (int j = 0; j < messageLen; j ++){ mess.put(messageAsBytes[j]); } messages.add(mess.array()); size += 2 + messageLen; } ByteBuffer result = ByteBuffer.allocate(size); result.put(intToBytes(messageVersionNumber, 1)); result.putShort(ackNum); result.put(messLines); for(byte[] mess: messages){ result.put(mess); } return result.array(); } public static byte[] raceStartStatus(long time, short ack, long startTime, int raceID, char notification){ int messageVersion = 0b1; byte[] timestamp = longToBytes(time, 6); byte[] ackNumber = intToBytes(ack, 2); byte[] raceStartTime = longToBytes(startTime, 6); int raceIdentifier = raceID; byte[] notificationType = intToBytes(notification, 1); ByteBuffer result = ByteBuffer.allocate(20); result.put(intToBytes(messageVersion, 1)); result.put(timestamp); result.put(ackNumber); result.put(raceStartTime); result.put(intToBytes(raceIdentifier)); result.put(notificationType); return result.array(); } public static byte[] yachtEventCode(long time, short acknowledgeNumber, int raceID, int destSourceID, int incidentID, int eventID){ int messageVersion = 0b10; byte[] encodeTime = longToBytes(time, 6); short ackNum = acknowledgeNumber; int raceUID = raceID;//TODO chekc if this is an into for a 4 char string. int destSource = destSourceID; int incident = incidentID; byte[] event = intToBytes(eventID, 1); ByteBuffer result = ByteBuffer.allocate(22); result.put(intToBytes(messageVersion, 1)); result.put(encodeTime); result.putShort(ackNum); result.put(intToBytes(raceUID)); result.put(intToBytes(destSource)); result.put(intToBytes(incident)); result.put(event); return result.array(); } public static byte[] chatterText(int messageType, String message){ int messageVersion = 0b1; byte[] type = intToBytes(messageType, 1); byte[] text = message.getBytes(); byte[] length = intToBytes(text.length, 1); ByteBuffer result = ByteBuffer.allocate(3 + text.length); result.put(intToBytes(messageVersion, 1)); result.put(type); result.put(length); result.put(text); return result.array(); } /** * Serializes an xml message into a byte array. * @param xmlMessage The message to serialize. * @return byte array contaning serialized message. */ public static byte[] xmlMessage(XMLMessage xmlMessage) { byte[] messageBytes = xmlMessage.getXmlMessage().getBytes(StandardCharsets.UTF_8); ByteBuffer tempOutputByteBuffer = ByteBuffer.allocate(14 + messageBytes.length); //ackNumber converted to bytes byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2); //Timestamp converted to bytes. byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6); //sequenceNumber converted to bytes byte[] sequenceNumberBytes = intToBytes(xmlMessage.getSequenceNumber(), 2); //xmlMsgLength converted to bytes byte[] xmlMsgLengthBytes = intToBytes(xmlMessage.getXmlMsgLength(), 2); tempOutputByteBuffer.put(xmlMessage.getVersionNumber()); tempOutputByteBuffer.put(ackNumberBytes); tempOutputByteBuffer.put(timestampBytes); tempOutputByteBuffer.put(xmlMessage.getXmlMsgSubType().getValue()); tempOutputByteBuffer.put(sequenceNumberBytes); tempOutputByteBuffer.put(xmlMsgLengthBytes); tempOutputByteBuffer.put(messageBytes); return tempOutputByteBuffer.array(); } public static byte[] boatLocation(BoatLocation boatLocation){ int messageVersionNumber = 0b1; byte[] time = longToBytes(boatLocation.getTime(), 6); byte[] sourceID = intToBytes(boatLocation.getSourceID(), 4); byte[] seqNum = longToBytes(boatLocation.getSequenceNumber(), 4); byte[] deviceType = intToBytes(boatLocation.getDeviceType(), 1); byte[] latitude = intToBytes(boatLocation.getLatitude(), 4); byte[] longitude = intToBytes(boatLocation.getLongitude(), 4); byte[] altitude = intToBytes(boatLocation.getAltitude(), 4); byte[] heading = intToBytes(boatLocation.getHeading(), 2); byte[] pitch = intToBytes(boatLocation.getPitch(), 2); byte[] roll = intToBytes(boatLocation.getRoll(), 2); byte[] boatSpeed = intToBytes(boatLocation.getBoatSpeed(), 2); byte[] cog = intToBytes(boatLocation.getBoatCOG(), 2); byte[] sog = intToBytes(boatLocation.getBoatSOG(), 2); byte[] apparentWindSpeed = intToBytes(boatLocation.getApparentWindSpeed(), 2); byte[] apparentWindAngle = intToBytes(boatLocation.getApparentWindAngle(), 2); byte[] trueWindSpeed = intToBytes(boatLocation.getTrueWindSpeed(), 2); byte[] trueWindDirection = intToBytes(boatLocation.getTrueWindDirection(), 2); byte[] trueWindAngle = intToBytes(boatLocation.getTrueWindAngle(), 2); byte[] currentDrift = intToBytes(boatLocation.getCurrentDrift(), 2); byte[] currentSet = intToBytes(boatLocation.getCurrentSet(), 2); byte[] rudderAngle = intToBytes(boatLocation.getRudderAngle(), 2); ByteBuffer result = ByteBuffer.allocate(56); result.put(intToBytes(messageVersionNumber, 1)); result.put(time); result.put(sourceID); result.put(seqNum); result.put(deviceType); result.put(latitude); result.put(longitude); result.put(altitude); result.put(heading); result.put(pitch); result.put(roll); result.put(boatSpeed); result.put(cog); result.put(sog); result.put(apparentWindSpeed); result.put(apparentWindAngle); result.put(trueWindSpeed); result.put(trueWindDirection); result.put(trueWindAngle); result.put(currentDrift); result.put(currentSet); result.put(rudderAngle); return result.array(); } public static byte[] markRounding(int time, int ackNumber, int raceID, int sourceID, int boatStatus, int roundingSide, int markType, int markID){ int messageVersionNumber = 0b1; byte[] byteTime = longToBytes(time, 6); byte[] byteAck = intToBytes(ackNumber, 2); byte[] byteRaceID = intToBytes(raceID, 4); byte[] byteSourceID = intToBytes(sourceID, 4); byte[] byteBoatStatus = intToBytes(boatStatus, 1); byte[] byteRoundingSide = intToBytes(roundingSide, 1); byte[] byteMarkType = intToBytes(markType, 1); byte[] byteMarkID = intToBytes(markID, 1); ByteBuffer result = ByteBuffer.allocate(21); result.put(intToBytes(messageVersionNumber, 1)); result.put(byteTime); result.put(byteAck); result.put(byteRaceID); result.put(byteSourceID); result.put(byteBoatStatus); result.put(byteRoundingSide); result.put(byteMarkType); result.put(byteMarkID); return result.array(); } public static byte[] courseWind(byte windID, ArrayList courseWinds){ int messageVersionNumber = 0b1; byte byteWindID = windID; byte[] loopcount = intToBytes(courseWinds.size(), 1); ByteBuffer result = ByteBuffer.allocate(3 + 20 * courseWinds.size()); result.put(intToBytes(messageVersionNumber, 1)); result.put(byteWindID); result.put(loopcount); for (CourseWind wind: courseWinds){ result.put(intToBytes(wind.getID(), 1)); result.put(longToBytes(wind.getTime(), 6)); result.put(intToBytes(wind.getRaceID(), 4)); result.put(intToBytes(wind.getWindDirection(), 2)); result.put(intToBytes(wind.getWindSpeed(), 2)); result.put(intToBytes(wind.getBestUpwindAngle(), 2)); result.put(intToBytes(wind.getBestDownwindAngle(), 2)); result.put(intToBytes(wind.getFlags(), 1)); } return result.array(); } public static byte[] averageWind(int time, int rawPeriod, int rawSampleSpeed, int period2, int speed2, int period3, int speed3, int period4, int speed4){ int messageVersionNumber = 0b1; byte[] byteTime = longToBytes(time,6); byte[] byteRawPeriod = intToBytes(rawPeriod, 2); byte[] byteRawSpeed = intToBytes(rawSampleSpeed, 2); byte[] bytePeriod2 = intToBytes(period2, 2); byte[] byteSpeed2 = intToBytes(speed2, 2); byte[] bytePeriod3 = intToBytes(period3, 2); byte[] byteSpeed3 = intToBytes(speed3, 2); byte[] bytePeriod4 = intToBytes(period4, 2); byte[] byteSpeed4 = intToBytes(speed4, 2); ByteBuffer result = ByteBuffer.allocate(23); result.put(intToBytes(messageVersionNumber, 1)); 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(); } }