• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

WindhoverLabs / yamcs_gdl90 / #36

26 Nov 2024 07:34PM UTC coverage: 0.0%. Remained the same
#36

push

web-flow
Merge 4e5c4b89e into 2cc1ae215

0 of 972 new or added lines in 7 files covered. (0.0%)

20 existing lines in 4 files now uncovered.

0 of 2375 relevant lines covered (0.0%)

0.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/java/com/windhoverlabs/yamcs/gdl90/OwnshipReport.java
1
/****************************************************************************
2
 *
3
 *   Copyright (c) 2024 Windhover Labs, L.L.C. All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in
13
 *    the documentation and/or other materials provided with the
14
 *    distribution.
15
 * 3. Neither the name Windhover Labs nor the names of its
16
 *    contributors may be used to endorse or promote products derived
17
 *    from this software without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
 * POSSIBILITY OF SUCH DAMAGE.
31
 *
32
 *****************************************************************************/
33

34
package com.windhoverlabs.yamcs.gdl90;
35

36
import java.io.ByteArrayOutputStream;
37
import java.nio.ByteBuffer;
38

39
/**
40
 * As per the spec:
41
 * https://www.faa.gov/sites/faa.gov/files/air_traffic/technology/adsb/archival/GDL90_Public_ICD_RevA.PDF
42
 * Pg 18
43
 */
