├── README.md └── src └── src ├── DatConRecs ├── Payload.java ├── Record.java ├── Record152_0.java ├── Record193_43.java ├── Record198_13.java ├── Record207.java ├── Record218_241.java ├── Record255_1.java ├── Record255_2.java ├── Record30_18.java ├── Record42_12.java ├── Record44_52.java ├── Record68_17.java └── Record92_3.java ├── Files ├── AnalyzeDatResults.java ├── BadArguments.java ├── CLIDatCon.java ├── ConvertDat.java ├── Corrupted.java ├── DatFile.java ├── FileBeingUsed.java ├── FileEnd.java ├── NotDatFile.java ├── Quaternion.java ├── RollPitchYaw.java ├── TSAGeoMag.java └── Util.java └── LICENSE.MD /README.md: -------------------------------------------------------------------------------- 1 | # DatCon 2 | Deprecated goto 3 | https://github.com/BudWalkerJava/DatCon 4 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Payload.java: -------------------------------------------------------------------------------- 1 | /* Payload class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.DatConRecs; 20 | 21 | import java.io.IOException; 22 | import java.io.PrintStream; 23 | import java.nio.ByteBuffer; 24 | import java.nio.ByteOrder; 25 | import java.util.Date; 26 | 27 | import src.Files.DatFile; 28 | import src.Files.FileEnd; 29 | import src.Files.Quaternion; 30 | import src.Files.RollPitchYaw; 31 | 32 | public class Payload { 33 | 34 | byte xorArray[] = null; 35 | 36 | ByteBuffer BB = null; 37 | 38 | int length = 0; 39 | 40 | int recType = 0; 41 | 42 | public long tickNo = 0; 43 | 44 | long start = 0; 45 | 46 | short subType = 0; 47 | 48 | public DatFile datFile = null; 49 | 50 | public Payload(DatFile df, long _start, int _length, int _segtype, 51 | short _subType, long _tickNo) throws IOException, FileEnd { 52 | datFile = df; 53 | start = _start; 54 | length = _length; 55 | recType = _segtype; 56 | tickNo = _tickNo; 57 | subType = _subType; 58 | 59 | xorArray = new byte[length]; 60 | BB = ByteBuffer.wrap(xorArray).order(ByteOrder.LITTLE_ENDIAN); 61 | 62 | byte xorKey = (byte) (tickNo % 256); 63 | for (int i = 0; i < length; i++) { 64 | if (start + i >= datFile.getLength()) { 65 | throw (new FileEnd()); 66 | } 67 | datFile.setPosition(start + i); 68 | xorArray[i] = (byte) (datFile.getByte() ^ xorKey); 69 | } 70 | } 71 | 72 | public long getStart() { 73 | return start; 74 | } 75 | 76 | public ByteBuffer getBB() { 77 | return BB; 78 | } 79 | 80 | public short subType() { 81 | return subType; 82 | } 83 | 84 | public void printBB(PrintStream printStream) { 85 | printStream.print("Rec" + recType + "_" + subType + " "); 86 | printStream.print("FilePos = " + start + " "); 87 | if (tickNo >= 0) 88 | printStream.print("TickNo = " + tickNo); 89 | printStream.println(""); 90 | for (int i = 0; i < length; i++) { 91 | printStream.print(i + ":" 92 | + String.format("%02X", (0xff & BB.get(i))) + ":" 93 | + String.format("%C", (0xff & BB.get(i))) + ":" 94 | + (0xff & BB.get(i))); 95 | if (i < length - 1) { 96 | printStream.print(":Shrt " + BB.getShort(i) + " :UShrt " 97 | + getUnsignedShort(i)); 98 | } 99 | if (i < length - 3) { 100 | printStream.print(" :I " + BB.getInt(i) + " :UI " 101 | + getUnsignedInt(i) + " :F " + BB.getFloat(i)); 102 | } 103 | if (i < length - 7) { 104 | printStream.print(" :L " + BB.getLong(i) + " :D " 105 | + BB.getDouble(i)); 106 | } 107 | printStream.println(""); 108 | } 109 | } 110 | 111 | public short getByte(int index) { 112 | return BB.get(index); 113 | } 114 | 115 | public short getUnsignedByte(int index) { 116 | return (short) (0xff & BB.get(index)); 117 | } 118 | 119 | public long getUnsignedInt(int index) { 120 | return (long) (0xff & BB.get(index)) 121 | + (256 * (long) (0xff & BB.get(index + 1))) 122 | + (65536 * (long) (0xff & BB.get(index + 2))) 123 | + (65536 * 256 * (long) (0xff & BB.get(index + 3))); 124 | } 125 | 126 | public int getUnsignedShort(int index) { 127 | return (int) (0xff & BB.get(index)) 128 | + (256 * (int) (0xff & BB.get(index + 1))); 129 | } 130 | 131 | public float getFloat(int index) { 132 | return BB.getFloat(index); 133 | } 134 | 135 | public int getShort(int index) { 136 | return BB.getShort(index); 137 | } 138 | 139 | public double getDouble(int index) { 140 | return BB.getDouble(index); 141 | } 142 | 143 | public long getTickNo() { 144 | return tickNo; 145 | } 146 | 147 | 148 | 149 | public String getString() { 150 | byte bytes[] = new byte[length]; 151 | int l = 0; 152 | byte B = 0x00; 153 | for (int i = 0; i < length; i++) { 154 | B = BB.get(i); 155 | if (B == 0x00 || B == '\r' || B == '\n') { 156 | l = i; 157 | break; 158 | } 159 | bytes[i] = B; 160 | } 161 | String retv = new String(bytes, 0, l); 162 | return retv; 163 | } 164 | 165 | public void printBB() { 166 | printBB(System.out); 167 | } 168 | 169 | 170 | } 171 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record.java: -------------------------------------------------------------------------------- 1 | /* RecordType class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.DatConRecs; 20 | 21 | import java.io.PrintStream; 22 | import java.nio.ByteBuffer; 23 | import java.text.DecimalFormat; 24 | import java.text.DecimalFormatSymbols; 25 | import java.util.Locale; 26 | 27 | import src.Files.ConvertDat; 28 | 29 | public abstract class Record { 30 | 31 | protected ByteBuffer payloadBB = null; 32 | 33 | public enum cvsTermType { 34 | FLOAT4, DOUBLE, BYTE, SHORT 35 | }; 36 | 37 | protected int _type = -1; 38 | 39 | protected int _subType = -1; 40 | 41 | 42 | static DecimalFormat df = new DecimalFormat("000.#############", 43 | new DecimalFormatSymbols(Locale.US)); 44 | 45 | 46 | 47 | public void process(Payload _record) { 48 | payloadBB = _record.getBB(); 49 | } 50 | 51 | 52 | 53 | public boolean isType(int _Type, short _subType) { 54 | return (this._type == _Type && this._subType == _subType); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record152_0.java: -------------------------------------------------------------------------------- 1 | /* Record152_0 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.DatConRecs; 20 | 21 | import java.io.PrintStream; 22 | import java.util.Iterator; 23 | import java.util.Vector; 24 | 25 | import src.Files.ConvertDat; 26 | import src.Files.FileEnd; 27 | 28 | public class Record152_0 extends Record { 29 | // 50 hZ 30 | // length 45 31 | 32 | public static Record152_0 current = null; 33 | 34 | public short aileron = 0; 35 | 36 | public short elevator = 0; 37 | 38 | public short throttle = 0; 39 | 40 | public short rudder = 0; 41 | 42 | public byte modeSwitch = 0; 43 | 44 | public short gpsHealth = 0; 45 | 46 | Vector hits = new Vector(500); 47 | 48 | Iterator hitsIterator = null; 49 | 50 | private int numHits = 0; 51 | 52 | public double clq = 0.0; 53 | 54 | public boolean clqHasValue = false; 55 | 56 | public Record152_0() { 57 | _type = 152; 58 | _subType = 0; 59 | current = this; 60 | } 61 | 62 | public void process(Payload _payload) { 63 | super.process(_payload); 64 | aileron = payloadBB.getShort(4); 65 | elevator = payloadBB.getShort(6); 66 | throttle = payloadBB.getShort(8); 67 | rudder = payloadBB.getShort(10); 68 | modeSwitch = payloadBB.get(31); 69 | gpsHealth = payloadBB.get(41); 70 | if (ConvertDat.EXPERIMENTAL) { 71 | hits.add(0, new Long(_payload.tickNo)); 72 | if (numHits == 500) { 73 | hits.remove(499); 74 | int count = 0; 75 | hitsIterator = hits.iterator(); 76 | while (hitsIterator.hasNext()) { 77 | long ti = ((Long) hitsIterator.next()).longValue(); 78 | if (ti < _payload.tickNo - 6000) 79 | break; 80 | count++; 81 | } 82 | clq = ((double) count) / numHits; 83 | clqHasValue = true; 84 | } else 85 | numHits++; 86 | } 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record193_43.java: -------------------------------------------------------------------------------- 1 | /* Record193_43 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.DatConRecs; 20 | 21 | import java.io.PrintStream; 22 | 23 | // 15 HZ 24 | public class Record193_43 extends Record { 25 | 26 | public static Record193_43 current = null; 27 | 28 | public double longRad = 0.0; 29 | 30 | public double latRad = 0.0; 31 | 32 | public double longitudeTablet = 0.0; 33 | 34 | public double latitudeTablet = 0.0; 35 | 36 | public boolean valid = false; 37 | 38 | public Record193_43() { 39 | current = this; 40 | _type = 193; 41 | _subType = 43; 42 | } 43 | 44 | // does not occur on every flight 45 | 46 | public void process(Payload _payload) { 47 | super.process(_payload); 48 | latRad = payloadBB.getDouble(155); 49 | longRad = payloadBB.getDouble(163); 50 | longitudeTablet = Math.toDegrees(longRad); 51 | latitudeTablet = Math.toDegrees(latRad); 52 | if (!valid) { 53 | if (longitudeTablet != 0.0 && latitudeTablet != 0.0) { 54 | valid = true; 55 | } 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record198_13.java: -------------------------------------------------------------------------------- 1 | /* Record198_13 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.DatConRecs; 20 | 21 | import java.io.PrintStream; 22 | 23 | import src.Files.TSAGeoMag; 24 | import src.Files.Util; 25 | 26 | public class Record198_13 extends Record { 27 | //length 36 28 | // 1 hZ 29 | public static Record198_13 current = null; 30 | 31 | private double longitudeHP = 0.0; 32 | 33 | private double latitudeHP = 0.0; 34 | 35 | private boolean valid = false; 36 | 37 | private double declination = 0.0; 38 | 39 | public static TSAGeoMag geoMag = new TSAGeoMag(); 40 | 41 | public Record198_13() { 42 | _type = 198; 43 | _subType = 13; 44 | current = this; 45 | } 46 | 47 | public void process(Payload _payload) { 48 | super.process(_payload); 49 | payloadBB = _payload.getBB(); 50 | double longRad = payloadBB.getDouble(0); 51 | double latRad = payloadBB.getDouble(8); 52 | if (!valid) { 53 | // following depends on .DAT having 800000.0 for these values before they're good 54 | if (longRad < 100.0 && latRad < 100.0) { 55 | valid = true; 56 | double longDeg = Math.toDegrees(longRad); 57 | double latDeg = Math.toDegrees(latRad); 58 | declination = geoMag.getDeclination(latDeg, longDeg); 59 | } 60 | } 61 | if (valid) { 62 | longitudeHP = longRad; 63 | latitudeHP = latRad; 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record207.java: -------------------------------------------------------------------------------- 1 | /* Record207 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.DatConRecs; 20 | 21 | import src.Files.Util; 22 | 23 | public class Record207 extends Record { 24 | 25 | // 200 hZ 26 | // length 122 27 | 28 | public static Record207 current = null; 29 | 30 | public double longRad = 0.0; 31 | 32 | public double latRad = 0.0; 33 | 34 | public int numSats = 0; 35 | 36 | public float quatW = (float) 0.0; 37 | 38 | public float quatX = (float) 0.0; 39 | 40 | public float quatY = (float) 0.0; 41 | 42 | public float quatZ = (float) 0.0; 43 | 44 | public float gpsAlt = (float) 0.0; 45 | 46 | public float accelX = (float) 0.0; 47 | 48 | public float accelY = (float) 0.0; 49 | 50 | public float accelZ = (float) 0.0; 51 | 52 | public float gyroX = (float) 0.0; 53 | 54 | public float gyroY = (float) 0.0; 55 | 56 | public float gyroZ = (float) 0.0; 57 | 58 | public float baroAlt = (float) 0.0; 59 | 60 | public float velN = (float) 0.0; 61 | 62 | public float velE = (float) 0.0; 63 | 64 | public float velD = (float) 0.0; 65 | 66 | public int magX = 0; 67 | 68 | public int magY = 0; 69 | 70 | public int magZ = 0; 71 | 72 | boolean valid = false; 73 | 74 | public float diffX = (float) 0.0; 75 | 76 | public float diffY = (float) 0.0; 77 | 78 | public float diffZ = (float) 0.0; 79 | 80 | float x4 = (float) 0.0; 81 | 82 | float x5 = (float) 0.0; 83 | 84 | float x6 = (float) 0.0; 85 | 86 | public int imuTemp = 0; 87 | 88 | int i2 = 0; 89 | 90 | int i3 = 0; 91 | 92 | int i4 = 0; 93 | 94 | int i5 = 0; 95 | 96 | public double totalZGyro = 0.0; 97 | 98 | public long lastTickNo = 0; 99 | 100 | // distance travelled stuff 101 | long dtLastTickNo = 0; 102 | 103 | public double distanceTraveled = 0.0; 104 | 105 | double dtLastLat = 0.0; 106 | 107 | double dtLastLong = 0.0; 108 | 109 | public double bearingDeclined = 0.0; 110 | 111 | public double bearingTrue = 0.0; 112 | 113 | public Record207() { 114 | current = this; 115 | _type = 207; 116 | _subType = 1; 117 | } 118 | 119 | public void process(Payload _payload) { 120 | super.process(_payload); 121 | longRad = payloadBB.getDouble(0); 122 | latRad = payloadBB.getDouble(8); 123 | gpsAlt = payloadBB.getFloat(16); 124 | accelX = payloadBB.getFloat(20); 125 | accelY = payloadBB.getFloat(24); 126 | accelZ = payloadBB.getFloat(28); 127 | gyroX = (float) Math.toDegrees(payloadBB.getFloat(32)); 128 | gyroY = (float) Math.toDegrees(payloadBB.getFloat(36)); 129 | gyroZ = (float) Math.toDegrees(payloadBB.getFloat(40)); 130 | baroAlt = payloadBB.getFloat(44); 131 | quatW = payloadBB.getFloat(48); 132 | quatX = payloadBB.getFloat(52); 133 | quatY = payloadBB.getFloat(56); 134 | quatZ = payloadBB.getFloat(60); 135 | diffX = payloadBB.getFloat(64); 136 | diffY = payloadBB.getFloat(68); 137 | diffZ = payloadBB.getFloat(72); 138 | velN = payloadBB.getFloat(76); 139 | velE = payloadBB.getFloat(80); 140 | velD = payloadBB.getFloat(84); 141 | x4 = payloadBB.getFloat(88); 142 | x5 = payloadBB.getFloat(92); 143 | x6 = payloadBB.getFloat(96); 144 | magX = payloadBB.getShort(100); 145 | magY = payloadBB.getShort(102); 146 | magZ = payloadBB.getShort(104); 147 | imuTemp = payloadBB.getShort(106); 148 | i2 = payloadBB.getShort(108); 149 | i3 = payloadBB.getShort(110); 150 | i4 = payloadBB.getShort(112); 151 | i5 = payloadBB.getShort(114); 152 | numSats = payloadBB.get(116); 153 | if (_payload.tickNo > _payload.datFile.flightStartTick) { 154 | if (_payload.tickNo > dtLastTickNo + 60) { 155 | if (dtLastLat == 0.0 && dtLastLong == 0.0) { 156 | dtLastLat = latRad; 157 | dtLastLong = longRad; 158 | } 159 | double dist = Util.distance(latRad, longRad, dtLastLat, 160 | dtLastLong); 161 | bearingTrue = Util.bearing(dtLastLat, dtLastLong, latRad, 162 | longRad); 163 | double x = bearingTrue - Record255_1.current.declination; 164 | if (x < -180.0) 165 | bearingDeclined = 360.0 + x; 166 | else if (x > 180.0) 167 | bearingDeclined = x - 360.0; 168 | else 169 | bearingDeclined = x; 170 | distanceTraveled += dist; 171 | dtLastLat = latRad; 172 | dtLastLong = longRad; 173 | dtLastTickNo = _payload.tickNo; 174 | } 175 | 176 | } 177 | if (lastTickNo != 0) { 178 | totalZGyro += gyroZ * ((double) (_payload.tickNo - lastTickNo)) 179 | / 600.0; 180 | } 181 | lastTickNo = _payload.tickNo; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record218_241.java: -------------------------------------------------------------------------------- 1 | /* Record218_241 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | package src.DatConRecs; 21 | 22 | import java.io.PrintStream; 23 | 24 | public class Record218_241 extends Record { 25 | 26 | public static Record218_241 current = null; 27 | 28 | boolean valid = false; 29 | 30 | public short rFrontLoad = 0; 31 | 32 | public short lFrontLoad = 0; 33 | 34 | public short lBackLoad = 0; 35 | 36 | public short rBackLoad = 0; 37 | 38 | public short rFrontSpeed = 0; 39 | 40 | public short lFrontSpeed = 0; 41 | 42 | public short lBackSpeed = 0; 43 | 44 | public short rBackSpeed = 0; 45 | 46 | public Record218_241() { 47 | _type = 218; 48 | _subType = 241; 49 | current = this; 50 | } 51 | 52 | // Byte 0, 19, 38, 57 may be ESC , usually 0, but -1 with ESC error 53 | 54 | public void process(Payload _payload) { 55 | super.process(_payload); 56 | rFrontLoad = payloadBB.getShort(1); 57 | rFrontSpeed = payloadBB.getShort(3); 58 | lFrontLoad = payloadBB.getShort(20); 59 | lFrontSpeed = payloadBB.getShort(22); 60 | lBackLoad = payloadBB.getShort(39); 61 | lBackSpeed = payloadBB.getShort(41); 62 | rBackLoad = payloadBB.getShort(58); 63 | rBackSpeed = payloadBB.getShort(60); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record255_1.java: -------------------------------------------------------------------------------- 1 | /* Record255_1 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | package src.DatConRecs; 21 | 22 | import java.util.regex.Matcher; 23 | import java.util.regex.Pattern; 24 | 25 | import src.Files.ConvertDat; 26 | import src.Files.TSAGeoMag; 27 | import src.Files.Util; 28 | 29 | public class Record255_1 extends Record { 30 | 31 | public static Record255_1 current = null; 32 | 33 | public double longitudeHP = 0.0; 34 | 35 | public double latitudeHP = 0.0; 36 | 37 | public double longitudeHPDegrees; 38 | 39 | public double latitudeHPDegrees; 40 | 41 | public float heightHP = 0.0f; 42 | 43 | public boolean validHP = false; 44 | 45 | public static TSAGeoMag geoMag = new TSAGeoMag(); 46 | 47 | public double declination = 0.0; 48 | 49 | public double inclination = 0.0; 50 | 51 | public String text = ""; 52 | 53 | ConvertDat convertDat = null; 54 | 55 | public boolean inspire1 = false; 56 | 57 | public boolean standard = false; 58 | 59 | public String batteryBarCode = ""; 60 | 61 | public boolean P3 = false; 62 | 63 | public Record255_1(ConvertDat convertDat) { 64 | current = this; 65 | _type = 255; 66 | _subType = 1; 67 | this.convertDat = convertDat; 68 | } 69 | 70 | public void process(Payload _payload) { 71 | super.process(_payload); 72 | long tickNo = _payload.getTickNo(); 73 | long timeOffset = convertDat.timeOffset; 74 | String payloadString = _payload.getString(); 75 | if (payloadString.length() > 0) { 76 | if (convertDat.csvEventLogOutput 77 | && convertDat.tickRangeLower <= _payload.getTickNo()) { 78 | if (text.length() > 0) 79 | text += "|"; 80 | text += payloadString; 81 | } 82 | if (convertDat.eloPS != null 83 | && convertDat.tickRangeLower <= _payload.getTickNo()) { 84 | convertDat.eloPS.println(Util.timeString(tickNo, timeOffset) 85 | + " : " + tickNo + " : " + payloadString); 86 | } 87 | if (payloadString.indexOf("Home Point") > -1) { 88 | Pattern latlonPattern = Pattern 89 | .compile(".*?(-*\\d+\\.\\d+)\\s+(-*\\d+\\.\\d+)\\s+(-*\\d+\\.\\d+)"); 90 | Matcher latlonMatcher = latlonPattern.matcher(payloadString); 91 | if (latlonMatcher.find()) { 92 | String lat = payloadString.substring( 93 | latlonMatcher.start(1), latlonMatcher.end(1)); 94 | String lon = payloadString.substring( 95 | latlonMatcher.start(2), latlonMatcher.end(2)); 96 | String hei = payloadString.substring( 97 | latlonMatcher.start(3), latlonMatcher.end(3)); 98 | longitudeHPDegrees = Double.parseDouble(lon); 99 | latitudeHPDegrees = Double.parseDouble(lat); 100 | declination = geoMag.getDeclination(latitudeHPDegrees, 101 | longitudeHPDegrees); 102 | inclination = geoMag.getDipAngle(latitudeHPDegrees, 103 | longitudeHPDegrees); 104 | heightHP = Float.parseFloat(hei); 105 | longitudeHP = Math.toRadians(longitudeHPDegrees); 106 | latitudeHP = Math.toRadians(latitudeHPDegrees); 107 | validHP = true; 108 | } 109 | } else if (payloadString.indexOf("Battery barcode:") > -1) { 110 | batteryBarCode = payloadString.substring(payloadString 111 | .indexOf(":") + 1); 112 | } 113 | 114 | if (payloadString.indexOf("Board") > -1) { 115 | if (payloadString.indexOf("wm320v2") > -1) { 116 | P3 = true; 117 | } else if (payloadString.indexOf("wm610") > -1) { 118 | inspire1 = true; 119 | } else if (payloadString.indexOf("wm321") > -1) { 120 | standard = true; 121 | } else if (payloadString.indexOf("tp1406") > -1) { 122 | // / don't know what this is, involves landing gear 123 | } 124 | } 125 | } 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record255_2.java: -------------------------------------------------------------------------------- 1 | /* Record255_2 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | package src.DatConRecs; 21 | 22 | import java.nio.ByteBuffer; 23 | import java.util.regex.Matcher; 24 | import java.util.regex.Pattern; 25 | 26 | import src.Files.ConvertDat; 27 | 28 | 29 | public class Record255_2 extends Record { 30 | 31 | public static Record255_2 current = null; 32 | 33 | ByteBuffer payload = null; 34 | 35 | private ConvertDat convertDat = null; 36 | 37 | public int batteryCycleCount = 0; 38 | 39 | public int batteryPercentage = 0; 40 | 41 | Pattern numberPattern = Pattern.compile("\\[\\s*(\\d+)\\s*\\]"); 42 | 43 | public Record255_2(ConvertDat convertDat) { 44 | current = this; 45 | _type = 255; 46 | _subType = 2; 47 | this.convertDat = convertDat; 48 | } 49 | 50 | public void process(Payload _payload) { 51 | super.process(_payload); 52 | payload = _payload.getBB(); 53 | String payloadString = _payload.getString(); 54 | if (payloadString.length() > 0) { 55 | if (convertDat.cloPS != null) { 56 | convertDat.cloPS.println(+_payload.getTickNo() + " : " 57 | + payloadString); 58 | } 59 | if (payloadString.indexOf("battery_info.life_percentage_0") > -1) { 60 | Matcher numberMatcher = numberPattern.matcher(payloadString); 61 | if (numberMatcher.find()) { 62 | String number = payloadString.substring( 63 | numberMatcher.start(1), numberMatcher.end(1)); 64 | batteryPercentage = Integer.parseInt(number); 65 | } 66 | } 67 | if (payloadString.indexOf("battery_info.cycle_count_0") > -1) { 68 | Matcher numberMatcher = numberPattern.matcher(payloadString); 69 | if (numberMatcher.find()) { 70 | String number = payloadString.substring( 71 | numberMatcher.start(1), numberMatcher.end(1)); 72 | batteryCycleCount = Integer.parseInt(number); 73 | } 74 | } 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record30_18.java: -------------------------------------------------------------------------------- 1 | /* Record30_18 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | package src.DatConRecs; 21 | 22 | public class Record30_18 extends Record { 23 | 24 | public static Record30_18 current = null; 25 | 26 | // 1 Hz 27 | // length 79 28 | public int batteryUsefulTime = 0; 29 | 30 | public boolean validBUT = false; 31 | 32 | public boolean validVP = false; 33 | 34 | public int voltagePercent = 0; 35 | 36 | public Record30_18() { 37 | current = this; 38 | _type = 30; 39 | _subType = 18; 40 | } 41 | 42 | public void process(Payload _payload) { 43 | super.process(_payload); 44 | batteryUsefulTime = payloadBB.getShort(0); 45 | if (!validBUT) { 46 | if (batteryUsefulTime > 0) 47 | validBUT = true; 48 | } 49 | voltagePercent = payloadBB.get(72); 50 | if (!validVP) { 51 | if (voltagePercent > 0) { 52 | validVP = true; 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record42_12.java: -------------------------------------------------------------------------------- 1 | /* Record42_12 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.DatConRecs; 20 | 21 | import src.Files.ConvertDat; 22 | 23 | 24 | public class Record42_12 extends Record { 25 | 26 | public static Record42_12 current = null; 27 | 28 | double longitude = 0.0; 29 | 30 | double latitude = 0.0; 31 | 32 | public float height = 0f; // height above HP meters 33 | 34 | public int flightTime = 0; 35 | 36 | public float roll = 0; 37 | 38 | public float pitch = 0; 39 | 40 | public float yaw = 0; 41 | 42 | private ConvertDat convertDat = null; 43 | 44 | public byte failure = 0x00; 45 | 46 | public byte flyc_state = 0x00; 47 | 48 | public byte nonGPSError = 0x00; 49 | 50 | public String NGPE = ""; 51 | 52 | public int dwflyState = 0; 53 | 54 | public String FLCS = ""; 55 | 56 | public int connectedToRC = 0x80; // 0x80 not connected, 0x00 connected 57 | 58 | // 10 hz 59 | // length 52 60 | 61 | public Record42_12(ConvertDat convertDat) { 62 | current = this; 63 | _type = 42; 64 | _subType = 12; 65 | this.convertDat = convertDat; 66 | } 67 | 68 | public void process(Payload _payload) { 69 | super.process(_payload); 70 | payloadBB = _payload.getBB(); 71 | longitude = Math.toDegrees(payloadBB.getDouble(0)); 72 | latitude = Math.toDegrees(payloadBB.getDouble(8)); 73 | height = ((float) (payloadBB.getShort(16))) / 10f; 74 | pitch = ((float) (payloadBB.getShort(24))) / 10f; 75 | roll = ((float) (payloadBB.getShort(26))) / 10f; 76 | yaw = ((float) (payloadBB.getShort(28))) / 10f; 77 | flyc_state = (byte) (0x7F & (payloadBB.get(30))); 78 | connectedToRC = (0x80 & (payloadBB.get(30))); 79 | failure = payloadBB.get(38); // possible linked to MOTOR_START_FAILED_CAUSE in osd.js 80 | nonGPSError = (byte) (0x07 & (payloadBB.get(39))); 81 | flightTime = payloadBB.getShort(42) * 100; 82 | if (convertDat.kmlType >= 0 83 | && convertDat.tickRangeLower <= _payload.getTickNo()) { 84 | if (longitude != 0.0 && latitude != 0.0 && height != 0.0f) { 85 | float alt = height; 86 | if (convertDat.kmlType == 1) { 87 | alt += convertDat.homePointElevation; 88 | } 89 | convertDat.kmlPS.println(" " + longitude + "," 90 | + latitude + "," + alt); 91 | } 92 | } 93 | } 94 | 95 | public void setStateStrings() { 96 | switch (nonGPSError) { 97 | case 1: 98 | NGPE = "FORBIN"; 99 | break; 100 | case 2: 101 | NGPE = "GPSNUM_NONENOUGH"; 102 | break; 103 | case 3: 104 | NGPE = "GPS_HDOP_LARGE"; 105 | break; 106 | case 4: 107 | NGPE = "GPS_POSITION_NON_MATCH"; 108 | break; 109 | case 5: 110 | NGPE = "SPEED_ERROR_LARGE"; 111 | break; 112 | case 6: 113 | NGPE = "YAW_ERROR_LARGE"; 114 | break; 115 | case 7: 116 | NGPE = "COMPASS_ERROR_LARGE"; 117 | break; 118 | } 119 | 120 | switch (flyc_state) { 121 | case 0: 122 | FLCS = "MANUAL"; 123 | dwflyState = 1; 124 | break; 125 | case 1: 126 | FLCS = "ATTI"; 127 | dwflyState = 2; 128 | break; 129 | case 2: 130 | FLCS = "ATTI_CL"; 131 | dwflyState = 3; 132 | break; 133 | case 3: 134 | FLCS = "ATTI_HOVER"; 135 | dwflyState = 4; 136 | break; 137 | case 4: 138 | FLCS = "HOVER"; 139 | dwflyState = 5; 140 | break; 141 | case 5: 142 | FLCS = "GSP_BLAKE"; 143 | dwflyState = 6; 144 | break; 145 | case 6: 146 | FLCS = "GPS_ATTI"; 147 | dwflyState = 7; 148 | break; 149 | case 7: 150 | FLCS = "GPS_CL"; 151 | dwflyState = 8; 152 | break; 153 | case 8: 154 | FLCS = "GPS_HOME_LOCK"; 155 | dwflyState = 9; 156 | break; 157 | case 9: 158 | FLCS = "GPS_HOT_POINT"; 159 | dwflyState = 20; 160 | break; 161 | case 10: 162 | FLCS = "ASSISTED_TAKEOFF"; 163 | dwflyState = 30; 164 | break; 165 | case 11: 166 | FLCS = "AUTO_TAKEOFF"; 167 | dwflyState = 40; 168 | break; 169 | case 12: 170 | FLCS = "AUTO_LANDING"; 171 | dwflyState = 50; 172 | break; 173 | case 13: 174 | FLCS = "ATTI_LANDING"; 175 | dwflyState = 60; 176 | break; 177 | case 14: 178 | FLCS = "NAVI_GO"; 179 | dwflyState = 70; 180 | break; 181 | case 15: 182 | FLCS = "GO_HOME"; 183 | dwflyState = 80; 184 | break; 185 | case 16: 186 | FLCS = "CLICK_GO"; 187 | dwflyState = 90; 188 | break; 189 | case 17: 190 | FLCS = "JOYSTICK"; 191 | dwflyState = 200; 192 | break; 193 | case 23: 194 | FLCS = "ATTI_LIMITED"; 195 | dwflyState = 300; 196 | break; 197 | case 24: 198 | FLCS = "GPS_ATTI_LIMITED"; 199 | dwflyState = 400; 200 | break; 201 | case 25: 202 | FLCS = "FOLLOW_ME"; 203 | dwflyState = 500; 204 | break; 205 | case 100: 206 | FLCS = "OTHER"; 207 | dwflyState = 600; 208 | break; 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record44_52.java: -------------------------------------------------------------------------------- 1 | /* Record44_52 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.DatConRecs; 20 | 21 | import java.io.PrintStream; 22 | 23 | import src.Files.ConvertDat; 24 | import src.Files.Quaternion; 25 | import src.Files.RollPitchYaw; 26 | 27 | // 50 HZ 28 | // length 237 29 | public class Record44_52 extends Record { 30 | 31 | public static Record44_52 current = null; 32 | 33 | public float quatW = 0.0f; 34 | 35 | public float quatX = 0.0f; 36 | 37 | public float quatY = 0.0f; 38 | 39 | public float quatZ = 0.0f; 40 | 41 | public float yaw = 0.0f; 42 | 43 | public float roll = 0.0f; 44 | 45 | public float pitch = 0.0f; 46 | 47 | public short rFront = 0; 48 | 49 | public short lFront = 0; 50 | 51 | public short lBack = 0; 52 | 53 | public short rBack = 0; 54 | 55 | public Record44_52() { 56 | current = this; 57 | _type = 44; 58 | _subType = 52; 59 | } 60 | 61 | public void process(Payload _payload) { 62 | super.process(_payload); 63 | // 70 Float some kind of yaw? 64 | // 74 float correction for gimbal? 65 | // 54, 58, 62, 66 the same as 78, 82, 86, 90 66 | quatW = payloadBB.getFloat(78); 67 | quatX = payloadBB.getFloat(82); 68 | quatY = payloadBB.getFloat(86); 69 | quatZ = payloadBB.getFloat(90); 70 | 71 | yaw = payloadBB.getFloat(94); 72 | roll = payloadBB.getFloat(98); 73 | pitch = payloadBB.getFloat(102); 74 | 75 | rFront = payloadBB.getShort(219); 76 | lFront = payloadBB.getShort(221); 77 | lBack = payloadBB.getShort(223); 78 | rBack = payloadBB.getShort(225); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record68_17.java: -------------------------------------------------------------------------------- 1 | /* Record68_17 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.DatConRecs; 20 | 21 | import java.io.PrintStream; 22 | 23 | // 50 HZ 24 | //length 47 25 | 26 | public class Record68_17 extends Record { 27 | 28 | public static Record68_17 current = null; 29 | 30 | public Record68_17() { 31 | current = this; 32 | _type = 68; 33 | _subType = 17; 34 | } 35 | 36 | public float crrnt = (float) 0.0; 37 | 38 | public float volt1 = (float) 0.0; 39 | 40 | public float volt2 = (float) 0.0; 41 | 42 | public float volt3 = (float) 0.0; 43 | 44 | public float volt4 = (float) 0.0; 45 | 46 | public float volt5 = (float) 0.0; 47 | 48 | public float volt6 = (float) 0.0; 49 | 50 | public float temp = (float) 0.0;; 51 | 52 | public float remainingCapacity = (float) 0.0; 53 | 54 | public float ratedCapacity = (float) 0.0; 55 | 56 | public float totalVolts = (float) 0.0; 57 | 58 | public float maxVolts = (float) 0.0; 59 | 60 | public float minVolts = (float) 0.0; 61 | 62 | public float sumOfVolts = (float) 0.0; 63 | 64 | public float avgVolts = (float) 0.0; 65 | 66 | long sumOfCurrents = 0; 67 | 68 | long numSamples = 0; 69 | 70 | public float voltDiff = (float) 0.0; 71 | 72 | public float maxCurrent = (float) 0.0; 73 | 74 | public float minCurrent = (float) 0.0; 75 | 76 | public float avgCurrent = (float) 0.0; 77 | 78 | public float watts = (float) 0.0; 79 | 80 | public float maxWatts = (float) 0.0; 81 | 82 | public float minWatts = (float) 0.0; 83 | 84 | float sumOfWatts = (float) 0.0; 85 | 86 | public float avgWatts = (float) 0.0; 87 | 88 | public int relativeCapacity; 89 | 90 | private void init() { 91 | maxVolts = (float) -1.0; 92 | minVolts = Float.MAX_VALUE; 93 | minCurrent = Float.MAX_VALUE; 94 | avgCurrent = (float) 0.0; 95 | maxWatts = (float) -1.0; 96 | minWatts = Float.MAX_VALUE; 97 | } 98 | 99 | public void process(Payload _payload) { 100 | super.process(_payload); 101 | if (numSamples == 0) { // first time 102 | init(); 103 | } 104 | numSamples++; 105 | ratedCapacity = (float) (((float) (payloadBB.getShort(2)))); 106 | remainingCapacity = (float) (((float) (payloadBB.getShort(4)))); 107 | totalVolts = (float) (((float) (payloadBB.getShort(6))) / 1000.0); 108 | crrnt = -(float) (((float) (_payload.getUnsignedShort(8) - 65536)) / 1000.0); 109 | relativeCapacity = payloadBB.get(11); 110 | temp = (float) (((float) (payloadBB.get(12)))); 111 | volt1 = (float) (((float) (payloadBB.getShort(18))) / 1000.0); 112 | volt2 = (float) (((float) (payloadBB.getShort(20))) / 1000.0); 113 | volt3 = (float) (((float) (payloadBB.getShort(22))) / 1000.0); 114 | volt4 = (float) (((float) (payloadBB.getShort(24))) / 1000.0); 115 | volt5 = (float) (((float) (payloadBB.getShort(26))) / 1000.0); 116 | volt6 = (float) (((float) (payloadBB.getShort(28))) / 1000.0); 117 | if (Record255_1.current.inspire1) { 118 | float voltMax = Math.max( 119 | volt1, 120 | Math.max( 121 | volt2, 122 | Math.max(volt3, 123 | Math.max(volt4, Math.max(volt5, volt6))))); 124 | float voltMin = Math.min( 125 | volt1, 126 | Math.min( 127 | volt2, 128 | Math.min(volt3, 129 | Math.min(volt4, Math.min(volt5, volt6))))); 130 | voltDiff = voltMax - voltMin; 131 | } else { 132 | float voltMax = Math.max(volt1, 133 | Math.max(volt2, Math.max(volt3, volt4))); 134 | float voltMin = Math.min(volt1, 135 | Math.min(volt2, Math.min(volt3, volt4))); 136 | voltDiff = voltMax - voltMin; 137 | } 138 | if (totalVolts > maxVolts) 139 | maxVolts = totalVolts; 140 | if (totalVolts < minVolts) 141 | minVolts = totalVolts; 142 | sumOfVolts += totalVolts; 143 | avgVolts = sumOfVolts / (float) numSamples; 144 | 145 | if (crrnt > maxCurrent) 146 | maxCurrent = crrnt; 147 | if (crrnt < minCurrent) 148 | minCurrent = crrnt; 149 | sumOfCurrents += crrnt; 150 | avgCurrent = sumOfCurrents / (float) numSamples; 151 | 152 | watts = totalVolts * crrnt; 153 | if (watts > maxWatts) 154 | maxWatts = watts; 155 | if (watts < minWatts) 156 | minWatts = watts; 157 | sumOfWatts += watts; 158 | avgWatts = sumOfWatts / (float) numSamples; 159 | } 160 | 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/src/DatConRecs/Record92_3.java: -------------------------------------------------------------------------------- 1 | /* Record92_3 class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | package src.DatConRecs; 21 | 22 | import java.io.PrintStream; 23 | 24 | // offset 28 float height vps in meters <================= 25 | // offset 32 Short validity of height 0 not valid, 190 and over valid 26 | // 34 40 non-GPS 36 compass error 27 | public class Record92_3 extends Record { 28 | 29 | public static Record92_3 current = null; 30 | 31 | // 200 Hz 32 | // width 44 33 | public float vpsHeight = 0f; 34 | 35 | public short vpsQuality = 0; 36 | 37 | public byte errorStatus = 0x00; 38 | 39 | public Record92_3() { 40 | current = this; 41 | _type = 92; 42 | _subType = 3; 43 | } 44 | 45 | public void process(Payload _payload) { 46 | super.process(_payload); 47 | payloadBB = _payload.getBB(); 48 | vpsHeight = payloadBB.getFloat(28); 49 | vpsQuality = payloadBB.getShort(32); 50 | errorStatus = payloadBB.get(34); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/src/Files/AnalyzeDatResults.java: -------------------------------------------------------------------------------- 1 | /* AnalyzeDatResults class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.Files; 20 | 21 | import src.Files.AnalyzeDatResults.ResultCode; 22 | 23 | public class AnalyzeDatResults { 24 | public enum ResultCode { 25 | NO_ERRORS, SOME_ERRORS, CORRUPTED, NOT_DAT 26 | } 27 | 28 | private ResultCode resultCode = ResultCode.NO_ERRORS; 29 | 30 | private String messages = ""; 31 | 32 | public void setResultCode(ResultCode _resultCode) { 33 | resultCode = _resultCode; 34 | } 35 | 36 | public void addMessage(String msg) { 37 | messages += msg; 38 | } 39 | 40 | public void resetMessages() { 41 | messages = ""; 42 | } 43 | 44 | public ResultCode getResultCode() { 45 | return resultCode; 46 | } 47 | 48 | public String getMessages() { 49 | return messages; 50 | } 51 | 52 | public String toString() { 53 | String retv = ""; 54 | switch (resultCode) { 55 | case NO_ERRORS: 56 | retv += ""; 57 | break; 58 | case SOME_ERRORS: 59 | retv += "Warnings:\n"; 60 | break; 61 | case CORRUPTED: 62 | retv += "Corrupted File\n"; 63 | break; 64 | case NOT_DAT: 65 | retv += "Not a .DAT file\n"; 66 | break; 67 | } 68 | retv += messages; 69 | return retv; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/src/Files/BadArguments.java: -------------------------------------------------------------------------------- 1 | /* BadArguments class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | package src.Files; 21 | 22 | public class BadArguments extends Exception { 23 | 24 | String cause = ""; 25 | 26 | public BadArguments(String _cause) { 27 | cause = _cause; 28 | } 29 | 30 | public String getMsg() { 31 | return "Bad Arguments " + cause; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/src/Files/CLIDatCon.java: -------------------------------------------------------------------------------- 1 | package src.Files; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.PrintStream; 6 | 7 | import src.Files.AnalyzeDatResults; 8 | import src.Files.ConvertDat; 9 | import src.Files.DatFile; 10 | import src.Files.NotDatFile; 11 | 12 | public class CLIDatCon { 13 | private static String version = "2.3.1"; 14 | 15 | public static void main(String[] args) { 16 | String datFileName = ""; 17 | String csvFileName = ""; 18 | if (args.length == 0) { 19 | System.out.println(version); 20 | System.exit(0); 21 | } 22 | if (args.length != 2) { 23 | System.out.println("BadArgs"); 24 | System.exit(0); 25 | } 26 | datFileName = args[0]; 27 | csvFileName = args[1]; 28 | 29 | File csvFile = new File(csvFileName); 30 | DatFile datFile; 31 | long timeOffset = 0; 32 | try { 33 | datFile = new DatFile(datFileName); 34 | ConvertDat convertDat = new ConvertDat(datFile); 35 | datFile.findMarkers(); 36 | if (datFile.motorStartTick != 0) { 37 | timeOffset = datFile.motorStartTick; 38 | } 39 | if (datFile.flightStartTick != -1) { 40 | timeOffset = datFile.flightStartTick; 41 | } 42 | convertDat.timeOffset = timeOffset; 43 | datFile.reset(); 44 | convertDat.createRecords(); 45 | convertDat.sampleRate = 30; 46 | PrintStream csvPS = new PrintStream(csvFile); 47 | convertDat.csvPS = csvPS; 48 | AnalyzeDatResults results = convertDat.analyze(true); 49 | csvPS.close(); 50 | System.out.println("OK"); 51 | } catch (IOException | NotDatFile e) { 52 | e.printStackTrace(); 53 | } catch (FileEnd e) { 54 | // TODO Auto-generated catch block 55 | e.printStackTrace(); 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/src/Files/ConvertDat.java: -------------------------------------------------------------------------------- 1 | /* ConvertDat class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | package src.Files; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | import java.io.PrintStream; 25 | import java.util.ArrayList; 26 | 27 | import src.DatConRecs.*; 28 | 29 | public class ConvertDat { 30 | 31 | public final static boolean EXPERIMENTAL = false; 32 | static public final String version = "2.3.1"; 33 | 34 | public DatFile _datFile = null; 35 | 36 | private FileEnd _fileEnd = new FileEnd(); 37 | 38 | public ConvertDat(DatFile datFile) { 39 | _datFile = datFile; 40 | } 41 | 42 | public ConvertDat() { 43 | } 44 | 45 | long tickNo = 0; 46 | 47 | public long tickRangeLower = 0; 48 | 49 | public long tickRangeUpper = Long.MAX_VALUE; 50 | 51 | public float sampleRate = (float) 600.0; 52 | 53 | public long timeOffset = 0; 54 | 55 | public Record records[] = null; 56 | 57 | public int kmlType = -1; // -1 = none, 0 = groundTrack, 1 = profile 58 | 59 | public File kmlFile; 60 | 61 | public String kmlFileName; 62 | 63 | public float homePointElevation = 0.0f; 64 | 65 | public boolean csvEventLogOutput = false; 66 | 67 | public PrintStream eloPS = null; 68 | 69 | public PrintStream cloPS = null; 70 | 71 | public PrintStream kmlPS = null; 72 | 73 | public PrintStream csvPS = null; 74 | 75 | public PrintStream tloPS = null; 76 | private boolean printVersion; 77 | 78 | public AnalyzeDatResults analyze(boolean printVersion) throws IOException { 79 | this.printVersion = printVersion; 80 | int sampleSize = (int) (600.0 / sampleRate); 81 | try { 82 | _datFile.setStartOfRecord(128); 83 | long fileLength = _datFile.getLength(); 84 | // If there is a .csv being produced go ahead and output 85 | // the first row containing the column headings 86 | if (csvPS != null) { 87 | csvPS.print("Tick#,offsetTime"); 88 | printCsvLine(csvPS, lineType.HEADER); 89 | } 90 | long lastTickNoPrinted = -sampleSize; 91 | // Main loop that gets a tick#Group and processes all the records in 92 | // that group 93 | while (true) { 94 | if (_datFile.getPos() > fileLength - 8) { 95 | throw (_fileEnd); 96 | } 97 | // Get the next tick#Group 98 | DatFile.tickGroup tG = _datFile.getTickGroup(); 99 | boolean processedSomePayloads = false; 100 | tickNo = tG.tickNo; 101 | if (tickNo <= tickRangeUpper) { 102 | for (int tgIndex = 0; tgIndex < tG.numElements; tgIndex++) { 103 | int payloadType = tG.payloadType[tgIndex]; 104 | long payloadStart = tG.start[tgIndex]; 105 | int payloadLength = tG.length[tgIndex]; 106 | short subType = tG.subType[tgIndex]; 107 | for (int i = 0; i < records.length; i++) { 108 | // For each record found in this tick#Group is it 109 | // something 110 | // that we want to process 111 | if (records[i].isType(payloadType, subType)) { 112 | Payload payload = new Payload(_datFile, 113 | payloadStart, payloadLength, 114 | payloadType, subType, tickNo); 115 | ((Record) records[i]).process(payload); 116 | processedSomePayloads = true; 117 | } 118 | } 119 | } 120 | if (tickRangeLower <= tickNo) { 121 | // if some payloads in this tick#Group were processed 122 | // then output the .csv line 123 | if ((csvPS != null) && processedSomePayloads 124 | && tickNo >= lastTickNoPrinted + sampleSize) { 125 | csvPS.print(tickNo + "," 126 | + Util.timeString(tickNo, timeOffset)); 127 | printCsvLine(csvPS, lineType.LINE); 128 | lastTickNoPrinted = tickNo; 129 | } 130 | } 131 | } 132 | } 133 | } catch (FileEnd ex) { 134 | } catch (Corrupted ex) { 135 | } 136 | return _datFile.getResults(); 137 | } 138 | 139 | private enum lineType { 140 | HEADER, LINE 141 | }; 142 | 143 | private void printCsvValue(String header, float value, lineType lineT, 144 | boolean valid) { 145 | if (lineT == lineType.HEADER) { 146 | csvPS.print("," + header); 147 | } else { 148 | csvPS.print(","); 149 | if (valid) 150 | csvPS.print(value); 151 | } 152 | } 153 | 154 | private void printCsvValue(String header, double value, lineType lineT, 155 | boolean valid) { 156 | if (lineT == lineType.HEADER) { 157 | csvPS.print("," + header); 158 | } else { 159 | csvPS.print(","); 160 | if (valid) 161 | csvPS.print(value); 162 | } 163 | } 164 | 165 | private void printCsvValue(String header, int value, lineType lineT, 166 | boolean valid) { 167 | if (lineT == lineType.HEADER) { 168 | csvPS.print("," + header); 169 | } else { 170 | csvPS.print(","); 171 | if (valid) 172 | csvPS.print(value); 173 | } 174 | } 175 | 176 | private void printCsvValue(String header, String value, lineType lineT, 177 | boolean valid) { 178 | if (lineT == lineType.HEADER) { 179 | csvPS.print("," + header); 180 | } else { 181 | csvPS.print(","); 182 | if (valid) 183 | csvPS.print(value); 184 | } 185 | } 186 | 187 | double lastLatRad = 0.0; 188 | double lastLongRad = 0.0; 189 | long lastTickNo = 0; 190 | private boolean notFirstLine = false; 191 | 192 | private void printCsvLine(PrintStream _csv, lineType lineT) { 193 | if (lineT == lineType.HEADER) 194 | notFirstLine = false; 195 | // Rec207 196 | float vel = (float) Math.sqrt(Record207.current.velN 197 | * Record207.current.velN + Record207.current.velE 198 | * Record207.current.velE + Record207.current.velD 199 | * Record207.current.velD); 200 | float velH = (float) Math.sqrt(Record207.current.velN 201 | * Record207.current.velN + Record207.current.velE 202 | * Record207.current.velE); 203 | float magMod = (int) Math.sqrt(Record207.current.magX 204 | * Record207.current.magX + Record207.current.magY 205 | * Record207.current.magY + Record207.current.magZ 206 | * Record207.current.magZ); 207 | float error = (float) Math.sqrt(Record207.current.diffX 208 | * Record207.current.diffX + Record207.current.diffY 209 | * Record207.current.diffY + Record207.current.diffZ 210 | * Record207.current.diffZ); 211 | float accel = (float) Math.sqrt(Record207.current.accelX 212 | * Record207.current.accelX + Record207.current.accelY 213 | * Record207.current.accelY + Record207.current.accelZ 214 | * Record207.current.accelZ); 215 | float gyro = (float) Math.sqrt(Record207.current.gyroX 216 | * Record207.current.gyroX + Record207.current.gyroY 217 | * Record207.current.gyroY + Record207.current.gyroZ 218 | * Record207.current.gyroZ); 219 | Quaternion q = new Quaternion(Record207.current.quatW, 220 | Record207.current.quatX, Record207.current.quatY, 221 | Record207.current.quatZ); 222 | double[] eulerAngs = q.toEuler(); 223 | double pitch = Math.toDegrees(eulerAngs[0]); 224 | double roll = Math.toDegrees(eulerAngs[1]); 225 | double yaw = Math.toDegrees(eulerAngs[2]); 226 | printCsvValue("flightTime(msec)", Record42_12.current.flightTime, 227 | lineT, true); 228 | double longitude = Math.toDegrees(Record207.current.longRad); 229 | double latitude = Math.toDegrees(Record207.current.latRad); 230 | boolean coordsValid = false; 231 | if (longitude != 0.0 && latitude != 0.0 && Math.abs(longitude) > 0.0175 232 | && Math.abs(latitude) > 0.0175) { 233 | coordsValid = true; 234 | } 235 | printCsvValue("Longitude", longitude, lineT, coordsValid); 236 | printCsvValue("Latitude", latitude, lineT, coordsValid); 237 | printCsvValue("numSats", Record207.current.numSats, lineT, true); 238 | printCsvValue("gpsHealth", Record152_0.current.gpsHealth, lineT, true); 239 | printCsvValue("gpsAltitude(meters)", Record207.current.gpsAlt, lineT, 240 | true); 241 | printCsvValue("baroAlt(meters)", Record207.current.baroAlt, lineT, true); 242 | printCsvValue("vpsHeight(M)", Record92_3.current.vpsHeight, lineT, 243 | (Record92_3.current.vpsQuality > 190)); 244 | printCsvValue("relativeHeight", Record42_12.current.height, lineT, true); 245 | printCsvValue("accelX(M/S2)", Record207.current.accelX, lineT, true); 246 | printCsvValue("accelY(M/S2)", Record207.current.accelY, lineT, true); 247 | printCsvValue("accelZ(M/S2)", Record207.current.accelZ, lineT, true); 248 | printCsvValue("accel(M/S2)", accel, lineT, true); 249 | printCsvValue("gyroX(degrees/s)", Record207.current.gyroX, lineT, true); 250 | printCsvValue("gyroY(degrees/s)", Record207.current.gyroY, lineT, true); 251 | printCsvValue("gyroZ(degrees/s)", Record207.current.gyroZ, lineT, true); 252 | printCsvValue("gyro(degrees/s)", gyro, lineT, true); 253 | 254 | printCsvValue("errorX", Record207.current.diffX, lineT, true); 255 | printCsvValue("errorY", Record207.current.diffY, lineT, true); 256 | printCsvValue("errorZ", Record207.current.diffZ, lineT, true); 257 | printCsvValue("error", error, lineT, true); 258 | 259 | printCsvValue("magX", Record207.current.magX, lineT, true); 260 | printCsvValue("magY", Record207.current.magY, lineT, true); 261 | printCsvValue("magZ", Record207.current.magZ, lineT, true); 262 | printCsvValue("magMod", magMod, lineT, true); 263 | printCsvValue("velN(M/S)", Record207.current.velN, lineT, true); 264 | printCsvValue("velE(M/S)", Record207.current.velE, lineT, true); 265 | printCsvValue("velD(M/S)", Record207.current.velD, lineT, true); 266 | printCsvValue("vel(M/S)", vel, lineT, true); 267 | printCsvValue("velH(M/S)", velH, lineT, true); 268 | double velGPS = 0.0; 269 | if (lineT == lineType.HEADER) { 270 | printCsvValue("velGPS-velH(M/S)", 0.0, lineT, true); 271 | } else { 272 | if (notFirstLine) { 273 | double distance = Util.distance(Record207.current.latRad, 274 | Record207.current.longRad, lastLatRad, lastLongRad); 275 | velGPS = distance / (((double) (tickNo - lastTickNo)) / 600.0); 276 | } else { 277 | velGPS = 0.0; 278 | } 279 | lastLatRad = Record207.current.latRad; 280 | lastLongRad = Record207.current.longRad; 281 | printCsvValue("velGPS-velH(M/S)", velGPS - velH, lineT, true); 282 | } 283 | 284 | printCsvValue("quatW", Record207.current.quatW, lineT, true); 285 | printCsvValue("quatX", Record207.current.quatX, lineT, true); 286 | printCsvValue("quatY", Record207.current.quatY, lineT, true); 287 | printCsvValue("quatZ", Record207.current.quatZ, lineT, true); 288 | 289 | printCsvValue("Roll", roll, lineT, true); 290 | printCsvValue("Pitch", pitch, lineT, true); 291 | printCsvValue("Yaw", yaw, lineT, true); 292 | printCsvValue("Yaw360", ((yaw + 360.0) % 360.0), lineT, true); 293 | 294 | printCsvValue("totalGyroZ", Record207.current.totalZGyro, lineT, true); 295 | if (lineT == lineType.HEADER) { 296 | printCsvValue("magYaw", 0.0, lineT, true); 297 | } else { 298 | Quaternion qAcc = Quaternion.fromAngles(eulerAngs[0], eulerAngs[1], 299 | 0.0); 300 | double magX = Record207.current.magX; 301 | double magY = Record207.current.magY; 302 | double magZ = Record207.current.magZ; 303 | Quaternion x = new Quaternion(0.0, magX, magY, magZ); 304 | Quaternion magXYPlane = qAcc.times(x).times(qAcc.conjugate()); 305 | double X = magXYPlane.getX(); 306 | double Y = magXYPlane.getY(); 307 | double magYaw = Math.toDegrees(-Math.atan2(Y, X)); 308 | printCsvValue("magYawX", magYaw, lineT, true); 309 | } 310 | 311 | double lbrfDiff = Record218_241.current.lBackSpeed 312 | - Record218_241.current.rFrontSpeed; 313 | double rblfDiff = Record218_241.current.rBackSpeed 314 | - Record218_241.current.lFrontSpeed; 315 | 316 | double thrust1 = Math.toDegrees(Math.atan2(lbrfDiff, rblfDiff)); 317 | double thrust2 = (thrust1 + 315.0) % 360.0; 318 | double thrustTheta = thrust2; 319 | if (thrust2 > 180.0) { 320 | thrustTheta = thrust2 - 360.0; 321 | } 322 | printCsvValue("thrustAngle", thrustTheta, lineT, true); 323 | 324 | double distanceHP = Util.distance(Record207.current.latRad, 325 | Record207.current.longRad, Record255_1.current.latitudeHP, 326 | Record255_1.current.longitudeHP); 327 | printCsvValue("homePointLongitude", 328 | Record255_1.current.longitudeHPDegrees, lineT, 329 | (Record255_1.current.validHP)); 330 | printCsvValue("homePointLatitude", 331 | Record255_1.current.latitudeHPDegrees, lineT, 332 | (Record255_1.current.validHP)); 333 | printCsvValue("homePointAltitude", Record255_1.current.heightHP, lineT, 334 | (Record255_1.current.validHP)); 335 | printCsvValue("geoMagDeclination", Record255_1.current.declination, 336 | lineT, (Record255_1.current.validHP)); 337 | printCsvValue("geoMagInclination", Record255_1.current.inclination, 338 | lineT, (Record255_1.current.validHP)); 339 | printCsvValue("distancHP(M)", distanceHP, lineT, 340 | (Record255_1.current.validHP)); 341 | 342 | printCsvValue("distanceTravelled(M)", 343 | Record207.current.distanceTraveled, lineT, true); 344 | printCsvValue("directionOfTravel", Record207.current.bearingDeclined, 345 | lineT, true); 346 | printCsvValue("directionOfTravelTrue", Record207.current.bearingTrue, 347 | lineT, true); 348 | printCsvValue("IMUTemp(C)", Record207.current.imuTemp, lineT, true); 349 | 350 | // Rec42_12 351 | Record42_12.current.setStateStrings(); 352 | printCsvValue("flyCState", Record42_12.current.flyc_state, lineT, true); 353 | printCsvValue("flyCState:String", Record42_12.current.FLCS, lineT, true); 354 | printCsvValue("nonGPSCause", Record42_12.current.nonGPSError, lineT, 355 | true); 356 | printCsvValue("nonGPSCause:String", Record42_12.current.NGPE, lineT, 357 | true); 358 | printCsvValue("DW flyCState", Record42_12.current.dwflyState, lineT, 359 | true); 360 | 361 | int connectedToRC = 0; 362 | if (Record42_12.current.connectedToRC == 0) { 363 | connectedToRC = 1; 364 | } 365 | printCsvValue("conectedToRC", connectedToRC, lineT, true); 366 | 367 | if (ConvertDat.EXPERIMENTAL) { 368 | printCsvValue("X:Roll", Record42_12.current.roll, lineT, true); 369 | printCsvValue("X:Pitch", Record42_12.current.pitch, lineT, true); 370 | printCsvValue("X:Yaw", Record42_12.current.yaw, lineT, true); 371 | printCsvValue("motorStartFailure", 372 | String.format("%02X", Record42_12.current.failure), lineT, 373 | true); 374 | 375 | } 376 | // Rec68_17 Battery Stuff 377 | printCsvValue("Current", Record68_17.current.crrnt, lineT, true); 378 | printCsvValue("Volt1", Record68_17.current.volt1, lineT, true); 379 | printCsvValue("Volt2", Record68_17.current.volt2, lineT, true); 380 | printCsvValue("Volt3", Record68_17.current.volt3, lineT, true); 381 | printCsvValue("Volt4", Record68_17.current.volt4, lineT, true); 382 | 383 | printCsvValue("Volt5", Record68_17.current.volt5, lineT, 384 | (Record255_1.current.inspire1)); 385 | printCsvValue("Volt6", Record68_17.current.volt6, lineT, 386 | (Record255_1.current.inspire1)); 387 | 388 | printCsvValue("totalVolts", Record68_17.current.totalVolts, lineT, true); 389 | printCsvValue("voltSpread", Record68_17.current.voltDiff, lineT, true); 390 | printCsvValue("Watts", Record68_17.current.watts, lineT, true); 391 | printCsvValue("batteryTemp(C)", Record68_17.current.temp, lineT, true); 392 | printCsvValue("ratedCapacity", Record68_17.current.ratedCapacity, 393 | lineT, true); 394 | printCsvValue("remaingCapacity", Record68_17.current.remainingCapacity, 395 | lineT, true); 396 | printCsvValue("percentageCapacity", 397 | Record68_17.current.relativeCapacity, lineT, true); 398 | 399 | printCsvValue("usefulTime", Record30_18.current.batteryUsefulTime, 400 | lineT, (Record30_18.current.validBUT)); 401 | 402 | printCsvValue("percentageVolts", Record30_18.current.voltagePercent, 403 | lineT, (Record30_18.current.validVP)); 404 | 405 | printCsvValue("batteryCycleCount", 406 | Record255_2.current.batteryCycleCount, lineT, true); 407 | printCsvValue("batteryLifePercentage", 408 | Record255_2.current.batteryPercentage, lineT, true); 409 | printCsvValue("batteryBarCode", Record255_1.current.batteryBarCode, 410 | lineT, true); 411 | 412 | printCsvValue("minCurrent", Record68_17.current.minCurrent, lineT, true); 413 | printCsvValue("maxCurrent", Record68_17.current.maxCurrent, lineT, true); 414 | printCsvValue("avgCurrent", Record68_17.current.avgCurrent, lineT, true); 415 | 416 | printCsvValue("minVolts", Record68_17.current.minVolts, lineT, true); 417 | printCsvValue("maxVolts", Record68_17.current.maxVolts, lineT, true); 418 | printCsvValue("avgVolts", Record68_17.current.avgVolts, lineT, true); 419 | 420 | printCsvValue("minWatts", Record68_17.current.minWatts, lineT, true); 421 | printCsvValue("maxWatts", Record68_17.current.maxWatts, lineT, true); 422 | printCsvValue("avgWatts", Record68_17.current.avgWatts, lineT, true); 423 | 424 | // Rec44_52 425 | printCsvValue("Gimbal:roll", Math.toDegrees(Record44_52.current.roll), 426 | lineT, true); 427 | printCsvValue("Gimbal:pitch", 428 | Math.toDegrees(Record44_52.current.pitch), lineT, true); 429 | printCsvValue("Gimbal:yaw", Math.toDegrees(Record44_52.current.yaw), 430 | lineT, true); 431 | 432 | Quaternion qGimbal = new Quaternion(Record44_52.current.quatW, 433 | Record44_52.current.quatX, Record44_52.current.quatY, 434 | Record44_52.current.quatZ); 435 | RollPitchYaw rpy = qGimbal.toRollPitchYaw(); 436 | printCsvValue("Gimbal:Xroll", rpy.getRollDeg(), lineT, true); 437 | printCsvValue("Gimbal:Xpitch", rpy.getPitchDeg(), lineT, true); 438 | printCsvValue("Gimbal:Xyaw", rpy.getYawDeg(), lineT, true); 439 | 440 | printCsvValue("MotorCmnd:RFront", Record44_52.current.rFront, lineT, 441 | true); 442 | printCsvValue("MotorCmnd:LFront", Record44_52.current.lFront, lineT, 443 | true); 444 | printCsvValue("MotorCmnd:LBack", Record44_52.current.lBack, lineT, true); 445 | printCsvValue("MotorCmnd:RBack", Record44_52.current.rBack, lineT, true); 446 | 447 | // Rec218_241 448 | printCsvValue("MotorSpeed:RFront", Record218_241.current.rFrontSpeed, 449 | lineT, !(Record255_1.current.standard)); 450 | printCsvValue("MotorSpeed:LFront", Record218_241.current.lFrontSpeed, 451 | lineT, !(Record255_1.current.standard)); 452 | printCsvValue("MotorSpeed:LBack", Record218_241.current.lBackSpeed, 453 | lineT, !(Record255_1.current.standard)); 454 | printCsvValue("MotorSpeed:RBack", Record218_241.current.rBackSpeed, 455 | lineT, !(Record255_1.current.standard)); 456 | printCsvValue("MotorLoad:RFront", Record218_241.current.rFrontLoad, 457 | lineT, !(Record255_1.current.standard)); 458 | printCsvValue("MotorLoad:LFront", Record218_241.current.lFrontLoad, 459 | lineT, !(Record255_1.current.standard)); 460 | printCsvValue("MotorLoad:LBack", Record218_241.current.lBackLoad, 461 | lineT, !(Record255_1.current.standard)); 462 | printCsvValue("MotorLoad:RBack", Record218_241.current.rBackLoad, 463 | lineT, !(Record255_1.current.standard)); 464 | 465 | // Rec152_0 466 | printCsvValue("Control:Aileron", Record152_0.current.aileron, lineT, 467 | true); 468 | printCsvValue("Control:Elevator", Record152_0.current.elevator, lineT, 469 | true); 470 | printCsvValue("Control:Throttle", Record152_0.current.throttle, lineT, 471 | true); 472 | printCsvValue("Control:Rudder", Record152_0.current.rudder, lineT, true); 473 | printCsvValue("Control:ModeSwitch", Record152_0.current.modeSwitch, 474 | lineT, true); 475 | 476 | if (ConvertDat.EXPERIMENTAL) { 477 | printCsvValue("ContrlLinkQual", Record152_0.current.clq, lineT, 478 | (Record152_0.current.clqHasValue)); 479 | 480 | } 481 | 482 | printCsvValue( 483 | "tabletLongitude", 484 | Record193_43.current.longitudeTablet, 485 | lineT, 486 | (Record193_43.current.valid && Record42_12.current.flyc_state == 25)); 487 | printCsvValue( 488 | "tabletLatitude", 489 | Record193_43.current.latitudeTablet, 490 | lineT, 491 | (Record193_43.current.valid && Record42_12.current.flyc_state == 25)); 492 | 493 | // Rec92_3 494 | if (ConvertDat.EXPERIMENTAL) { 495 | printCsvValue("errorStatus", Record92_3.current.errorStatus, lineT, 496 | true); 497 | } 498 | 499 | String model = ""; 500 | if (Record255_1.current.P3) { 501 | model = "P3Adv/Pro"; 502 | } else if (Record255_1.current.inspire1) { 503 | model = "Inspire1"; 504 | } else if (Record255_1.current.standard) { 505 | model = "P3Standard"; 506 | } 507 | 508 | printCsvValue("A/C model", model, lineT, true); 509 | if (csvEventLogOutput) { 510 | String noComma = Record255_1.current.text.replaceAll(",", "."); 511 | printCsvValue("eventLog", noComma, lineT, true); 512 | Record255_1.current.text = ""; 513 | } 514 | if (printVersion) { 515 | printCsvValue(version, "", lineT, false); 516 | } 517 | _csv.println(); 518 | if (lineT == lineType.LINE) { 519 | notFirstLine = true; 520 | lastTickNo = tickNo; 521 | } 522 | } 523 | 524 | public void setRecords(Record[] recs) { 525 | records = recs; 526 | } 527 | 528 | public void setSampleRate(float sampleRate) { 529 | this.sampleRate = sampleRate; 530 | } 531 | 532 | public void createRecords() { 533 | ArrayList recordsList = new ArrayList(); 534 | recordsList = new ArrayList(); 535 | recordsList.add(new Record207()); 536 | recordsList.add(new Record42_12(this)); 537 | recordsList.add(new Record68_17()); 538 | recordsList.add(new Record44_52()); 539 | recordsList.add(new Record218_241()); 540 | recordsList.add(new Record152_0()); 541 | recordsList.add(new Record30_18()); 542 | recordsList.add(new Record198_13()); 543 | recordsList.add(new Record193_43()); 544 | recordsList.add(new Record92_3()); 545 | // recordsList.add(new Record187_7()); 546 | recordsList.add(new Record255_1(this)); 547 | recordsList.add(new Record255_2(this)); 548 | 549 | records = new Record[recordsList.size()]; 550 | for (int i = 0; i < recordsList.size(); i++) { 551 | records[i] = recordsList.get(i); 552 | } 553 | } 554 | 555 | } 556 | -------------------------------------------------------------------------------- /src/src/Files/Corrupted.java: -------------------------------------------------------------------------------- 1 | /* Corrupted class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.Files; 20 | 21 | public class Corrupted extends Exception { 22 | long tickNo = 0; 23 | 24 | long filePos = 0; 25 | 26 | public Corrupted(long _tickNo, long _filePos) { 27 | tickNo = _tickNo; 28 | filePos = _filePos; 29 | } 30 | public Corrupted() { 31 | 32 | } 33 | 34 | public String toString() { 35 | return "Partial or missing record at or near tickNo " + tickNo 36 | + ", file Position " + filePos; 37 | } 38 | 39 | public long getFilePos() { 40 | return filePos; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/src/Files/DatFile.java: -------------------------------------------------------------------------------- 1 | /* DatFile class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.Files; 20 | 21 | import java.io.File; 22 | import java.io.FileInputStream; 23 | import java.io.IOException; 24 | import java.nio.ByteOrder; 25 | import java.nio.MappedByteBuffer; 26 | import java.nio.channels.FileChannel; 27 | 28 | import src.DatConRecs.Payload; 29 | 30 | public class DatFile { 31 | 32 | final static int headerLength = 10; 33 | 34 | MappedByteBuffer memory = null; 35 | 36 | private long filePos = 0; 37 | 38 | File file = null; 39 | 40 | FileInputStream inputStream = null; 41 | 42 | FileChannel _channel = null; 43 | 44 | long fileLength = 0; 45 | 46 | public String buildStr = ""; 47 | 48 | long nextFilPos = 128; //beginning filePos of next tick group 49 | 50 | int nextTickGroup = 0; //tickNo of next group 51 | 52 | protected FileEnd _fileEnd = new FileEnd(); 53 | 54 | int numCorrupted = 0; 55 | 56 | AnalyzeDatResults results = null; 57 | 58 | long startOfRecord = 0; 59 | 60 | public long lowestTickNo = -1; 61 | 62 | public long highestTickNo = -1; 63 | 64 | public long motorStartTick = 0; 65 | 66 | public long motorStopTick = -1; 67 | 68 | public long flightStartTick = -1; 69 | 70 | public long gpsLockTick = -1; 71 | 72 | public void reset() throws FileEnd, IOException { 73 | tickGroups[0].reset(); 74 | tickGroups[1].reset(); 75 | tgIndex = 1; 76 | numCorrupted = 0; 77 | results = new AnalyzeDatResults(); 78 | startOfRecord = 128; 79 | setPosition(startOfRecord); 80 | } 81 | 82 | public class tickGroup { 83 | public int numElements = 0; 84 | 85 | public long start[] = new long[30]; 86 | 87 | public short subType[] = new short[30]; 88 | 89 | public byte msgs[] = new byte[30]; 90 | 91 | public int length[] = new int[30]; 92 | 93 | public short payloadType[] = new short[30]; 94 | 95 | public int tickNo = -1; 96 | 97 | public void reset() { 98 | numElements = 0; 99 | tickNo = -1; 100 | } 101 | 102 | public void add(int _tickNo, long _start, int _length, short _ptType, 103 | short _subType, byte _msgs) { 104 | numElements++; 105 | tickNo = _tickNo; 106 | start[numElements - 1] = _start; 107 | length[numElements - 1] = _length; 108 | payloadType[numElements - 1] = _ptType; 109 | subType[numElements - 1] = _subType; 110 | msgs[numElements - 1] = _msgs; 111 | } 112 | 113 | public void add(long _start, int _length, short _ptType, 114 | short _subType, byte _msgs) { 115 | numElements++; 116 | start[numElements - 1] = _start; 117 | length[numElements - 1] = _length; 118 | payloadType[numElements - 1] = _ptType; 119 | subType[numElements - 1] = _subType; 120 | msgs[numElements - 1] = _msgs; 121 | } 122 | } 123 | 124 | public tickGroup tickGroups[] = { new tickGroup(), new tickGroup() }; 125 | 126 | protected int tgIndex = 1; 127 | 128 | protected long lastRecordTickNo = 0; 129 | 130 | protected boolean alternateStructure = false; 131 | 132 | public tickGroup getTickGroup() throws FileEnd, Corrupted { 133 | tickGroup thisTickGroup = null; 134 | tickGroup nextTickGroup = null; 135 | if (tgIndex == 1) { 136 | tgIndex = 0; 137 | thisTickGroup = tickGroups[0]; 138 | nextTickGroup = tickGroups[1]; 139 | } else { 140 | tgIndex = 1; 141 | thisTickGroup = tickGroups[1]; 142 | nextTickGroup = tickGroups[0]; 143 | } 144 | int thisGroupsTickNo = thisTickGroup.tickNo; 145 | nextTickGroup.numElements = 0; // reset the nextTickGroup to be empty 146 | 147 | boolean done = false; 148 | int length = 0; 149 | long nextStartOfRecord = 0; 150 | while (!done) { 151 | try { 152 | setPosition(startOfRecord); 153 | if (getByte(startOfRecord) != 0x55) { // if not positioned at next 0x55, then its corrupted 154 | throw (new Corrupted(thisGroupsTickNo, startOfRecord)); 155 | } 156 | length = (0xFF & getByte(startOfRecord + 1)); 157 | byte always0 = (byte) getByte(startOfRecord + 2); 158 | short type = (short) (0xFF & getByte(startOfRecord + 3)); 159 | short subType = (short) (0xFF & getByte(startOfRecord + 4)); 160 | byte msg = (byte) getByte(startOfRecord + 5); 161 | int thisRecordTickNo = (int) getUnsignedInt(startOfRecord + 6); 162 | if (thisRecordTickNo < 0 163 | || (alternateStructure && thisRecordTickNo > 4500000) 164 | || (!alternateStructure && thisRecordTickNo > 1500000)) { 165 | throw (new Corrupted(lastRecordTickNo, startOfRecord + 1)); 166 | } 167 | lastRecordTickNo = thisRecordTickNo; 168 | if (length == 0) { 169 | throw (new Corrupted(thisGroupsTickNo, startOfRecord + 1)); 170 | } 171 | nextStartOfRecord = startOfRecord + length; // the next 0x55 , we hope 172 | if (nextStartOfRecord > fileLength) 173 | throw (_fileEnd); 174 | if (getByte(nextStartOfRecord) != 0x55) { // if not positioned at next 0x55, then its corrupted 175 | throw (new Corrupted(thisGroupsTickNo, nextStartOfRecord)); 176 | } 177 | if ((0xff & msg) == 0x80) { 178 | type = 255; 179 | subType = 1; 180 | } 181 | if ((0xff & msg) == 0xFF) { 182 | type = 255; 183 | subType = 2; 184 | } 185 | if (thisGroupsTickNo == -1) { //thisTickGroup doesn't yet have a tickNo 186 | thisGroupsTickNo = thisRecordTickNo; 187 | thisTickGroup.tickNo = thisRecordTickNo; 188 | } 189 | if (thisRecordTickNo > thisTickGroup.tickNo) { //start next group 190 | nextTickGroup.reset(); 191 | nextTickGroup.add(thisRecordTickNo, startOfRecord 192 | + headerLength, length - headerLength, type, 193 | subType, msg); 194 | done = true; 195 | } else if (thisRecordTickNo == thisTickGroup.tickNo) { 196 | thisTickGroup.add(startOfRecord + headerLength, length 197 | - headerLength, type, subType, msg); 198 | } else { // (tickNo < thisTickGroup.tickNo) in the last group 199 | //for now, just ignore 200 | } 201 | 202 | startOfRecord = nextStartOfRecord; 203 | } catch (Corrupted c) { 204 | if (getPos() > fileLength - 600) { 205 | throw (_fileEnd); 206 | } 207 | numCorrupted++; 208 | 209 | if (numCorrupted > 25) { 210 | results.setResultCode(AnalyzeDatResults.ResultCode.CORRUPTED); 211 | throw (new Corrupted(thisGroupsTickNo, startOfRecord)); 212 | } 213 | try { 214 | setPosition(c.filePos); 215 | byte fiftyfive = readByte(); 216 | while (fiftyfive != 0X55) { 217 | if (getPos() > fileLength - 1000) { 218 | throw (_fileEnd); 219 | } 220 | fiftyfive = readByte(); 221 | } 222 | } catch (Exception e) { 223 | throw (new Corrupted(thisGroupsTickNo, startOfRecord)); 224 | } 225 | //set position right before the next 0x55 226 | startOfRecord = getPos() - 1; 227 | } catch (FileEnd f) { 228 | throw (_fileEnd); 229 | } catch (Exception e) { 230 | results.setResultCode(AnalyzeDatResults.ResultCode.CORRUPTED); 231 | throw (new Corrupted(thisGroupsTickNo, startOfRecord)); 232 | } 233 | } 234 | return thisTickGroup; 235 | } 236 | 237 | public DatFile(String fileName) throws IOException, NotDatFile { 238 | this(new File(fileName)); 239 | } 240 | 241 | public DatFile(File _file) throws IOException, NotDatFile { 242 | file = _file; 243 | tickGroups[0] = new tickGroup(); 244 | tickGroups[1] = new tickGroup(); 245 | results = new AnalyzeDatResults(); 246 | fileLength = file.length(); 247 | inputStream = new FileInputStream(file); 248 | _channel = inputStream.getChannel(); 249 | memory = _channel.map(FileChannel.MapMode.READ_ONLY, 0, fileLength); 250 | memory.order(ByteOrder.LITTLE_ENDIAN); 251 | try { 252 | if (getByte(128) != 0x55) { 253 | alternateStructure = true; 254 | } 255 | } catch (FileEnd e) { 256 | close(); 257 | throw (new NotDatFile()); 258 | } 259 | buildStr = getString(16); 260 | if (buildStr.indexOf("BUILD") < 0) { 261 | close(); 262 | throw (new NotDatFile()); 263 | } 264 | } 265 | 266 | public void close() { 267 | if (inputStream != null) { 268 | try { 269 | inputStream.close(); 270 | if (inputStream.getChannel() != null) { 271 | inputStream.getChannel().close(); 272 | } 273 | } catch (IOException e) { 274 | e.printStackTrace(); 275 | } 276 | } 277 | memory = null; 278 | System.gc(); 279 | System.runFinalization(); 280 | } 281 | 282 | public void skipOver(int num) throws IOException { 283 | filePos = filePos + num; 284 | if (filePos > fileLength) 285 | throw (new IOException()); 286 | _channel.position(filePos); 287 | } 288 | 289 | public String toString() { 290 | return file.getName(); 291 | } 292 | 293 | public String bufferToString() throws FileEnd { 294 | return filePos + ":" + String.format("%02X", (0xff & getByte())) 295 | + " : " + (0xff & getByte()) + " :Shrt " + getShort() 296 | + " :UShrt " + getUnsignedShort() + " :I " + getInt() + " :UI " 297 | + getUnsignedInt() + " :L " + getLong() + " :F " + getFloat() 298 | + " :D " + getDouble(); 299 | } 300 | 301 | public void setPosition(long pos) throws FileEnd, IOException { 302 | filePos = pos; 303 | if (filePos >= fileLength) 304 | throw (new FileEnd()); 305 | _channel.position(pos); 306 | } 307 | 308 | public long getPos() { 309 | return filePos; 310 | } 311 | 312 | public long getLength() { 313 | return fileLength; 314 | } 315 | 316 | public byte getByte() { 317 | return memory.get((int) filePos); 318 | } 319 | 320 | public int getByte(long fp) throws FileEnd { 321 | if (fp >= fileLength) 322 | throw (new FileEnd()); 323 | return memory.get((int) fp); 324 | } 325 | 326 | private String getString(long fp) { 327 | int length = 256; 328 | byte bytes[] = new byte[length]; 329 | int l = 0; 330 | int B = 0x00; 331 | for (int i = 0; i < length; i++) { 332 | try { 333 | B = getByte((int) fp + i); 334 | } catch (FileEnd e) { 335 | // TODO Auto-generated catch block 336 | e.printStackTrace(); 337 | } 338 | if (B == 0x00 || B == '\r' || B == '\n') { 339 | l = i; 340 | break; 341 | } 342 | bytes[i] = (byte) B; 343 | } 344 | String retv = new String(bytes, 0, l); 345 | return retv; 346 | } 347 | 348 | public byte readByte() throws IOException { 349 | byte rv = getByte(); 350 | skipOver(1); 351 | return rv; 352 | } 353 | 354 | protected short getShort() { 355 | return memory.getShort((int) filePos); 356 | } 357 | 358 | public int getUnsignedShort() { 359 | return (int) (0xff & memory.get((int) filePos)) + 256 360 | * (int) (0xff & memory.get((int) (filePos + 1))); 361 | } 362 | 363 | private int getUnsignedShort(long fp) throws FileEnd { 364 | if (fp > fileLength - 2) 365 | throw (new FileEnd()); 366 | return (int) (0xff & memory.get((int) fp)) + 256 367 | * (int) (0xff & memory.get((int) (fp + 1))); 368 | } 369 | 370 | public int getInt() { 371 | return memory.getInt((int) filePos); 372 | } 373 | 374 | public long getUnsignedInt() throws FileEnd { 375 | return getUnsignedInt(filePos); 376 | } 377 | 378 | protected long getUnsignedInt(long fp) throws FileEnd { 379 | if (fp > fileLength - 4) 380 | throw (new FileEnd()); 381 | return (long) (0xff & memory.get((int) fp)) 382 | + (256 * (long) (0xff & memory.get((int) (fp + 1)))) 383 | + (65536 * (long) (0xff & memory.get((int) (fp + 2)))) 384 | + (65536 * 256 * (long) (0xff & memory.get((int) (fp + 3)))); 385 | } 386 | 387 | public long getLong() { 388 | return memory.getLong((int) filePos); 389 | } 390 | 391 | public float getFloat() { 392 | return memory.getFloat((int) filePos); 393 | } 394 | 395 | public double getDouble() { 396 | return memory.getDouble((int) filePos); 397 | } 398 | 399 | public AnalyzeDatResults getResults() { 400 | return results; 401 | } 402 | 403 | public File getFile() { 404 | return file; 405 | } 406 | 407 | public void setStartOfRecord(long sor) { 408 | startOfRecord = sor; 409 | } 410 | 411 | public String fileName() { 412 | String retv = "Unknown"; 413 | try { 414 | retv = file.getCanonicalPath(); 415 | } catch (IOException e) { 416 | 417 | } 418 | return retv; 419 | } 420 | 421 | public void findMarkers() { 422 | findMotorStartEnd(); 423 | findLowestTickNo(); 424 | int length = 0; 425 | boolean done = false; 426 | long nextStartOfRecord = 0; 427 | long filePos = fileLength - 200000; 428 | try { 429 | setPosition(filePos); 430 | byte fiftyfive = readByte(); 431 | while (fiftyfive != 0X55) { 432 | if (getPos() > fileLength - 1000) { 433 | throw (_fileEnd); 434 | } 435 | fiftyfive = readByte(); 436 | } 437 | filePos = getPos() - 1; 438 | while (!done) { 439 | try { 440 | setPosition(filePos); 441 | length = (0xFF & getByte(filePos + 1)); 442 | if (length == 0) { 443 | throw (new Corrupted()); 444 | } 445 | nextStartOfRecord = filePos + length; 446 | if (nextStartOfRecord > fileLength) { 447 | throw (_fileEnd); 448 | } 449 | if (getByte(nextStartOfRecord) != 0x55) { 450 | throw (new Corrupted()); 451 | } 452 | long tickNo = (int) getUnsignedInt(filePos + 6); 453 | if (lowestTickNo < 0) { 454 | lowestTickNo = tickNo; 455 | } 456 | highestTickNo = tickNo; 457 | filePos = nextStartOfRecord; 458 | } catch (Corrupted c) { 459 | setPosition(getPos() + 1); 460 | fiftyfive = readByte(); 461 | while (fiftyfive != 0X55) { 462 | if (getPos() > fileLength - 1000) { 463 | throw (_fileEnd); 464 | } 465 | fiftyfive = readByte(); 466 | } 467 | filePos = getPos() - 1; 468 | } 469 | } 470 | } catch (Exception e) { 471 | } 472 | } 473 | 474 | private void findLowestTickNo() { 475 | int length = 0; 476 | boolean done = false; 477 | long nextStartOfRecord = 0; 478 | long filePos = 128; 479 | try { 480 | setPosition(filePos); 481 | byte fiftyfive = readByte(); 482 | while (fiftyfive != 0X55) { 483 | if (getPos() > fileLength - 1000) { 484 | throw (_fileEnd); 485 | } 486 | fiftyfive = readByte(); 487 | } 488 | filePos = getPos() - 1; 489 | while (!done) { 490 | try { 491 | setPosition(filePos); 492 | length = (0xFF & getByte(filePos + 1)); 493 | if (length == 0) { 494 | throw (new Corrupted()); 495 | } 496 | nextStartOfRecord = filePos + length; 497 | if (nextStartOfRecord > fileLength) { 498 | throw (_fileEnd); 499 | } 500 | if (getByte(nextStartOfRecord) != 0x55) { 501 | throw (new Corrupted()); 502 | } 503 | long tickNo = (int) getUnsignedInt(filePos + 6); 504 | lowestTickNo = tickNo; 505 | done = true; 506 | } catch (Corrupted c) { 507 | setPosition(getPos() + 1); 508 | fiftyfive = readByte(); 509 | while (fiftyfive != 0X55) { 510 | if (getPos() > fileLength - 1000) { 511 | throw (_fileEnd); 512 | } 513 | fiftyfive = readByte(); 514 | } 515 | filePos = getPos() - 1; 516 | } 517 | } 518 | } catch (Exception e) { 519 | } 520 | } 521 | 522 | private void findMotorStartEnd() { 523 | try { 524 | reset(); 525 | long tickNo = 0; 526 | while (true) { 527 | if (getPos() > fileLength - 8) { 528 | throw (_fileEnd); 529 | } 530 | DatFile.tickGroup tG = getTickGroup(); 531 | tickNo = tG.tickNo; 532 | for (int tgIndex = 0; tgIndex < tG.numElements; tgIndex++) { 533 | short payloadType = tG.payloadType[tgIndex]; 534 | long payloadStart = tG.start[tgIndex]; 535 | int payloadLength = tG.length[tgIndex]; 536 | short subType = tG.subType[tgIndex]; 537 | if (payloadType == 255 && subType == 1) { 538 | Payload xorBB = new Payload(this, payloadStart, 539 | payloadLength, payloadType, subType, tickNo); 540 | String payloadString = xorBB.getString(); 541 | if (payloadString.indexOf("M.Start") > 0 542 | && motorStartTick == 0) { 543 | motorStartTick = tickNo; 544 | } 545 | if (payloadString.indexOf("M. Stop") > 0) { 546 | motorStopTick = tickNo; 547 | } 548 | } 549 | else if (gpsLockTick == -1 && payloadType == 42 550 | && subType == 12) { 551 | Payload payload = new Payload(this, payloadStart, 552 | payloadLength, payloadType, subType, tickNo); 553 | double longitude = Math.toDegrees(payload.getDouble(0)); 554 | double latitude = Math.toDegrees(payload.getDouble(8)); 555 | if (longitude != 0.0 && latitude != 0.0 556 | && Math.abs(longitude) > 0.0175 557 | && Math.abs(latitude) > 0.0175) { 558 | gpsLockTick = tickNo; 559 | } 560 | } else if (flightStartTick == -1 && payloadType == 42 561 | && subType == 12) { 562 | Payload payload = new Payload(this, payloadStart, 563 | payloadLength, payloadType, subType, tickNo); 564 | if (payload.getShort(42) > 0) { 565 | flightStartTick = tickNo 566 | - (long) (0.6f * ((float) (payload 567 | .getShort(42) * 100))); 568 | } 569 | } 570 | } 571 | } 572 | } catch (FileEnd ex) { 573 | } catch (Corrupted ex) { 574 | } catch (IOException e) { 575 | } 576 | } 577 | } 578 | -------------------------------------------------------------------------------- /src/src/Files/FileBeingUsed.java: -------------------------------------------------------------------------------- 1 | /* FileBeingUsed class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | package src.Files; 21 | 22 | public class FileBeingUsed extends Exception { 23 | 24 | private String fileName; 25 | 26 | public FileBeingUsed(String fileName) { 27 | this.fileName = fileName; 28 | } 29 | 30 | public String getFileName() { 31 | return fileName; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/src/Files/FileEnd.java: -------------------------------------------------------------------------------- 1 | /* FileEnd class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.Files; 20 | 21 | public class FileEnd extends Exception { 22 | 23 | } -------------------------------------------------------------------------------- /src/src/Files/NotDatFile.java: -------------------------------------------------------------------------------- 1 | /* NotDatFile class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.Files; 20 | 21 | public class NotDatFile extends Exception { 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/src/Files/Quaternion.java: -------------------------------------------------------------------------------- 1 | /* Quaternion class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | package src.Files; 20 | 21 | import java.text.DecimalFormat; 22 | 23 | /****************************************************************************** 24 | * Compilation: javac Quaternion.java Execution: java Quaternion 25 | * 26 | * Data type for quaternions. 27 | * 28 | * http://mathworld.wolfram.com/Quaternion.html 29 | * 30 | * The data type is "immutable" so once you create and initialize a Quaternion, 31 | * you cannot change it. 32 | * 33 | * % java Quaternion 34 | * 35 | ******************************************************************************/ 36 | 37 | public class Quaternion { 38 | static DecimalFormat df = new DecimalFormat("0.####"); 39 | 40 | private final double SCALAR; // scalar 41 | 42 | private final double X, Y, Z; // vector 43 | 44 | // create a new object with the given components 45 | public Quaternion(double scalar, double x1, double x2, double x3) { 46 | this.SCALAR = scalar; 47 | this.X = x1; 48 | this.Y = x2; 49 | this.Z = x3; 50 | } 51 | 52 | public Quaternion(double x, double y, double z) { 53 | // Converts 3 angles to a Quaternion 54 | x *= 0.5d; 55 | y *= 0.5d; 56 | z *= 0.5d; 57 | 58 | double c1 = (double) Math.cos(z); 59 | double c2 = (double) Math.cos(y); 60 | double c3 = (double) Math.cos(x); 61 | 62 | double s1 = (double) Math.sin(z); 63 | double s2 = (double) Math.sin(y); 64 | double s3 = (double) Math.sin(x); 65 | 66 | this.SCALAR = c1 * c2 * c3 - s1 * s2 * s3; 67 | this.X = c1 * s2 * c3 - s1 * c2 * s3; 68 | this.Y = s1 * s2 * c3 + c1 * c2 * s3; 69 | this.Z = s1 * c2 * c3 + c1 * s2 * s3; 70 | } 71 | 72 | public static Quaternion fromAngles(double pitch, double roll, double yaw) { 73 | // x=pitch, y=roll, z=yaw?????? 74 | pitch *= 0.5d; 75 | roll *= 0.5d; 76 | yaw *= 0.5d; 77 | 78 | double c1 = (double) Math.cos(yaw); 79 | double c2 = (double) Math.cos(roll); 80 | double c3 = (double) Math.cos(pitch); 81 | 82 | double s1 = (double) Math.sin(yaw); 83 | double s2 = (double) Math.sin(roll); 84 | double s3 = (double) Math.sin(pitch); 85 | 86 | return new Quaternion(c1 * c2 * c3 - s1 * s2 * s3, c1 * s2 * c3 - s1 87 | * c2 * s3, s1 * s2 * c3 + c1 * c2 * s3, s1 * c2 * c3 + c1 * s2 88 | * s3); 89 | } 90 | 91 | public static Quaternion fromVector(double x, double y, double z) { 92 | double xy = Math.atan2(y, x); 93 | double xz = Math.atan2(z, x); 94 | double yz = Math.atan2(y, z); 95 | Quaternion retv = new Quaternion(yz, xz, xy); 96 | return retv; 97 | } 98 | 99 | public static Quaternion fromXYVector(double x, double y) { 100 | double xy = Math.atan2(y, x); 101 | Quaternion retv = new Quaternion(0.0, 0.0, xy); 102 | return retv; 103 | } 104 | 105 | public static Quaternion fromZYVector(double z, double y) { 106 | double zy = Math.atan2(z, y); 107 | Quaternion retv = new Quaternion(0.0, zy, 0.0); 108 | return retv; 109 | } 110 | 111 | public static Quaternion fromZXVector(double z, double x) { 112 | double zx = Math.atan2(z, x); 113 | Quaternion retv = new Quaternion(zx, 0.0, 0.0); 114 | return retv; 115 | } 116 | 117 | // return a string representation of the invoking object 118 | public String toString() { 119 | return df.format(SCALAR) + " + " + df.format(X) + "i + " + df.format(Y) 120 | + "j + " + df.format(Z) + "k"; 121 | } 122 | 123 | // return the quaternion norm 124 | public double norm() { 125 | return Math.sqrt(SCALAR * SCALAR + X * X + Y * Y + Z * Z); 126 | } 127 | 128 | // return the quaternion conjugate 129 | public Quaternion conjugate() { 130 | return new Quaternion(SCALAR, -X, -Y, -Z); 131 | } 132 | 133 | // return a new Quaternion whose value is (this + b) 134 | public Quaternion plus(Quaternion b) { 135 | Quaternion a = this; 136 | return new Quaternion(a.SCALAR + b.SCALAR, a.X + b.X, a.Y + b.Y, a.Z 137 | + b.Z); 138 | } 139 | 140 | // return a new Quaternion whose value is (this * b) 141 | public Quaternion times(Quaternion b) { 142 | Quaternion a = this; 143 | double y0 = a.SCALAR * b.SCALAR - a.X * b.X - a.Y * b.Y - a.Z * b.Z; 144 | double y1 = a.SCALAR * b.X + a.X * b.SCALAR + a.Y * b.Z - a.Z * b.Y; 145 | double y2 = a.SCALAR * b.Y - a.X * b.Z + a.Y * b.SCALAR + a.Z * b.X; 146 | double y3 = a.SCALAR * b.Z + a.X * b.Y - a.Y * b.X + a.Z * b.SCALAR; 147 | return new Quaternion(y0, y1, y2, y3); 148 | } 149 | 150 | // return a new Quaternion whose value is the inverse of this 151 | public Quaternion inverse() { 152 | double d = SCALAR * SCALAR + X * X + Y * Y + Z * Z; 153 | return new Quaternion(SCALAR / d, -X / d, -Y / d, -Z / d); 154 | } 155 | 156 | // return a / b 157 | // we use the definition a * b^-1 (as opposed to b^-1 a) 158 | public Quaternion divides(Quaternion b) { 159 | Quaternion a = this; 160 | return a.times(b.inverse()); 161 | } 162 | 163 | public RollPitchYaw toRollPitchYaw() { 164 | double sqW = SCALAR * SCALAR; 165 | double sqX = X * X; 166 | double sqY = Y * Y; 167 | double sqZ = Z * Z; 168 | double yaw = 0.0; 169 | double pitch = 0.0; 170 | double roll = 0.0; 171 | double unit = sqX + sqY + sqZ + sqW; // if normalised is one, otherwise 172 | // is correction factor 173 | double test = SCALAR * X + Y * Z; 174 | if (test > 0.499 * unit) { // singularity at north pole 175 | yaw = 2 * Math.atan2(Y, SCALAR); 176 | pitch = Math.PI / 2; 177 | roll = 0; 178 | } else if (test < -0.499 * unit) { // singularity at south pole 179 | yaw = -2 * Math.atan2(Y, SCALAR); 180 | pitch = -Math.PI / 2; 181 | roll = 0; 182 | } else { 183 | yaw = Math.atan2(2.0 * (SCALAR * Z - X * Y), 184 | 1.0 - 2.0 * (sqZ + sqX)); 185 | 186 | roll = Math.asin(2.0 * test / unit); 187 | pitch = Math.atan2(2.0 * (SCALAR * Y - X * Z), 188 | 1.0 - 2.0 * (sqY + sqX)); 189 | } 190 | return (new RollPitchYaw(roll, pitch, yaw)); 191 | } 192 | 193 | public double[] toEuler() { 194 | double sqW = SCALAR * SCALAR; 195 | double sqX = X * X; 196 | double sqY = Y * Y; 197 | double sqZ = Z * Z; 198 | double yaw = 0.0; 199 | double roll = 0.0; 200 | double pitch = 0.0; 201 | double[] retv = new double[3]; 202 | double unit = sqX + sqY + sqZ + sqW; // if normalised is one, otherwise 203 | // is correction factor 204 | double test = SCALAR * X + Y * Z; 205 | if (test > 0.499 * unit) { // singularity at north pole 206 | yaw = 2 * Math.atan2(Y, SCALAR); 207 | pitch = Math.PI / 2; 208 | roll = 0; 209 | } else if (test < -0.499 * unit) { // singularity at south pole 210 | yaw = -2 * Math.atan2(Y, SCALAR); 211 | pitch = -Math.PI / 2; 212 | roll = 0; 213 | } else { 214 | yaw = Math.atan2(2.0 * (SCALAR * Z - X * Y), 215 | 1.0 - 2.0 * (sqZ + sqX)); 216 | roll = Math.asin(2.0 * test / unit); 217 | pitch = Math.atan2(2.0 * (SCALAR * Y - X * Z), 218 | 1.0 - 2.0 * (sqY + sqX)); 219 | } 220 | retv[0] = pitch; 221 | retv[1] = roll; 222 | retv[2] = yaw; 223 | return retv; 224 | } 225 | 226 | public double getScalar() { 227 | return SCALAR; 228 | } 229 | 230 | public double getX() { 231 | return X; 232 | } 233 | 234 | public double getY() { 235 | return Y; 236 | } 237 | 238 | } 239 | -------------------------------------------------------------------------------- /src/src/Files/RollPitchYaw.java: -------------------------------------------------------------------------------- 1 | /* RollPitchYaw class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | package src.Files; 21 | 22 | import java.text.DecimalFormat; 23 | 24 | public class RollPitchYaw { 25 | static DecimalFormat df = new DecimalFormat("0.####"); 26 | 27 | double roll = 0.0; 28 | 29 | double pitch = 0.0; 30 | 31 | double yaw = 0.0; 32 | 33 | public RollPitchYaw(double roll, double pitch, double yaw) { 34 | this.roll = roll; 35 | this.pitch = pitch; 36 | this.yaw = yaw; 37 | } 38 | 39 | public String toString() { 40 | return "Roll: " + df.format(roll) + " Pitch: " + df.format(pitch) 41 | + " Yaw: " + df.format(yaw); 42 | } 43 | 44 | public String toDegString() { 45 | return "Roll: " + df.format(Math.toDegrees(roll)) + " Degs" 46 | + " Pitch: " + df.format(Math.toDegrees(pitch)) + " Degs" 47 | + " Yaw: " + df.format(Math.toDegrees(yaw)) + " Degs"; 48 | } 49 | 50 | public double getRollDeg() { 51 | return Math.toDegrees(roll); 52 | } 53 | 54 | public double getPitchDeg() { 55 | return Math.toDegrees(pitch); 56 | } 57 | 58 | public double getYawDeg() { 59 | return Math.toDegrees(yaw); 60 | } 61 | 62 | public RollPitchYaw(Quaternion q) { 63 | 64 | } 65 | 66 | public RollPitchYaw() { 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/src/Files/TSAGeoMag.java: -------------------------------------------------------------------------------- 1 | package src.Files; 2 | 3 | /* PUBLIC DOMAIN NOTICE 4 | This program was prepared by Los Alamos National Security, LLC 5 | at Los Alamos National Laboratory (LANL) under contract No. 6 | DE-AC52-06NA25396 with the U.S. Department of Energy (DOE). 7 | All rights in the program are reserved by the DOE and 8 | Los Alamos National Security, LLC. Permission is granted to the 9 | public to copy and use this software without charge, 10 | provided that this Notice and any statement of authorship are 11 | reproduced on all copies. Neither the U.S. Government nor LANS 12 | makes any warranty, express or implied, or assumes any liability 13 | or responsibility for the use of this software. 14 | */ 15 | 16 | /* License Statement from the NOAA 17 | The WMM source code is in the public domain and not licensed or 18 | under copyright. The information and software may be used freely 19 | by the public. As required by 17 U.S.C. 403, third parties producing 20 | copyrighted works consisting predominantly of the material produced 21 | by U.S. government agencies must provide notice with such work(s) 22 | identifying the U.S. Government material incorporated and stating 23 | that such material is not subject to copyright protection. 24 | */ 25 | 26 | //////////////////////////////////////////////////////////////////////////// 27 | // 28 | //GeoMag.java - originally geomag.c 29 | //Ported to Java 1.0.2 by Tim Walker 30 | //tim.walker@worldnet.att.net 31 | //tim@acusat.com 32 | // 33 | //Updated: 1/28/98 34 | // 35 | //Original source geomag.c available at 36 | //http://www.ngdc.noaa.gov/seg/potfld/DoDWMM.html 37 | // 38 | //NOTE: original comments from the geomag.c source file are in ALL CAPS 39 | //Tim's added comments for the port to Java are not 40 | // 41 | //////////////////////////////////////////////////////////////////////////// 42 | 43 | import java.util.Calendar; 44 | import java.util.GregorianCalendar; 45 | 46 | /**

47 | * 48 | * Last updated on May 26, 2015

49 | * NOTE: Comment out the logger references, and put back in the System.out.println 50 | * statements if not using log4j in your application. Checks are not made on the method inputs 51 | * to ensure they are within a valid range.

52 | * 53 | * Verified by a JUnit test using the test values distributed with the 2015 update.

54 | * 55 | * This is a class to generate the magnetic declination, 56 | * magnetic field strength and inclination for any point 57 | * on the earth. The true bearing = magnetic bearing + declination. 58 | * This class is adapted from an Applet from the NOAA National Data Center 59 | * at http://www.ngdc.noaa.gov/seg/segd.shtml. 60 | * None of the calculations 61 | * were changed. This class requires an input file named WMM.COF, which 62 | * must be in the same directory that the application is run from.
63 | * NOTE: If the WMM.COF file is missing, the internal fit coefficients 64 | * for 2015 will be used. 65 | * 66 | * Using the correct date, the declination is accurate to about 0.5 degrees.

67 | * 68 | * This is the LANL D-3 version of the GeoMagnetic calculator from 69 | * the NOAA National Data Center at http://www.ngdc.noaa.gov/seg/segd.shtml.

70 | * 71 | * Adapted by John St. Ledger, Los Alamos National Laboratory 72 | * June 25, 1999

73 | * 74 | * 75 | * Version 2 Comments: The world magnetic model is updated every 5 years. 76 | * The data for 2000 uses the same algorithm to calculate the magnetic 77 | * field variables. The only change is in the spherical harmonic coefficients 78 | * in the input file. The input file has been renamed to WMM.COF. Once again, 79 | * the date was fixed. This time to January 1, 2001. Also, a deprecated 80 | * constructor for StreamTokenizer was replaced, and the error messages in the catch 81 | * clause were changed. Methods to get the field strength and inclination 82 | * were added.

83 | * 84 | * Found out some interesting information about the altitude. The altitude entered 85 | * for the calculations is the height above the WGS84 spheroid, not height MSL. Using 86 | * MSL height means that the altitude could be in error by as much as 200 meters. 87 | * This should not be significant for our applications.

88 | * 89 | *

NOTE: This class is not thread safe.

90 | * 91 | * 92 | * @version 3.0 January 19, 2000 93 | *

Updated for 2000 data.

94 | * 95 | * @version 4.0 March 1, 2002 96 | *

Changed so that if data file doesn't exist, 97 | * it uses an internal version of the coefficients from 98 | * the 2000 update.

99 | * 100 | * 101 | * @version 5.0 June 1, 2005 102 | *

Changed so that if data file doesn't exist, 103 | * it uses an internal version of the coefficients from 104 | * the 2005 update. Previously, only calculated the declination at sea level 105 | * for one date. Now can return all of the variables as a function of date and 106 | * altitude. Original version used float variables. All changed to type double. 107 | * Does not check if the input date is within the valid block.

108 | * 109 | * @version 5.1 June 20, 2005 110 | *

Fixed a bug discovered by Alvin Liem. In my zeal to clean up compiler comments 111 | * I deleted some double casts for integers that resulted in an integer division 112 | * being made when double division was needed.

113 | * 114 | * @version 5.2 June 1, 2006 115 | *

Took out the input error variable, which was no longer being used. 116 | * Now verified with a JUnit test. Deleted the main() method which printed 117 | * a table of test values.

118 | * 119 | * @version 5.3 January 28, 2009 120 | *

Fixed JavaDoc comments, and replaced the StringTokenizer uses with String.split(). 121 | * 122 | * @version 5.4 January 5, 2010 123 | *

Updated for 2010 data. The new 2010 WMM.COF values are now used. Also, added 124 | * log4j support.

125 | * 126 | * @version 5.5 October 10, 2012 127 | *

Made minor changes. The default date used when the caller does not input a date is now the epoch + 2.5 years, 128 | * rather than being a fixed value. This means that the default date is automatically updated if a new WMM.COF file 129 | * is used. Also, now have a method to return the date as a decimal year, given the Gregorian Calendar date.

130 | * 131 | * @version 5.6 January 15, 2015 132 | *

Updated the internal coefficients to the 2015 values. Passes the new JUnit tests.

133 | * 134 | * @version 5.7 May 26, 2015 135 | *

Martin Frassl discovered a major bug in the code. I thought that X was in the East direction. It is not. The X axis 136 | * is in the North direction. This is now fixed so that getNorthIntensity and getEastIntensity return the correct values. 137 | * Thank you Martin!. The X, Y, and Z axes are defined in table 1 of the reference:

138 | *
    Reference: 139 | *
  • Chulliat, A., S. Macmillan, P. Alken, C. Beggan, M. Nair, B. Hamilton, A. Woods, V. Ridley, S. Maus and A. Thomson, 140 | * 2015, The US/UK World Magnetic Model for 2015-2020: Technical Report, National Geophysical Data Center, NOAA. 141 | * doi: 10.7289/V5TB14V7
142 | * 143 | *
    References: 144 | * 145 | *
  • JOHN M. QUINN, DAVID J. KERRIDGE AND DAVID R. BARRACLOUGH, 146 | * WORLD MAGNETIC CHARTS FOR 1985 - SPHERICAL HARMONIC 147 | * MODELS OF THE GEOMAGNETIC FIELD AND ITS SECULAR 148 | * VARIATION, GEOPHYS. J. R. ASTR. SOC. (1986) 87, 149 | * PP 1143-1157
  • 150 | * 151 | *
  • DEFENSE MAPPING AGENCY TECHNICAL REPORT, TR 8350.2: 152 | * DEPARTMENT OF DEFENSE WORLD GEODETIC SYSTEM 1984, 153 | * SEPT. 30 (1987)
  • 154 | * 155 | *
  • JOSEPH C. CAIN, ET AL.; A PROPOSED MODEL FOR THE 156 | * INTERNATIONAL GEOMAGNETIC REFERENCE FIELD - 1965, 157 | * J. GEOMAG. AND GEOELECT. VOL. 19, NO. 4, PP 335-355 158 | * (1967) (SEE APPENDIX)
  • 159 | * 160 | *
  • ALFRED J. ZMUDA, WORLD MAGNETIC SURVEY 1957-1969, 161 | * INTERNATIONAL ASSOCIATION OF GEOMAGNETISM AND 162 | * AERONOMY (IAGA) BULLETIN #28, PP 186-188 (1971)
  • 163 | * 164 | *
  • JOHN M. QUINN, RACHEL J. COLEMAN, MICHAEL R. PECK, AND 165 | * STEPHEN E. LAUBER; THE JOINT US/UK 1990 EPOCH 166 | * WORLD MAGNETIC MODEL, TECHNICAL REPORT NO. 304, 167 | * NAVAL OCEANOGRAPHIC OFFICE (1991)
  • 168 | * 169 | *
  • JOHN M. QUINN, RACHEL J. COLEMAN, DONALD L. SHIEL, AND 170 | * JOHN M. NIGRO; THE JOINT US/UK 1995 EPOCH WORLD 171 | * MAGNETIC MODEL, TECHNICAL REPORT NO. 314, NAVAL 172 | * OCEANOGRAPHIC OFFICE (1995)
173 | * 174 | * 175 | * 176 | * 177 | *

WMM-2000 is a National Imagery and Mapping Agency (NIMA) standard 178 | * product. It is covered under NIMA Military Specification: 179 | * MIL-W-89500 (1993). 180 | * 181 | * For information on the use and applicability of this product contact

182 | * 183 | * DIRECTOR
184 | * NATIONAL IMAGERY AND MAPPING AGENCY/HEADQUARTERS
185 | * ATTN: CODE P33
186 | * 12310 SUNRISE VALLEY DRIVE
187 | * RESTON, VA 20191-3449
188 | * (703) 264-3002
189 | * 190 | * 191 | *

The FORTRAN version of GEOMAG PROGRAMMED BY:

192 | * 193 | * JOHN M. QUINN 7/19/90
194 | * FLEET PRODUCTS DIVISION, CODE N342
195 | * NAVAL OCEANOGRAPHIC OFFICE (NAVOCEANO)
196 | * STENNIS SPACE CENTER (SSC), MS 39522-5001
197 | * USA
198 | * PHONE: COM: (601) 688-5828
199 | * AV: 485-5828
200 | * FAX: (601) 688-5521
201 | * 202 | *

NOW AT:

203 | * 204 | * GEOMAGNETICS GROUP
205 | * U. S. GEOLOGICAL SURVEY MS 966
206 | * FEDERAL CENTER
207 | * DENVER, CO 80225-0046
208 | * USA
209 | * PHONE: COM: (303) 273-8475
210 | * FAX: (303) 273-8600
211 | * EMAIL: quinn@ghtmail.cr.usgs.gov
212 | */ 213 | public class TSAGeoMag { 214 | 215 | //variables for magnetic calculations //////////////////////////////////// 216 | // 217 | // Variables were identified in geomag.for, the FORTRAN 218 | // version of the geomag calculator. 219 | 220 | /** The input string array which contains each line of input for the 221 | * wmm.cof input file. Added so that all data was internal, so that 222 | * applications do not have to mess with carrying around a data file. 223 | * In the TSAGeoMag Class, the columns in this file are as follows: 224 | * n, m, gnm, hnm, dgnm, dhnm 225 | */ 226 | private String[] input = { 227 | " 2015.0 WMM-2015 12/15/2014", 228 | " 1 0 -29438.5 0.0 10.7 0.0", 229 | " 1 1 -1501.1 4796.2 17.9 -26.8", 230 | " 2 0 -2445.3 0.0 -8.6 0.0", 231 | " 2 1 3012.5 -2845.6 -3.3 -27.1", 232 | " 2 2 1676.6 -642.0 2.4 -13.3", 233 | " 3 0 1351.1 0.0 3.1 0.0", 234 | " 3 1 -2352.3 -115.3 -6.2 8.4", 235 | " 3 2 1225.6 245.0 -0.4 -0.4", 236 | " 3 3 581.9 -538.3 -10.4 2.3", 237 | " 4 0 907.2 0.0 -0.4 0.0", 238 | " 4 1 813.7 283.4 0.8 -0.6", 239 | " 4 2 120.3 -188.6 -9.2 5.3", 240 | " 4 3 -335.0 180.9 4.0 3.0", 241 | " 4 4 70.3 -329.5 -4.2 -5.3", 242 | " 5 0 -232.6 0.0 -0.2 0.0", 243 | " 5 1 360.1 47.4 0.1 0.4", 244 | " 5 2 192.4 196.9 -1.4 1.6", 245 | " 5 3 -141.0 -119.4 0.0 -1.1", 246 | " 5 4 -157.4 16.1 1.3 3.3", 247 | " 5 5 4.3 100.1 3.8 0.1", 248 | " 6 0 69.5 0.0 -0.5 0.0", 249 | " 6 1 67.4 -20.7 -0.2 0.0", 250 | " 6 2 72.8 33.2 -0.6 -2.2", 251 | " 6 3 -129.8 58.8 2.4 -0.7", 252 | " 6 4 -29.0 -66.5 -1.1 0.1", 253 | " 6 5 13.2 7.3 0.3 1.0", 254 | " 6 6 -70.9 62.5 1.5 1.3", 255 | " 7 0 81.6 0.0 0.2 0.0", 256 | " 7 1 -76.1 -54.1 -0.2 0.7", 257 | " 7 2 -6.8 -19.4 -0.4 0.5", 258 | " 7 3 51.9 5.6 1.3 -0.2", 259 | " 7 4 15.0 24.4 0.2 -0.1", 260 | " 7 5 9.3 3.3 -0.4 -0.7", 261 | " 7 6 -2.8 -27.5 -0.9 0.1", 262 | " 7 7 6.7 -2.3 0.3 0.1", 263 | " 8 0 24.0 0.0 0.0 0.0", 264 | " 8 1 8.6 10.2 0.1 -0.3", 265 | " 8 2 -16.9 -18.1 -0.5 0.3", 266 | " 8 3 -3.2 13.2 0.5 0.3", 267 | " 8 4 -20.6 -14.6 -0.2 0.6", 268 | " 8 5 13.3 16.2 0.4 -0.1", 269 | " 8 6 11.7 5.7 0.2 -0.2", 270 | " 8 7 -16.0 -9.1 -0.4 0.3", 271 | " 8 8 -2.0 2.2 0.3 0.0", 272 | " 9 0 5.4 0.0 0.0 0.0", 273 | " 9 1 8.8 -21.6 -0.1 -0.2", 274 | " 9 2 3.1 10.8 -0.1 -0.1", 275 | " 9 3 -3.1 11.7 0.4 -0.2", 276 | " 9 4 0.6 -6.8 -0.5 0.1", 277 | " 9 5 -13.3 -6.9 -0.2 0.1", 278 | " 9 6 -0.1 7.8 0.1 0.0", 279 | " 9 7 8.7 1.0 0.0 -0.2", 280 | " 9 8 -9.1 -3.9 -0.2 0.4", 281 | " 9 9 -10.5 8.5 -0.1 0.3", 282 | " 10 0 -1.9 0.0 0.0 0.0", 283 | " 10 1 -6.5 3.3 0.0 0.1", 284 | " 10 2 0.2 -0.3 -0.1 -0.1", 285 | " 10 3 0.6 4.6 0.3 0.0", 286 | " 10 4 -0.6 4.4 -0.1 0.0", 287 | " 10 5 1.7 -7.9 -0.1 -0.2", 288 | " 10 6 -0.7 -0.6 -0.1 0.1", 289 | " 10 7 2.1 -4.1 0.0 -0.1", 290 | " 10 8 2.3 -2.8 -0.2 -0.2", 291 | " 10 9 -1.8 -1.1 -0.1 0.1", 292 | " 10 10 -3.6 -8.7 -0.2 -0.1", 293 | " 11 0 3.1 0.0 0.0 0.0", 294 | " 11 1 -1.5 -0.1 0.0 0.0", 295 | " 11 2 -2.3 2.1 -0.1 0.1", 296 | " 11 3 2.1 -0.7 0.1 0.0", 297 | " 11 4 -0.9 -1.1 0.0 0.1", 298 | " 11 5 0.6 0.7 0.0 0.0", 299 | " 11 6 -0.7 -0.2 0.0 0.0", 300 | " 11 7 0.2 -2.1 0.0 0.1", 301 | " 11 8 1.7 -1.5 0.0 0.0", 302 | " 11 9 -0.2 -2.5 0.0 -0.1", 303 | " 11 10 0.4 -2.0 -0.1 0.0", 304 | " 11 11 3.5 -2.3 -0.1 -0.1", 305 | " 12 0 -2.0 0.0 0.1 0.0", 306 | " 12 1 -0.3 -1.0 0.0 0.0", 307 | " 12 2 0.4 0.5 0.0 0.0", 308 | " 12 3 1.3 1.8 0.1 -0.1", 309 | " 12 4 -0.9 -2.2 -0.1 0.0", 310 | " 12 5 0.9 0.3 0.0 0.0", 311 | " 12 6 0.1 0.7 0.1 0.0", 312 | " 12 7 0.5 -0.1 0.0 0.0", 313 | " 12 8 -0.4 0.3 0.0 0.0", 314 | " 12 9 -0.4 0.2 0.0 0.0", 315 | " 12 10 0.2 -0.9 0.0 0.0", 316 | " 12 11 -0.9 -0.2 0.0 0.0", 317 | " 12 12 0.0 0.7 0.0 0.0", }; 318 | 319 | /** 320 | * Geodetic altitude in km. An input, 321 | * but set to zero in this class. Changed 322 | * back to an input in version 5. If not specified, 323 | * then is 0. 324 | */ 325 | private double alt = 0; 326 | 327 | /** 328 | * Geodetic latitude in deg. An input. 329 | */ 330 | private double glat = 0; 331 | 332 | /** 333 | * Geodetic longitude in deg. An input. 334 | */ 335 | private double glon = 0; 336 | 337 | /** 338 | * Time in decimal years. An input. 339 | */ 340 | private double time = 0; 341 | 342 | /** 343 | * Geomagnetic declination in deg. 344 | * East is positive, West is negative. 345 | * (The negative of variation.) 346 | */ 347 | private double dec = 0; 348 | 349 | /** 350 | * Geomagnetic inclination in deg. 351 | * Down is positive, up is negative. 352 | */ 353 | private double dip = 0; 354 | 355 | /** 356 | * Geomagnetic total intensity, in nano Teslas. 357 | */ 358 | private double ti = 0; 359 | 360 | /** 361 | * Geomagnetic grid variation, referenced to 362 | * grid North. Not calculated or output in version 5.0. 363 | */ 364 | //private double gv = 0; 365 | 366 | /** 367 | * The maximum number of degrees of the spherical harmonic model. 368 | */ 369 | private int maxdeg = 12; 370 | 371 | /** 372 | * The maximum order of spherical harmonic model. 373 | */ 374 | private int maxord; 375 | 376 | /** Added in version 5. In earlier versions the date for the calculation was held as a 377 | * constant. Now the default date is set to 2.5 years plus the epoch read from the 378 | * input file. 379 | */ 380 | private double defaultDate = 2018.5; 381 | 382 | /** Added in version 5. In earlier versions the altitude for the calculation was held as a 383 | * constant at 0. In version 5, if no altitude is specified in the calculation, this 384 | * altitude is used by default. 385 | */ 386 | private final double defaultAltitude = 0; 387 | 388 | /** 389 | * The Gauss coefficients of main geomagnetic model (nt). 390 | */ 391 | private double c[][] = new double[13][13]; 392 | 393 | /** 394 | * The Gauss coefficients of secular geomagnetic model (nt/yr). 395 | */ 396 | private double cd[][] = new double[13][13]; 397 | 398 | /** 399 | * The time adjusted geomagnetic gauss coefficients (nt). 400 | */ 401 | private double tc[][] = new double[13][13]; 402 | 403 | /** 404 | * The theta derivative of p(n,m) (unnormalized). 405 | */ 406 | private double dp[][] = new double[13][13]; 407 | 408 | /** 409 | * The Schmidt normalization factors. 410 | */ 411 | private double snorm[] = new double[169]; 412 | 413 | /** 414 | * The sine of (m*spherical coord. longitude). 415 | */ 416 | private double sp[] = new double[13]; 417 | 418 | /** 419 | * The cosine of (m*spherical coord. longitude). 420 | */ 421 | private double cp[] = new double[13]; 422 | 423 | private double fn[] = new double[13]; 424 | 425 | private double fm[] = new double[13]; 426 | 427 | /** 428 | * The associated Legendre polynomials for m=1 (unnormalized). 429 | */ 430 | private double pp[] = new double[13]; 431 | 432 | private double k[][] = new double[13][13]; 433 | 434 | /** 435 | * The variables otime (old time), oalt (old altitude), 436 | * olat (old latitude), olon (old longitude), are used to 437 | * store the values used from the previous calculation to 438 | * save on calculation time if some inputs don't change. 439 | */ 440 | private double otime, oalt, olat, olon; 441 | 442 | /** The date in years, for the start of the valid time of the fit coefficients */ 443 | private double epoch; 444 | 445 | /** bx is the north south field intensity 446 | * by is the east west field intensity 447 | * bz is the vertical field intensity positive downward 448 | * bh is the horizontal field intensity 449 | */ 450 | private double bx, by, bz, bh; 451 | 452 | private double re, a2, b2, c2, a4, b4, c4; 453 | 454 | private double r, d, ca, sa, ct, st; // even though these only occur in one method, they must be 455 | // created here, or won't have correct values calculated 456 | // These values are only recalculated if the altitude changes. 457 | 458 | // 459 | //////////////////////////////////////////////////////////////////////////// 460 | 461 | /** 462 | * Instantiates object by calling initModel(). 463 | */ 464 | public TSAGeoMag() { 465 | //read model data from file and initialize the GeoMag routine 466 | initModel(); 467 | } 468 | 469 | /** 470 | * Reads data from file and initializes magnetic model. If 471 | * the file is not present, or an IO exception occurs, then the internal 472 | * values valid for 2015 will be used. Note that the last line of the 473 | * WMM.COF file must be 9999... for this method to read in the input 474 | * file properly. 475 | */ 476 | private void initModel() { 477 | glat = 0; 478 | glon = 0; 479 | //bOutDated = false; 480 | //String strModel = new String(); 481 | //String strFile = new String("WMM.COF"); 482 | // String strFile = new String("wmm-95.dat"); 483 | 484 | // INITIALIZE CONSTANTS 485 | maxord = maxdeg; 486 | sp[0] = 0.0; 487 | cp[0] = snorm[0] = pp[0] = 1.0; 488 | dp[0][0] = 0.0; 489 | /** 490 | * Semi-major axis of WGS-84 ellipsoid, in km. 491 | */ 492 | double a = 6378.137; 493 | /** 494 | * Semi-minor axis of WGS-84 ellipsoid, in km. 495 | */ 496 | double b = 6356.7523142; 497 | /** 498 | * Mean radius of IAU-66 ellipsoid, in km. 499 | */ 500 | re = 6371.2; 501 | a2 = a * a; 502 | b2 = b * b; 503 | c2 = a2 - b2; 504 | a4 = a2 * a2; 505 | b4 = b2 * b2; 506 | c4 = a4 - b4; 507 | 508 | setCoeff(); 509 | // CONVERT SCHMIDT NORMALIZED GAUSS COEFFICIENTS TO UNNORMALIZED 510 | snorm[0] = 1.0; 511 | for (int n = 1; n <= maxord; n++) { 512 | 513 | snorm[n] = snorm[n - 1] * (2 * n - 1) / n; 514 | int j = 2; 515 | 516 | for (int m = 0, D1 = 1, D2 = (n - m + D1) / D1; D2 > 0; D2--, m += D1) { 517 | k[m][n] = (double) (((n - 1) * (n - 1)) - (m * m)) 518 | / (double) ((2 * n - 1) * (2 * n - 3)); 519 | if (m > 0) { 520 | double flnmj = ((n - m + 1) * j) / (double) (n + m); 521 | snorm[n + m * 13] = snorm[n + (m - 1) * 13] 522 | * Math.sqrt(flnmj); 523 | j = 1; 524 | c[n][m - 1] = snorm[n + m * 13] * c[n][m - 1]; 525 | cd[n][m - 1] = snorm[n + m * 13] * cd[n][m - 1]; 526 | } 527 | c[m][n] = snorm[n + m * 13] * c[m][n]; 528 | cd[m][n] = snorm[n + m * 13] * cd[m][n]; 529 | } //for(m...) 530 | 531 | fn[n] = (n + 1); 532 | fm[n] = n; 533 | 534 | } //for(n...) 535 | 536 | k[1][1] = 0.0; 537 | 538 | otime = oalt = olat = olon = -1000.0; 539 | 540 | } 541 | 542 | /**

PURPOSE: THIS ROUTINE COMPUTES THE DECLINATION (DEC), 543 | * INCLINATION (DIP), TOTAL INTENSITY (TI) AND 544 | * GRID VARIATION (GV - POLAR REGIONS ONLY, REFERENCED 545 | * TO GRID NORTH OF POLAR STEREOGRAPHIC PROJECTION) OF 546 | * THE EARTH'S MAGNETIC FIELD IN GEODETIC COORDINATES 547 | * FROM THE COEFFICIENTS OF THE CURRENT OFFICIAL 548 | * DEPARTMENT OF DEFENSE (DOD) SPHERICAL HARMONIC WORLD 549 | * MAGNETIC MODEL (WMM-2010). THE WMM SERIES OF MODELS IS 550 | * UPDATED EVERY 5 YEARS ON JANUARY 1'ST OF THOSE YEARS 551 | * WHICH ARE DIVISIBLE BY 5 (I.E. 1980, 1985, 1990 ETC.) 552 | * BY THE NAVAL OCEANOGRAPHIC OFFICE IN COOPERATION 553 | * WITH THE BRITISH GEOLOGICAL SURVEY (BGS). THE MODEL 554 | * IS BASED ON GEOMAGNETIC SURVEY MEASUREMENTS FROM 555 | * AIRCRAFT, SATELLITE AND GEOMAGNETIC OBSERVATORIES.

556 | * 557 | * 558 | * 559 | * ACCURACY: IN OCEAN AREAS AT THE EARTH'S SURFACE OVER THE 560 | * ENTIRE 5 YEAR LIFE OF A DEGREE AND ORDER 12 561 | * SPHERICAL HARMONIC MODEL SUCH AS WMM-95, THE ESTIMATED 562 | * RMS ERRORS FOR THE VARIOUS MAGENTIC COMPONENTS ARE:

563 | *
    564 | * DEC - 0.5 Degrees
    565 | * DIP - 0.5 Degrees
    566 | * TI - 280.0 nanoTeslas (nT)
    567 | * GV - 0.5 Degrees
568 | * 569 | *

OTHER MAGNETIC COMPONENTS THAT CAN BE DERIVED FROM 570 | * THESE FOUR BY SIMPLE TRIGONOMETRIC RELATIONS WILL 571 | * HAVE THE FOLLOWING APPROXIMATE ERRORS OVER OCEAN AREAS:

572 | *
    573 | * X - 140 nT (North)
    574 | * Y - 140 nT (East)
    575 | * Z - 200 nT (Vertical) Positive is down
    576 | * H - 200 nT (Horizontal)
577 | * 578 | *

OVER LAND THE RMS ERRORS ARE EXPECTED TO BE SOMEWHAT 579 | * HIGHER, ALTHOUGH THE RMS ERRORS FOR DEC, DIP AND GV 580 | * ARE STILL ESTIMATED TO BE LESS THAN 0.5 DEGREE, FOR 581 | * THE ENTIRE 5-YEAR LIFE OF THE MODEL AT THE EARTH's 582 | * SURFACE. THE OTHER COMPONENT ERRORS OVER LAND ARE 583 | * MORE DIFFICULT TO ESTIMATE AND SO ARE NOT GIVEN.

584 | * 585 | * THE ACCURACY AT ANY GIVEN TIME OF ALL FOUR 586 | * GEOMAGNETIC PARAMETERS DEPENDS ON THE GEOMAGNETIC 587 | * LATITUDE. THE ERRORS ARE LEAST AT THE EQUATOR AND 588 | * GREATEST AT THE MAGNETIC POLES.

589 | * 590 | * IT IS VERY IMPORTANT TO NOTE THAT A DEGREE AND 591 | * ORDER 12 MODEL, SUCH AS WMM-2010 DESCRIBES ONLY 592 | * THE LONG WAVELENGTH SPATIAL MAGNETIC FLUCTUATIONS 593 | * DUE TO EARTH'S CORE. NOT INCLUDED IN THE WMM SERIES 594 | * MODELS ARE INTERMEDIATE AND SHORT WAVELENGTH 595 | * SPATIAL FLUCTUATIONS OF THE GEOMAGNETIC FIELD 596 | * WHICH ORIGINATE IN THE EARTH'S MANTLE AND CRUST. 597 | * CONSEQUENTLY, ISOLATED ANGULAR ERRORS AT VARIOUS 598 | * POSITIONS ON THE SURFACE (PRIMARILY OVER LAND, IN 599 | * CONTINENTAL MARGINS AND OVER OCEANIC SEAMOUNTS, 600 | * RIDGES AND TRENCHES) OF SEVERAL DEGREES MAY BE 601 | * EXPECTED. ALSO NOT INCLUDED IN THE MODEL ARE 602 | * NONSECULAR TEMPORAL FLUCTUATIONS OF THE GEOMAGNETIC 603 | * FIELD OF MAGNETOSPHERIC AND IONOSPHERIC ORIGIN. 604 | * DURING MAGNETIC STORMS, TEMPORAL FLUCTUATIONS CAN 605 | * CAUSE SUBSTANTIAL DEVIATIONS OF THE GEOMAGNETIC 606 | * FIELD FROM MODEL VALUES. IN ARCTIC AND ANTARCTIC 607 | * REGIONS, AS WELL AS IN EQUATORIAL REGIONS, DEVIATIONS 608 | * FROM MODEL VALUES ARE BOTH FREQUENT AND PERSISTENT.

609 | * 610 | * IF THE REQUIRED DECLINATION ACCURACY IS MORE 611 | * STRINGENT THAN THE WMM SERIES OF MODELS PROVIDE, THEN 612 | * THE USER IS ADVISED TO REQUEST SPECIAL (REGIONAL OR 613 | * LOCAL) SURVEYS BE PERFORMED AND MODELS PREPARED BY 614 | * THE USGS, WHICH OPERATES THE US GEOMAGNETIC 615 | * OBSERVATORIES. REQUESTS OF THIS NATURE SHOULD 616 | * BE MADE THROUGH NIMA AT THE ADDRESS ABOVE.

617 | * 618 | * 619 | * 620 | * NOTE: THIS VERSION OF GEOMAG USES THE WMM-2010 GEOMAGNETIC 621 | * MODEL REFERENCED TO THE WGS-84 GRAVITY MODEL ELLIPSOID

622 | * 623 | * @param fLat The latitude in decimal degrees. 624 | * @param fLon The longitude in decimal degrees. 625 | * @param year The date as a decimal year. 626 | * @param altitude The altitude in kilometers. 627 | */ 628 | private void calcGeoMag(double fLat, double fLon, double year, 629 | double altitude) { 630 | 631 | glat = fLat; 632 | glon = fLon; 633 | alt = altitude; 634 | /** 635 | * The date in decimal years for calculating the magnetic field components. 636 | */ 637 | time = year; 638 | 639 | double dt = time - epoch; 640 | //if (otime < 0.0 && (dt < 0.0 || dt > 5.0)) 641 | // if(bCurrent){ 642 | // if (dt < 0.0 || dt > 5.0) 643 | // bOutDated = true; 644 | // else 645 | // bOutDated = false; 646 | // } 647 | 648 | double pi = Math.PI; 649 | double dtr = (pi / 180.0); 650 | double rlon = glon * dtr; 651 | double rlat = glat * dtr; 652 | double srlon = Math.sin(rlon); 653 | double srlat = Math.sin(rlat); 654 | double crlon = Math.cos(rlon); 655 | double crlat = Math.cos(rlat); 656 | double srlat2 = srlat * srlat; 657 | double crlat2 = crlat * crlat; 658 | sp[1] = srlon; 659 | cp[1] = crlon; 660 | 661 | // CONVERT FROM GEODETIC COORDS. TO SPHERICAL COORDS. 662 | if (alt != oalt || glat != olat) { 663 | double q = Math.sqrt(a2 - c2 * srlat2); 664 | double q1 = alt * q; 665 | double q2 = ((q1 + a2) / (q1 + b2)) * ((q1 + a2) / (q1 + b2)); 666 | ct = srlat / Math.sqrt(q2 * crlat2 + srlat2); 667 | st = Math.sqrt(1.0 - (ct * ct)); 668 | double r2 = ((alt * alt) + 2.0 * q1 + (a4 - c4 * srlat2) / (q * q)); 669 | r = Math.sqrt(r2); 670 | d = Math.sqrt(a2 * crlat2 + b2 * srlat2); 671 | ca = (alt + d) / r; 672 | sa = c2 * crlat * srlat / (r * d); 673 | } 674 | if (glon != olon) { 675 | for (int m = 2; m <= maxord; m++) { 676 | sp[m] = sp[1] * cp[m - 1] + cp[1] * sp[m - 1]; 677 | cp[m] = cp[1] * cp[m - 1] - sp[1] * sp[m - 1]; 678 | } 679 | } 680 | double aor = re / r; 681 | double ar = aor * aor; 682 | double br = 0, bt = 0, bp = 0, bpp = 0; 683 | 684 | for (int n = 1; n <= maxord; n++) { 685 | ar = ar * aor; 686 | for (int m = 0, D3 = 1, D4 = (n + m + D3) / D3; D4 > 0; D4--, m += D3) { 687 | 688 | //COMPUTE UNNORMALIZED ASSOCIATED LEGENDRE POLYNOMIALS 689 | //AND DERIVATIVES VIA RECURSION RELATIONS 690 | if (alt != oalt || glat != olat) { 691 | if (n == m) { 692 | snorm[n + m * 13] = st * snorm[n - 1 + (m - 1) * 13]; 693 | dp[m][n] = st * dp[m - 1][n - 1] + ct 694 | * snorm[n - 1 + (m - 1) * 13]; 695 | } 696 | if (n == 1 && m == 0) { 697 | snorm[n + m * 13] = ct * snorm[n - 1 + m * 13]; 698 | dp[m][n] = ct * dp[m][n - 1] - st 699 | * snorm[n - 1 + m * 13]; 700 | } 701 | if (n > 1 && n != m) { 702 | if (m > n - 2) 703 | snorm[n - 2 + m * 13] = 0.0; 704 | if (m > n - 2) 705 | dp[m][n - 2] = 0.0; 706 | snorm[n + m * 13] = ct * snorm[n - 1 + m * 13] 707 | - k[m][n] * snorm[n - 2 + m * 13]; 708 | dp[m][n] = ct * dp[m][n - 1] - st 709 | * snorm[n - 1 + m * 13] - k[m][n] 710 | * dp[m][n - 2]; 711 | } 712 | } 713 | 714 | //TIME ADJUST THE GAUSS COEFFICIENTS 715 | 716 | if (time != otime) { 717 | tc[m][n] = c[m][n] + dt * cd[m][n]; 718 | 719 | if (m != 0) 720 | tc[n][m - 1] = c[n][m - 1] + dt * cd[n][m - 1]; 721 | } 722 | 723 | //ACCUMULATE TERMS OF THE SPHERICAL HARMONIC EXPANSIONS 724 | double temp1, temp2; 725 | double par = ar * snorm[n + m * 13]; 726 | if (m == 0) { 727 | temp1 = tc[m][n] * cp[m]; 728 | temp2 = tc[m][n] * sp[m]; 729 | } else { 730 | temp1 = tc[m][n] * cp[m] + tc[n][m - 1] * sp[m]; 731 | temp2 = tc[m][n] * sp[m] - tc[n][m - 1] * cp[m]; 732 | } 733 | 734 | bt = bt - ar * temp1 * dp[m][n]; 735 | bp += (fm[m] * temp2 * par); 736 | br += (fn[n] * temp1 * par); 737 | 738 | //SPECIAL CASE: NORTH/SOUTH GEOGRAPHIC POLES 739 | 740 | if (st == 0.0 && m == 1) { 741 | if (n == 1) 742 | pp[n] = pp[n - 1]; 743 | else 744 | pp[n] = ct * pp[n - 1] - k[m][n] * pp[n - 2]; 745 | double parp = ar * pp[n]; 746 | bpp += (fm[m] * temp2 * parp); 747 | } 748 | 749 | } //for(m...) 750 | 751 | } //for(n...) 752 | 753 | if (st == 0.0) 754 | bp = bpp; 755 | else 756 | bp /= st; 757 | 758 | //ROTATE MAGNETIC VECTOR COMPONENTS FROM SPHERICAL TO 759 | //GEODETIC COORDINATES 760 | // bx must be the east-west field component 761 | // by must be the north-south field component 762 | // bz must be the vertical field component. 763 | bx = -bt * ca - br * sa; 764 | by = bp; 765 | bz = bt * sa - br * ca; 766 | 767 | //COMPUTE DECLINATION (DEC), INCLINATION (DIP) AND 768 | //TOTAL INTENSITY (TI) 769 | 770 | bh = Math.sqrt((bx * bx) + (by * by)); 771 | ti = Math.sqrt((bh * bh) + (bz * bz)); 772 | // Calculate the declination. 773 | dec = (Math.atan2(by, bx) / dtr); 774 | //logger.debug( "Dec is: " + dec ); 775 | dip = (Math.atan2(bz, bh) / dtr); 776 | 777 | // This is the variation for grid navigation. 778 | // Not used at this time. See St. Ledger for explanation. 779 | //COMPUTE MAGNETIC GRID VARIATION IF THE CURRENT 780 | //GEODETIC POSITION IS IN THE ARCTIC OR ANTARCTIC 781 | //(I.E. GLAT > +55 DEGREES OR GLAT < -55 DEGREES) 782 | // Grid North is referenced to the 0 Meridian of a polar 783 | // stereographic projection. 784 | 785 | //OTHERWISE, SET MAGNETIC GRID VARIATION TO -999.0 786 | /* 787 | gv = -999.0; 788 | if (Math.abs(glat) >= 55.){ 789 | if (glat > 0.0 && glon >= 0.0) 790 | gv = dec-glon; 791 | if (glat > 0.0 && glon < 0.0) 792 | gv = dec + Math.abs(glon); 793 | if (glat < 0.0 && glon >= 0.0) 794 | gv = dec+glon; 795 | if (glat < 0.0 && glon < 0.0) 796 | gv = dec - Math.abs(glon); 797 | if (gv > +180.0) 798 | gv -= 360.0; 799 | if (gv < -180.0) 800 | gv += 360.0; 801 | } 802 | */ 803 | otime = time; 804 | oalt = alt; 805 | olat = glat; 806 | olon = glon; 807 | 808 | } 809 | 810 | /** 811 | * Returns the declination from the Department of 812 | * Defense geomagnetic model and data, in degrees. The 813 | * magnetic heading + declination = true heading. The date and 814 | * altitude are the defaults, of half way through the valid 815 | * 5 year period, and 0 elevation. 816 | * (True heading + variation = magnetic heading.) 817 | * 818 | * @param dlat Latitude in decimal degrees. 819 | * @param dlong Longitude in decimal degrees. 820 | * 821 | * @return The declination in degrees. 822 | */ 823 | public double getDeclination(double dlat, double dlong) { 824 | calcGeoMag(dlat, dlong, defaultDate, defaultAltitude); 825 | return dec; 826 | } 827 | 828 | /** 829 | * Returns the declination from the Department of 830 | * Defense geomagnetic model and data, in degrees. The 831 | * magnetic heading + declination = true heading. 832 | * (True heading + variation = magnetic heading.) 833 | * 834 | * @param dlat Latitude in decimal degrees. 835 | * @param dlong Longitude in decimal degrees. 836 | * @param year The date as a decimial year. 837 | * @param altitude The altitude in kilometers. 838 | * 839 | * @return The declination in degrees. 840 | */ 841 | public double getDeclination(double dlat, double dlong, double year, 842 | double altitude) { 843 | calcGeoMag(dlat, dlong, year, altitude); 844 | return dec; 845 | } 846 | 847 | /** 848 | * Returns the magnetic field intensity from the 849 | * Department of Defense geomagnetic model and data 850 | * in nano Tesla. The date and 851 | * altitude are the defaults, of half way through the valid 852 | * 5 year period, and 0 elevation. 853 | * 854 | * @param dlat Latitude in decimal degrees. 855 | * @param dlong Longitude in decimal degrees. 856 | * 857 | * @return Magnetic field strength in nano Tesla. 858 | */ 859 | public double getIntensity(double dlat, double dlong) { 860 | calcGeoMag(dlat, dlong, defaultDate, defaultAltitude); 861 | return ti; 862 | } 863 | 864 | /** 865 | * Returns the magnetic field intensity from the 866 | * Department of Defense geomagnetic model and data 867 | * in nano Tesla. 868 | * 869 | * @param dlat Latitude in decimal degrees. 870 | * @param dlong Longitude in decimal degrees. 871 | * @param year Date of the calculation in decimal years. 872 | * @param altitude Altitude of the calculation in kilometers. 873 | * 874 | * @return Magnetic field strength in nano Tesla. 875 | */ 876 | public double getIntensity(double dlat, double dlong, double year, 877 | double altitude) { 878 | calcGeoMag(dlat, dlong, year, altitude); 879 | return ti; 880 | } 881 | 882 | /** 883 | * Returns the horizontal magnetic field intensity from the 884 | * Department of Defense geomagnetic model and data 885 | * in nano Tesla. The date and 886 | * altitude are the defaults, of half way through the valid 887 | * 5 year period, and 0 elevation. 888 | * 889 | * @param dlat Latitude in decimal degrees. 890 | * @param dlong Longitude in decimal degrees. 891 | * 892 | * @return The horizontal magnetic field strength in nano Tesla. 893 | */ 894 | public double getHorizontalIntensity(double dlat, double dlong) { 895 | calcGeoMag(dlat, dlong, defaultDate, defaultAltitude); 896 | return bh; 897 | } 898 | 899 | /** 900 | * Returns the horizontal magnetic field intensity from the 901 | * Department of Defense geomagnetic model and data 902 | * in nano Tesla. 903 | * 904 | * @param dlat Latitude in decimal degrees. 905 | * @param dlong Longitude in decimal degrees. 906 | * @param year Date of the calculation in decimal years. 907 | * @param altitude Altitude of the calculation in kilometers. 908 | * 909 | * @return The horizontal magnetic field strength in nano Tesla. 910 | */ 911 | public double getHorizontalIntensity(double dlat, double dlong, 912 | double year, double altitude) { 913 | calcGeoMag(dlat, dlong, year, altitude); 914 | return bh; 915 | } 916 | 917 | /** 918 | * Returns the vertical magnetic field intensity from the 919 | * Department of Defense geomagnetic model and data 920 | * in nano Tesla. The date and 921 | * altitude are the defaults, of half way through the valid 922 | * 5 year period, and 0 elevation. 923 | * 924 | * @param dlat Latitude in decimal degrees. 925 | * @param dlong Longitude in decimal degrees. 926 | * 927 | * @return The vertical magnetic field strength in nano Tesla. 928 | */ 929 | public double getVerticalIntensity(double dlat, double dlong) { 930 | calcGeoMag(dlat, dlong, defaultDate, defaultAltitude); 931 | return bz; 932 | } 933 | 934 | /** 935 | * Returns the vertical magnetic field intensity from the 936 | * Department of Defense geomagnetic model and data 937 | * in nano Tesla. 938 | * 939 | * @param dlat Latitude in decimal degrees. 940 | * @param dlong Longitude in decimal degrees. 941 | * @param year Date of the calculation in decimal years. 942 | * @param altitude Altitude of the calculation in kilometers. 943 | * 944 | * @return The vertical magnetic field strength in nano Tesla. 945 | */ 946 | public double getVerticalIntensity(double dlat, double dlong, double year, 947 | double altitude) { 948 | calcGeoMag(dlat, dlong, year, altitude); 949 | return bz; 950 | } 951 | 952 | /** 953 | * Returns the northerly magnetic field intensity from the 954 | * Department of Defense geomagnetic model and data 955 | * in nano Tesla. The date and 956 | * altitude are the defaults, of half way through the valid 957 | * 5 year period, and 0 elevation. 958 | * 959 | * @param dlat Latitude in decimal degrees. 960 | * @param dlong Longitude in decimal degrees. 961 | * 962 | * @return The northerly component of the magnetic field strength in nano Tesla. 963 | */ 964 | public double getNorthIntensity(double dlat, double dlong) { 965 | calcGeoMag(dlat, dlong, defaultDate, defaultAltitude); 966 | return bx; 967 | } 968 | 969 | /** 970 | * Returns the northerly magnetic field intensity from the 971 | * Department of Defense geomagnetic model and data 972 | * in nano Tesla. 973 | * 974 | * @param dlat Latitude in decimal degrees. 975 | * @param dlong Longitude in decimal degrees. 976 | * @param year Date of the calculation in decimal years. 977 | * @param altitude Altitude of the calculation in kilometers. 978 | * 979 | * @return The northerly component of the magnetic field strength in nano Tesla. 980 | */ 981 | public double getNorthIntensity(double dlat, double dlong, double year, 982 | double altitude) { 983 | calcGeoMag(dlat, dlong, year, altitude); 984 | return bx; 985 | } 986 | 987 | /** 988 | * Returns the easterly magnetic field intensity from the 989 | * Department of Defense geomagnetic model and data 990 | * in nano Tesla. The date and 991 | * altitude are the defaults, of half way through the valid 992 | * 5 year period, and 0 elevation. 993 | * 994 | * @param dlat Latitude in decimal degrees. 995 | * @param dlong Longitude in decimal degrees. 996 | * 997 | * @return The easterly component of the magnetic field strength in nano Tesla. 998 | */ 999 | public double getEastIntensity(double dlat, double dlong) { 1000 | calcGeoMag(dlat, dlong, defaultDate, defaultAltitude); 1001 | return by; 1002 | } 1003 | 1004 | /** 1005 | * Returns the easterly magnetic field intensity from the 1006 | * Department of Defense geomagnetic model and data 1007 | * in nano Tesla. 1008 | * 1009 | * @param dlat Latitude in decimal degrees. 1010 | * @param dlong Longitude in decimal degrees. 1011 | * @param year Date of the calculation in decimal years. 1012 | * @param altitude Altitude of the calculation in kilometers. 1013 | * 1014 | * @return The easterly component of the magnetic field strength in nano Tesla. 1015 | */ 1016 | public double getEastIntensity(double dlat, double dlong, double year, 1017 | double altitude) { 1018 | calcGeoMag(dlat, dlong, year, altitude); 1019 | return by; 1020 | } 1021 | 1022 | /** 1023 | * Returns the magnetic field dip angle from the 1024 | * Department of Defense geomagnetic model and data, 1025 | * in degrees. The date and 1026 | * altitude are the defaults, of half way through the valid 1027 | * 5 year period, and 0 elevation. 1028 | * 1029 | * @param dlat Latitude in decimal degrees. 1030 | * @param dlong Longitude in decimal degrees. 1031 | * 1032 | * @return The magnetic field dip angle, in degrees. 1033 | */ 1034 | public double getDipAngle(double dlat, double dlong) { 1035 | calcGeoMag(dlat, dlong, defaultDate, defaultAltitude); 1036 | return dip; 1037 | } 1038 | 1039 | /** 1040 | * Returns the magnetic field dip angle from the 1041 | * Department of Defense geomagnetic model and data, 1042 | * in degrees. 1043 | * 1044 | * @param dlat Latitude in decimal degrees. 1045 | * @param dlong Longitude in decimal degrees. 1046 | * @param year Date of the calculation in decimal years. 1047 | * @param altitude Altitude of the calculation in kilometers. 1048 | * 1049 | * @return The magnetic field dip angle, in degrees. 1050 | */ 1051 | public double getDipAngle(double dlat, double dlong, double year, 1052 | double altitude) { 1053 | calcGeoMag(dlat, dlong, year, altitude); 1054 | return dip; 1055 | } 1056 | 1057 | /** This method sets the input data to the internal fit coefficents. 1058 | * If there is an exception reading the input file WMM.COF, these values 1059 | * are used. 1060 | * 1061 | * NOTE: This method is not tested by the JUnit test, unless the WMM.COF file 1062 | * is missing. 1063 | */ 1064 | private void setCoeff() { 1065 | c[0][0] = 0.0; 1066 | cd[0][0] = 0.0; 1067 | 1068 | epoch = Double.parseDouble(input[0].trim().split("[\\s]+")[0]); 1069 | defaultDate = epoch + 2.5; 1070 | 1071 | String[] tokens; 1072 | 1073 | //loop to get data from internal values 1074 | for (int i = 1; i < input.length; i++) { 1075 | tokens = input[i].trim().split("[\\s]+"); 1076 | 1077 | int n = Integer.parseInt(tokens[0]); 1078 | int m = Integer.parseInt(tokens[1]); 1079 | double gnm = Double.parseDouble(tokens[2]); 1080 | double hnm = Double.parseDouble(tokens[3]); 1081 | double dgnm = Double.parseDouble(tokens[4]); 1082 | double dhnm = Double.parseDouble(tokens[5]); 1083 | 1084 | if (m <= n) { 1085 | c[m][n] = gnm; 1086 | cd[m][n] = dgnm; 1087 | 1088 | if (m != 0) { 1089 | c[n][m - 1] = hnm; 1090 | cd[n][m - 1] = dhnm; 1091 | } 1092 | } 1093 | } 1094 | } 1095 | 1096 | /**

1097 | * Given a Gregorian Calendar object, this returns the decimal year 1098 | * value for the calendar, accurate to the day of the input calendar. 1099 | * The hours, minutes, and seconds of the date are ignored.

1100 | * 1101 | * If the input Gregorian Calendar is new GregorianCalendar(2012, 6, 1), all of 1102 | * the first of July is counted, and this returns 2012.5. (183 days out of 366)

1103 | * 1104 | * If the input Gregorian Calendar is new GregorianCalendar(2010, 0, 0), the first 1105 | * of January is not counted, and this returns 2010.0

1106 | * 1107 | * @param cal Has the date (year, month, and day of the month) 1108 | * @return The date in decimal years 1109 | */ 1110 | public double decimalYear(GregorianCalendar cal) { 1111 | int year = cal.get(Calendar.YEAR); 1112 | double daysInYear; 1113 | if (cal.isLeapYear(year)) { 1114 | daysInYear = 366.0; 1115 | } else { 1116 | daysInYear = 365.0; 1117 | } 1118 | 1119 | return year + (cal.get(Calendar.DAY_OF_YEAR)) / daysInYear; 1120 | } 1121 | 1122 | } 1123 | -------------------------------------------------------------------------------- /src/src/Files/Util.java: -------------------------------------------------------------------------------- 1 | /* Util class 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that redistribution of source code include 5 | the following disclaimer in the documentation and/or other materials provided 6 | with the distribution. 7 | 8 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11 | DISCLAIMED. IN NO EVENT SHALL THE CREATOR OR CONTRIBUTORS BE LIABLE FOR 12 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 13 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 14 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 15 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 16 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 17 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | */ 19 | 20 | package src.Files; 21 | 22 | import java.text.DecimalFormat; 23 | import java.text.DecimalFormatSymbols; 24 | import java.util.Locale; 25 | 26 | public class Util { 27 | 28 | public static double distance(double lat1, double lon1, double lat2, 29 | double lon2) { 30 | 31 | final int R = 6371; // Radius of the earth 32 | if (lat1 == 0.0 || lon1 == 0.0 || lat2 == 0.0 || lon2 == 0.0) 33 | return 0.0; 34 | double latDistance = (lat2 - lat1); 35 | double lonDistance = (lon2 - lon1); 36 | double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) 37 | + Math.cos((lat1)) * Math.cos((lat2)) 38 | * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2); 39 | double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 40 | double distance = R * c * 1000; // convert to meters 41 | return distance; 42 | } 43 | 44 | // computes true(not magnetic) bearing 45 | public static double bearing(double lat1, double lon1, double lat2, 46 | double lon2) { 47 | double longDiff = (lon2 - lon1); 48 | double y = Math.sin(longDiff) * Math.cos(lat2); 49 | double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) 50 | * Math.cos(lat2) * Math.cos(longDiff); 51 | //return (Math.toDegrees(Math.atan2(y, x)) + 360) % 360; 52 | return Math.toDegrees(Math.atan2(y, x)); 53 | } 54 | 55 | public static float time(long tickNo, long offset) { 56 | return (float) (tickNo - offset) / (float) 600.0; 57 | } 58 | 59 | public static DecimalFormat timeFormat = new DecimalFormat("###.000", 60 | new DecimalFormatSymbols(Locale.US)); 61 | 62 | public static String timeString(long tickNo, long offset) { 63 | return timeFormat.format(time(tickNo, offset)); 64 | } 65 | 66 | public static long getTickFromTime(Number time, long offset) { 67 | return ((long) (600.0 * time.doubleValue())) + offset; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/src/LICENSE.MD: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that redistribution of source code include 3 | the following disclaimer in the documentation and/or other materials provided 4 | with the distribution. 5 | 6 | THIS SOFTWARE IS PROVIDED BY ITS CREATOR "AS IS" AND 7 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 8 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 9 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 10 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 11 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 12 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 13 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 14 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 15 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 | --------------------------------------------------------------------------------