package seng302.Networking.MessageEncoders; import seng302.Model.BoatInRace; import seng302.Networking.Utils.BoatLocationMessage; import seng302.Networking.Utils.CourseWind; import seng302.Networking.Utils.RaceMessage; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; /** * Created by fwy13 on 19/04/17. */ public class RaceVisionByteEncoder { public byte[] heartBeat(int seq) { ByteBuffer heartBeat = ByteBuffer.allocate(4); heartBeat.putInt(seq); byte[] result = heartBeat.array(); return result; } public byte[] raceStatus(long time, int race, int raceState, long startTime, short raceWindDir, short raceWindSpeed, int raceType, ArrayList boats) { ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20 * boats.size()); //Version Number 1 bytes byte versionNum = 0b10; //this changes with the pdf. (2) byte[] timeBytes = convert(time, 6);//time (6 bytes) byte[] raceID = ByteBuffer.allocate(4).putInt(race).array();//race identifier incase multiple races are going at once. byte[] raceStatus = convert(raceState, 1);//race status 0 - 10 byte[] expectedStart = convert(startTime, 6);//number of milliseconds from Jan 1, 1970 for when the data is valid byte[] raceWind = ByteBuffer.allocate(2).putShort(raceWindDir).array();//North = 0x0000 East = 0x4000 South = 0x8000 byte[] windSpeed = ByteBuffer.allocate(2).putShort(raceWindSpeed).array();//mm/sec byte[] numBoats = convert(boats.size(), 1); byte[] bytesRaceType = convert(raceType, 1);//1 match race, 2 fleet race raceStatusMessage.put(versionNum); raceStatusMessage.put(timeBytes); raceStatusMessage.put(raceID); raceStatusMessage.put(raceStatus); raceStatusMessage.put(expectedStart); raceStatusMessage.put(raceWind); raceStatusMessage.put(windSpeed); raceStatusMessage.put(numBoats); raceStatusMessage.put(bytesRaceType); for (int i = 0; i < boats.size(); i++) { int sourceID = 0; //TODO use boats source id. byte[] legNum = convert(boats.get(i).getCurrentLeg().getLegNumber(), 1); byte[] numPenalties = convert(0, 1); //TODO use boats in race penalties class byte[] numPenaltiesServed = convert(0, 1);//TODO use boats in race penalites served. byte[] estNextMarkTime = convert((long) 0, 6);//TODO use boats estimated time to next mark. byte[] estFinishTime = convert((long) 0, 6);//TODO use boats estimated time to the finish. raceStatusMessage.putInt(sourceID); raceStatusMessage.put(legNum); raceStatusMessage.put(numPenalties); raceStatusMessage.put(numPenaltiesServed); raceStatusMessage.put(estNextMarkTime); raceStatusMessage.put(estFinishTime); } return raceStatusMessage.array(); } public 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 = convert(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(convert(message[i].getLineNumber(), 1)); mess.put(convert(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(convert(messageVersionNumber, 1)); result.putShort(ackNum); result.put(messLines); for (byte[] mess : messages) { result.put(mess); } return result.array(); } public byte[] raceStartStatus(long time, short ack, long startTime, int raceID, char notification) { int messageVersion = 0b1; byte[] timestamp = convert(time, 6); byte[] ackNumber = convert(ack, 2); byte[] raceStartTime = convert(startTime, 6); int raceIdentifier = raceID; byte[] notificationType = convert(notification, 1); ByteBuffer result = ByteBuffer.allocate(20); result.put(convert(messageVersion, 1)); result.put(timestamp); result.put(ackNumber); result.put(raceStartTime); result.putInt(raceIdentifier); result.put(notificationType); return result.array(); } public byte[] yachtEventCode(long time, short acknowledgeNumber, int raceID, int destSourceID, int incidentID, int eventID) { int messageVersion = 0b10; byte[] encodeTime = convert(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 = convert(eventID, 1); ByteBuffer result = ByteBuffer.allocate(22); result.put(convert(messageVersion, 1)); result.put(encodeTime); result.putShort(ackNum); result.putInt(raceUID); result.putInt(destSource); result.putInt(incident); result.put(event); return result.array(); } public byte[] chatterText(int messageType, String message) { int messageVersion = 0b1; byte[] type = convert(messageType, 1); byte[] length = convert(message.length(), 1); byte[] text = convert(message, length[0]); ByteBuffer result = ByteBuffer.allocate(3 + text.length); result.put(convert(messageVersion, 1)); result.put(type); result.put(length); result.put(text); return result.array(); } public byte[] boatLocation(BoatLocationMessage boatLocationMessage) { int messageVersionNumber = 0b1; byte[] time = convert(boatLocationMessage.getTime(), 6); byte[] sourceID = convert(boatLocationMessage.getSourceID(), 4); byte[] seqNum = convert(boatLocationMessage.getSequenceNumber(), 4); byte deviceType = boatLocationMessage.getDeviceType(); byte[] latitude = convert(boatLocationMessage.getLatitude(), 4); byte[] longitude = convert(boatLocationMessage.getLongitude(), 4); byte[] altitude = convert(boatLocationMessage.getAltitude(), 4); byte[] heading = convert(boatLocationMessage.getHeading(), 2); byte[] pitch = convert(boatLocationMessage.getPitch(), 2); byte[] roll = convert(boatLocationMessage.getRoll(), 2); byte[] boatSpeed = convert(boatLocationMessage.getBoatSpeed(), 2); byte[] cog = convert(boatLocationMessage.getBoatCOG(), 2); byte[] sog = convert(boatLocationMessage.getBoatSOG(), 2); byte[] apparentWindSpeed = convert(boatLocationMessage.getApparentWindSpeed(), 2); byte[] apparentWindAngle = convert(boatLocationMessage.getApparentWindAngle(), 2); byte[] trueWindSpeed = convert(boatLocationMessage.getTrueWindSpeed(), 2); byte[] trueWindDirection = convert(boatLocationMessage.getTrueWindDirection(), 2); byte[] trueWindAngle = convert(boatLocationMessage.getTrueWindAngle(), 2); byte[] currentDrift = convert(boatLocationMessage.getCurrentDrift(), 2); byte[] currentSet = convert(boatLocationMessage.getCurrentSet(), 2); byte[] rudderAngle = convert(boatLocationMessage.getRudderAngle(), 2); ByteBuffer result = ByteBuffer.allocate(56); result.put(convert(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 byte[] markRounding(int time, int ackNumber, int raceID, int sourceID, int boatStatus, int roundingSide, int markType, int markID) { int messageVersionNumber = 0b1; byte[] byteTime = convert(time, 6); byte[] byteAck = convert(ackNumber, 2); byte[] byteRaceID = convert(raceID, 4); byte[] byteSourceID = convert(sourceID, 4); byte[] byteBoatStatus = convert(boatStatus, 1); byte[] byteRoundingSide = convert(roundingSide, 1); byte[] byteMarkType = convert(markType, 1); byte[] byteMarkID = convert(markID, 1); ByteBuffer result = ByteBuffer.allocate(21); result.put(convert(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 byte[] courseWind(byte windID, ArrayList courseWinds) { int messageVersionNumber = 0b1; byte byteWindID = windID; byte[] loopcount = convert(courseWinds.size(), 1); ByteBuffer result = ByteBuffer.allocate(3 + 20 * courseWinds.size()); result.put(convert(messageVersionNumber, 1)); result.put(byteWindID); result.put(loopcount); for (CourseWind wind : courseWinds) { result.put(convert(wind.getID(), 1)); result.put(convert(wind.getTime(), 6)); result.put(convert(wind.getRaceID(), 4)); result.put(convert(wind.getWindDirection(), 2)); result.put(convert(wind.getWindSpeed(), 2)); result.put(convert(wind.getBestUpwindAngle(), 2)); result.put(convert(wind.getBestDownwindAngle(), 2)); result.put(convert(wind.getFlags(), 1)); } return result.array(); } public 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 = convert(time, 6); byte[] byteRawPeriod = convert(rawPeriod, 2); byte[] byteRawSpeed = convert(rawSampleSpeed, 2); byte[] bytePeriod2 = convert(period2, 2); byte[] byteSpeed2 = convert(speed2, 2); byte[] bytePeriod3 = convert(period3, 2); byte[] byteSpeed3 = convert(speed3, 2); byte[] bytePeriod4 = convert(period4, 2); byte[] byteSpeed4 = convert(speed4, 2); ByteBuffer result = ByteBuffer.allocate(23); result.put(convert(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(); } public byte[] convert(String s, int size) { byte[] m = s.getBytes(Charset.forName("UTF-8")); int length = m.length; byte[] result; if (length > 255) { length = 255; } else if (size < 1) { result = new byte[0]; return result; } result = Arrays.copyOfRange(m, 0, length + 1); return result; } public byte[] convert(int n, int size) { byte[] result; if (size > 4) { result = new byte[4]; return result; } else if (size < 1) { result = new byte[0]; return result; } ByteBuffer byteBuffer = ByteBuffer.allocate(4); byteBuffer.putInt(n); byte[] bytes = byteBuffer.array(); result = Arrays.copyOfRange(bytes, 4 - size, 4); return result; } public byte[] convert(long n, int size) { byte[] result; if (size > 8) { result = new byte[8]; return result; } else if (size < 1) { result = new byte[0]; return result; } ByteBuffer byteBuffer = ByteBuffer.allocate(8); byteBuffer.putLong(n); byte[] bytes = byteBuffer.array(); result = Arrays.copyOfRange(bytes, 8 - size, 8); return result; } public byte[] convert(short n, int size) { byte[] result; if (size > 2) { result = new byte[2]; return result; } else if (size < 1) { result = new byte[0]; return result; } ByteBuffer byteBuffer = ByteBuffer.allocate(2); byteBuffer.putShort(n); byte[] bytes = byteBuffer.array(); result = Arrays.copyOfRange(bytes, 2 - size, 2); return result; } }