44
public class OwnshipReport {
×
45

46
  byte FlagByte = 0x7E;
×
47
  //        First Byte
48
  public static final byte MessageID = 10;
49

50
  //          Traffic Alert Status (s)
51
  public boolean TrafficAlertStatus;
52

53
  //  Address Type (t)
54
  /**
55
   * t = 0 : ADS-B with ICAO address t = 1 : ADS-B with Self-assigned address t = 2 : TIS-B with
56
   * ICAO address t = 3 : TIS-B with track file ID. t = 4 : Surface Vehicle t = 5 : Ground Station
57
   * Beacon t = 6-15 : reserved
58
   */
59
  public int AddressType;
60

61
  //  Participant Address in base 8 (aa aa aa)
62
  public int ParticipantAddress;
63

64
  //  ll ll ll
65
  public double Latitude;
66
  //  nn nn nn
67
  public double Longitude;
68

69
  //  ddd
70
  public int Altitude;
71

72
  // Miscellaneous indicators:
73

74
  public boolean TrueTrackAngle;
75
  public boolean MagneticHeading;
76
  public boolean TrueHeading;
77
  public boolean ReportUpdated;
78
  public boolean ReportExtrapolated;
79
  public boolean OnGround;
80
  public boolean Airborne;
81
  public int Miscellaneous;
82
  public byte i;
83
  public byte a;
84

85
  public int horizontalVelocity;
86

87
  public int verticalVelocity;
88

89
  public int trackHeading;
90

91
  //  Emitter Category. Should be an enum.
92
  public byte ee;
93

94
  public String callSign;
95

96
  //  EMERGENCY /PRIORITY CODE
97
  public byte px;
98

99
  public byte[] toBytes() throws Exception {
100

101
    ByteArrayOutputStream messageStream = new ByteArrayOutputStream();
×
102

103
    messageStream.write(MessageID);
×
104

105
    byte st = 0x00;
×
106

107
    if (TrafficAlertStatus) {
×
108
      st = (byte) (st & 0xf0);
×
109
    }
110

111
    st = (byte) (st & AddressType);
×
112

113
    messageStream.write(st);
×
114

115
    // aaaaaa Big Endian
116
    byte[] ParticipantAddressBytes =
×
117
        ByteBuffer.allocate(4)
×
118
            .putInt(Integer.parseUnsignedInt(Integer.toString(ParticipantAddress), 8))
×
119
            .array();
×
120
    messageStream.write(ParticipantAddressBytes[1]);
×
121
    messageStream.write(ParticipantAddressBytes[2]);
×
122
    messageStream.write(ParticipantAddressBytes[3]);
×
123

124
    int packed = packLatLong(Latitude);
×
125

126
    String tempLat = Integer.toHexString(packed);
×
127

128
    // llllll Big Endian
129
    byte[] LatitudeBytes = ByteBuffer.allocate(4).putInt(packed).array();
×
130
    messageStream.write(LatitudeBytes[1]);
×
131
    messageStream.write(LatitudeBytes[2]);
×
132
    messageStream.write(LatitudeBytes[3]);
×
133

134
    packed = packLatLong(Longitude);
×
135

136
    // llllll Big Endian
137
    byte[] LongitudeBytes = ByteBuffer.allocate(4).putInt(packed).array();
×
138
    messageStream.write(LongitudeBytes[1]);
×
139
    messageStream.write(LongitudeBytes[2]);
×
140
    messageStream.write(LongitudeBytes[3]);
×
141

142
    int packedAltitude = packAltitude(Altitude);
×
143

144
    // ddd Big Endian
145
    byte[] AltitudeBytes = ByteBuffer.allocate(4).putInt(packedAltitude).array();
×
146

147
    byte dmByte = (byte) AltitudeBytes[2];
×
148

NEW
149
    if (TrueHeading) {
×
150
      dmByte = (byte) (dmByte | (1 << 0));
×
NEW
151
      dmByte = (byte) (dmByte | (1 << 1));
×
NEW
152
      dmByte = (byte) (dmByte | (1 << 3));
×
153
    }
154
    //    if (Airborne) {
155
    //      //            TODO:Set bit accordingly
156
    //    }
157
    //
158
    //    dmByte = (byte) setNibble(dmByte, 0x03, 1);
159

160
    //    dmByte = 0x09;
UNCOV
161
    int dddm = packedAltitude << 20 | (dmByte);
×
162

163
    // hhh Big Endian
164
    byte[] dddmBytes = ByteBuffer.allocate(4).putInt(dddm).array();
×
165

166
    //        TODO:Needs to be revisited
167

168
    messageStream.write(dddmBytes[0]);
×
169
    messageStream.write(dddmBytes[3]);
×
170

171
    byte iaByte = 0;
×
172

173
    iaByte = (byte) setNibble(iaByte, a, 0);
×
174
    iaByte = (byte) setNibble(iaByte, i, 1);
×
175

176
    messageStream.write(iaByte);
×
177

178
    int c = horizontalVelocity << 20 | (verticalVelocity / 64);
×
179

180
    // hhh Big Endian
181
    byte[] cBytes = ByteBuffer.allocate(4).putInt(c).array();
×
182

183
    messageStream.write(cBytes[0]);
×
184
    messageStream.write(cBytes[1]);
×
185
    messageStream.write(cBytes[3]);
×
186

187
    int packedHeading = packHeading(trackHeading);
×
188

189
    // tt Big Endian
190
    byte[] HeadingBytes = ByteBuffer.allocate(4).putInt(packedHeading).array();
×
191
    messageStream.write(HeadingBytes[3]);
×
192

193
    messageStream.write(ee);
×
194
    byte[] callSignBytes = this.callSign.getBytes();
×
195
    if (callSignBytes.length > 8) {
×
196
      throw new Exception("callSign is greater than 8 characters");
×
197
    }
198

199
    for (byte b : callSignBytes) {
×
200
      messageStream.write(b);
×
201
    }
202

203
    int callSignBytesRemainder = 8 - callSignBytes.length;
×
204

205
    for (int i = 0; i < callSignBytesRemainder; i++) {
×
206
      messageStream.write(0x20);
×
207
    }
208

209
    messageStream.write(px);
×
210

211
    byte[] crcData = messageStream.toByteArray();
×
212
    int crc = CrcTable.crcCompute(crcData, 0, crcData.length);
×
213
    //
214
    // Go through message data and escape characters as per the spec
215
    // ....
216
    //
217

218
    byte[] crcBytes = ByteBuffer.allocate(4).putInt(crc).array();
×
219
    messageStream.write(crcBytes[3]);
×
220
    messageStream.write(crcBytes[2]);
×
221

222
    ByteArrayOutputStream messageStreamOut =
×
223
        com.windhoverlabs.yamcs.gdl90.OwnshipGeoAltitude.escapeBytes(messageStream.toByteArray());
×
224

225
    ByteBuffer bbOut = ByteBuffer.allocate(messageStreamOut.toByteArray().length + 2).put(FlagByte);
×
226

227
    bbOut.put(messageStreamOut.toByteArray());
×
228

229
    bbOut.put(FlagByte);
×
230

231
    byte[] dataOut = bbOut.array();
×
232

233
    messageStream.toByteArray();
×
234

235
    return dataOut;
×
236
  }
237

238
  private ByteArrayOutputStream minimallyFunctionalMessage() {
239
    // Minimally functional message for ForeFlight
240
    // TODO:Write unit test
241
    ByteArrayOutputStream messageStream = new ByteArrayOutputStream();
×
242
    byte[] data = exampleMesssage();
×
243
    messageStream.write(FlagByte);
×
244

245
    messageStream.write(MessageID);
×
246
    messageStream.write(0x00);
×
247
    messageStream.write(0xAB); // "Magic" Byte that makes ForeFlight recognize the device
×
248
    messageStream.write(0);
×
249
    messageStream.write(0);
×
250
    messageStream.write(0);
×
251
    messageStream.write(0);
×
252
    messageStream.write(0);
×
253
    messageStream.write(0);
×
254
    messageStream.write(0);
×
255
    messageStream.write(0);
×
256
    messageStream.write(0);
×
257
    messageStream.write(0);
×
258
    messageStream.write(0xA9); // "Magic" Byte that makes ForeFlight recognize the device
×
259
    messageStream.write(0);
×
260
    messageStream.write(0);
×
261
    messageStream.write(0);
×
262
    messageStream.write(0);
×
263
    messageStream.write(0);
×
264
    messageStream.write(0);
×
265
    messageStream.write(0);
×
266
    messageStream.write(0);
×
267
    messageStream.write(0);
×
268
    messageStream.write(0);
×
269
    messageStream.write(0);
×
270
    messageStream.write(0);
×
271
    messageStream.write(0);
×
272
    messageStream.write(0);
×
273

274
    // CRC
275

276
    //    TODO:Offset needs to be re-calculated for escape characters
277
    byte[] crcData = messageStream.toByteArray();
×
278
    int crc = CrcTable.crcCompute(crcData, 1, crcData.length - 1);
×
279

280
    //
281
    // Go through message data and escape characters as per the spec
282
    // ....
283
    //
284

285
    byte[] crcBytes = ByteBuffer.allocate(4).putInt(crc).array();
×
286
    messageStream.write(crcBytes[3]);
×
287
    messageStream.write(crcBytes[2]);
×
288

289
    messageStream.write(FlagByte);
×
290
    return messageStream;
×
291
  }
292

293
  public static int setNibble(int num, int nibble, int which) {
294
    int shiftNibble = nibble << (4 * which);
×
295
    int shiftMask = 0x0000000F << (4 * which);
×
296
    return (num & ~shiftMask) | shiftNibble;
×
297
  }
298

299
  public int packLatLong(double LatLon) {
300

301
    Double doubleVal = LatLon;
×
302

303
    int valLon = (int) (doubleVal / (180.0 / 8388608.0));
×
304

305
    return valLon;
×
306
  }
307

308
  public int packAltitude(int altFt) {
309
    //          Double doubleVal = altFt;
310
    return (int) ((1000 + altFt) / 25);
×
311
  }
312

313
  public int packHeading(float heading) {
314
    return Math.round((heading / 360) * 256);
×
315
  }
316

317
  private byte[] exampleMesssage() {
318
    // TODO: Use this message for unit tests
319
    //          Minimum length: message length(including Message ID) + 2 Flag Bytes+ CRC16(2 bytes)
320
    byte[] data = new byte[32];
×
321
    data[0] = FlagByte;
×
322

323
    data[1] = MessageID;
×
324
    data[2] = 0x00;
×
325
    data[3] = (byte) 0xAB;
×
326
    data[4] = 0x45;
×
327
    data[5] = 0x49;
×
328
    data[6] = 0x1F;
×
329
    data[7] = (byte) 0xEF;
×
330
    data[8] = 0x15;
×
331
    data[9] = (byte) 0xA8;
×
332
    data[10] = (byte) 0x89;
×
333

334
    data[11] = 0x78;
×
335
    data[12] = 0x0F;
×
336

337
    Miscellaneous = 0xffffffff; // 12th byte
×
338
    byte[] MiscellaneousBytes = ByteBuffer.allocate(4).putInt(Miscellaneous).array();
×
339

340
    data[13] = 0x09;
×
341

342
    data[14] = (byte) 0xA9;
×
343
    data[15] = 0x07;
×
344
    data[16] = (byte) 0xB0;
×
345
    data[17] = 0x01;
×
346
    data[18] = 0x20;
×
347
    data[19] = 0x01;
×
348
    data[20] = 0x4E;
×
349
    data[21] = 0x38;
×
350
    data[22] = 0x32;
×
351
    data[23] = 0x35;
×
352
    data[24] = 0x56;
×
353

354
    data[25] = 0x20;
×
355
    data[26] = 0x20;
×
356
    data[27] = 0x20;
×
357
    data[28] = 0x00;
×
358

359
    int crc = 0;
×
360

361
    //    TODO:Offset needs to be re-calculated for escape characters
362
    crc = CrcTable.crcCompute(data, 1, 28);
×
363

364
    byte[] crcBytes = ByteBuffer.allocate(4).putInt(crc).array();
×
365

366
    data[data.length - 3] = crcBytes[3];
×
367
    data[data.length - 2] = crcBytes[2];
×
368
    data[data.length - 1] = FlagByte;
×
369
    return data;
×
370
  }
371
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc