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

WindhoverLabs / yamcs_gdl90 / #38

26 Nov 2024 07:42PM UTC coverage: 0.0%. Remained the same
#38

Pull #3

lorenzo-gomez-windhover
-Upgrade yamcs to 5.9.8
Pull Request #3: Binary Mode

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

20 existing lines in 4 files now uncovered.

0 of 2374 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/GDL90Link.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 static org.yamcs.StandardTupleDefinitions.GENTIME_COLUMN;
37
import static org.yamcs.StandardTupleDefinitions.TM_RECTIME_COLUMN;
38

39
import com.google.gson.Gson;
40
import com.google.protobuf.Timestamp;
41
import com.google.protobuf.util.Timestamps;
42
import java.io.IOException;
43
import java.net.DatagramPacket;
44
import java.net.DatagramSocket;
45
import java.net.InetAddress;
46
import java.net.SocketException;
47
import java.net.UnknownHostException;
48
import java.nio.ByteBuffer;
49
import java.nio.file.WatchKey;
50
import java.nio.file.WatchService;
51
import java.text.ParseException;
52
import java.time.Duration;
53
import java.time.Instant;
54
import java.util.ArrayList;
55
import java.util.Arrays;
56
import java.util.HashMap;
57
import java.util.HashSet;
58
import java.util.List;
59
import java.util.Map;
60
import java.util.Map.Entry;
61
import java.util.Set;
62
import java.util.concurrent.ConcurrentHashMap;
63
import java.util.concurrent.Executors;
64
import java.util.concurrent.ScheduledExecutorService;
65
import java.util.concurrent.TimeUnit;
66
import java.util.stream.Collectors;
67
import org.yamcs.ConfigurationException;
68
import org.yamcs.InitException;
69
import org.yamcs.Processor;
70
import org.yamcs.ProcessorException;
71
import org.yamcs.ProcessorFactory;
72
import org.yamcs.Spec;
73
import org.yamcs.ValidationException;
74
import org.yamcs.YConfiguration;
75
import org.yamcs.archive.ReplayOptions;
76
import org.yamcs.client.ClientException;
77
import org.yamcs.client.ConnectionListener;
78
import org.yamcs.client.ParameterSubscription;
79
import org.yamcs.client.YamcsClient;
80
import org.yamcs.parameter.ParameterValue;
81
import org.yamcs.parameter.SystemParametersProducer;
82
import org.yamcs.parameter.SystemParametersService;
83
import org.yamcs.protobuf.SubscribeParametersRequest;
84
import org.yamcs.protobuf.SubscribeParametersRequest.Action;
85
import org.yamcs.protobuf.Yamcs;
86
import org.yamcs.protobuf.Yamcs.EndAction;
87
import org.yamcs.protobuf.Yamcs.NamedObjectId;
88
import org.yamcs.protobuf.Yamcs.ReplayRequest;
89
import org.yamcs.tctm.AbstractLink;
90
import org.yamcs.tctm.PacketInputStream;
91
import org.yamcs.utils.ByteArrayUtils;
92
import org.yamcs.xtce.Parameter;
93
import org.yamcs.yarch.ColumnDefinition;
94
import org.yamcs.yarch.DataType;
95
import org.yamcs.yarch.FileSystemBucket;
96
import org.yamcs.yarch.Stream;
97
import org.yamcs.yarch.StreamSubscriber;
98
import org.yamcs.yarch.Tuple;
99
import org.yamcs.yarch.TupleDefinition;
100
import org.yamcs.yarch.YarchDatabase;
101
import org.yamcs.yarch.YarchDatabaseInstance;
102

103
public class GDL90Link extends AbstractLink
×
104
    implements Runnable,
105
        SystemParametersProducer,
106
        ParameterSubscription.Listener,
107
        ConnectionListener,
108
        StreamSubscriber {
109

110
  class HostPortPair {
111
    String host;
112
    String port;
113

NEW
114
    public HostPortPair(String newHost, String newPort) {
×
NEW
115
      this.host = newHost;
×
NEW
116
      this.port = newPort;
×
NEW
117
    }
×
118

119
    @Override
120
    public boolean equals(Object otherPair) {
NEW
121
      if (!(otherPair instanceof HostPortPair)) {
×
NEW
122
        return false;
×
123
      } else {
NEW
124
        HostPortPair other = (HostPortPair) otherPair;
×
NEW
125
        return other.host.equals(this.host) && other.port.equals(this.port);
×
126
      }
127
    }
128

129
    @Override
130
    public int hashCode() {
131
      //            Substract hashes so that order matters
NEW
132
      return this.host.hashCode() - this.port.hashCode();
×
133
    }
134
  }
135

136
  class Vector3F {
137
    double data[];
138

NEW
139
    public Vector3F() {
×
NEW
140
      data = new double[3];
×
NEW
141
    }
×
142
  }
143

144
  class Vector4F {
145
    double data[];
146

NEW
147
    public Vector4F() {
×
NEW
148
      data = new double[4];
×
NEW
149
    }
×
150
  }
151

152
  class QT extends Vector4F {
153

NEW
154
    public QT() {
×
NEW
155
      super();
×
NEW
156
    }
×
157

158
    Matrix3F3 RotationMatrix() {
NEW
159
      Matrix3F3 R = new Matrix3F3();
×
NEW
160
      double aSq = data[0] * data[0];
×
NEW
161
      double bSq = data[1] * data[1];
×
NEW
162
      double cSq = data[2] * data[2];
×
NEW
163
      double dSq = data[3] * data[3];
×
NEW
164
      R.data[0][0] = aSq + bSq - cSq - dSq;
×
NEW
165
      R.data[0][1] = 2.0f * (data[1] * data[2] - data[0] * data[3]);
×
NEW
166
      R.data[0][2] = 2.0f * (data[0] * data[2] + data[1] * data[3]);
×
NEW
167
      R.data[1][0] = 2.0f * (data[1] * data[2] + data[0] * data[3]);
×
NEW
168
      R.data[1][1] = aSq - bSq + cSq - dSq;
×
NEW
169
      R.data[1][2] = 2.0f * (data[2] * data[3] - data[0] * data[1]);
×
NEW
170
      R.data[2][0] = 2.0f * (data[1] * data[3] - data[0] * data[2]);
×
NEW
171
      R.data[2][1] = 2.0f * (data[0] * data[1] + data[2] * data[3]);
×
NEW
172
      R.data[2][2] = aSq - bSq - cSq + dSq;
×
NEW
173
      return R;
×
174
    }
175
  }
176

NEW
177
  class YPR {
×
178
    double yaw, pitch, roll;
179
  }
180

181
  class Matrix3F3 {
182
    double data[][];
183

NEW
184
    public Matrix3F3() {
×
NEW
185
      data = new double[3][3];
×
NEW
186
    }
×
187

188
    Vector3F ToEuler() {
NEW
189
      Vector3F euler = new Vector3F();
×
NEW
190
      euler.data[1] = Math.asin(-data[2][0]);
×
191

NEW
192
      if (Math.abs(euler.data[1] - Math.PI / 2) < 1.0e-3f) {
×
NEW
193
        euler.data[0] = 0.0f;
×
NEW
194
        euler.data[2] =
×
NEW
195
            Math.atan2(data[1][2] - data[0][1], data[0][2] + data[1][1]) + euler.data[0];
×
196

NEW
197
      } else if (Math.abs(euler.data[1] + Math.PI / 2) < 1.0e-3f) {
×
NEW
198
        euler.data[0] = 0.0f;
×
NEW
199
        euler.data[2] =
×
NEW
200
            Math.atan2(data[1][2] - data[0][1], data[0][2] + data[1][1]) - euler.data[0];
×
201

202
      } else {
NEW
203
        euler.data[0] = Math.atan2(data[2][1], data[2][2]);
×
NEW
204
        euler.data[2] = Math.atan2(data[1][0], data[0][0]);
×
205
      }
206

NEW
207
      return euler;
×
208
    }
209
  }
210

211
  class GDL90Device {
212
    String host;
213
    String port;
214
    DatagramPacket datagram;
215
    boolean alive;
216
    int keepAliveSeconds;
217
    Instant lastBroadcastTime;
218
    boolean blackListed;
219

220
    AHRSMode ahrsMode;
221

222
    public GDL90Device(
223
        String newHost,
224
        String newPort,
225
        DatagramPacket newDatagram,
226
        boolean newAlive,
227
        int newKeepAliveSeconds,
228
        Instant newLastBradcastTime,
NEW
229
        boolean isBlackListed) {
×
230
      this.host = newHost;
×
231
      this.port = newPort;
×
232
      this.datagram = newDatagram;
×
233
      this.alive = newAlive;
×
234
      this.keepAliveSeconds = newKeepAliveSeconds;
×
235
      this.lastBroadcastTime = newLastBradcastTime;
×
NEW
236
      this.blackListed = isBlackListed;
×
UNCOV
237
    }
×
238

239
    public String toString() {
NEW
240
      return "\"Host:"
×
241
          + this.host
242
          + ", Port:"
243
          + this.port
244
          + ", Alive:"
245
          + this.alive
246
          + ", BlackListed:"
247
          + this.blackListed
248
          + "\"";
249
    }
250
  }
251

NEW
252
  enum AHRS_MODE {
×
NEW
253
    YPR,
×
NEW
254
    QT
×
255
  }
256

NEW
257
  enum AHRS_ENCODING {
×
NEW
258
    WHL,
×
NEW
259
    FF
×
260
  }
261
  /* Configuration Defaults */
262
  private static TupleDefinition gftdef;
263

264
  private boolean outOfSync = false;
×
265

266
  private Parameter outOfSyncParam;
267
  private Parameter streamEventCountParam;
268
  private Parameter logEventCountParam;
269
  private Parameter devicesParam;
270
  private Parameter blackListParam;
271

272
  private int streamEventCount;
273
  private int logEventCount;
274

275
  /* Configuration Parameters */
276
  protected long initialDelay;
277
  protected long period;
278

279
  /* Internal member attributes. */
280
  protected List<FileSystemBucket> buckets;
281
  protected YConfiguration packetInputStreamArgs;
282
  protected PacketInputStream packetInputStream;
283
  protected WatchService watcher;
284
  protected List<WatchKey> watchKeys;
285
  protected Thread thread;
286

287
  private DatagramSocket foreFlightSocket;
288
  private DatagramSocket GDL90Socket;
289

290
  private ParameterSubscription subscription;
291

292
  private ConcurrentHashMap<String, org.yamcs.protobuf.Pvalue.ParameterValue> paramsToSend =
×
293
      new ConcurrentHashMap<String, org.yamcs.protobuf.Pvalue.ParameterValue>();
294

295
  private String yamcsHost;
296
  private int yamcsPort;
297

298
  private String processorName;
299
  private Processor processor;
300

301
  private ReplayOptions replayOptions;
302

303
  private YamcsClient yclient;
304

305
  int MAX_LENGTH = 1024;
×
306
  DatagramPacket foreFlightdatagram = new DatagramPacket(new byte[MAX_LENGTH], MAX_LENGTH);
×
307

308
  private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
×
309

310
  private ConcurrentHashMap<String, String> pvMap;
311
  private int heartBeatCount = 0;
×
312
  private int ownShipReportCount = 0;
×
313
  private int ownshipGeoAltitudeCount = 0;
×
314
  private int foreFlightIDCount = 0;
×
315
  private int AHRSCount = 0;
×
NEW
316
  private int WHLAHRSCount = 0;
×
317
  String GDL90Hostname;
318

319
  Integer appNameMax;
320
  Integer eventMsgMax;
321
  private String heartbeatStreamName;
322
  private Stream heartbeatStream;
323

324
  private String ownShipReportStreamName;
325
  private Stream ownShipReportStream;
326

327
  private String ownShipGeoAltitudeStreamName;
328
  private Stream ownShipGeoAltitudeStream;
329

330
  private String AHRSStreamName;
331
  private Stream AHRSStream;
332

333
  private String WHLAHRSStreamName;
334
  private Stream WHLAHRSStream;
335

336
  private String ForeFlightIDStreamName;
337
  private Stream ForeFlightIDStream;
338

339
  private String _1HZ_MsgsStreamName;
340
  private Stream _1HZ_MsgsStream;
341

342
  private String _5HZ_MsgsStreamName;
343
  private Stream _5HZ_MsgsStream;
344

345
  static final String RECTIME_CNAME = "rectime";
346
  static final String MSG_NAME_CNAME = "MSG_NAME_CNAME";
347
  static final String DATA_CNAME = "data";
348

349
  //  Make keepAliveConfig configurable, maybe...
350

351
  public int keepAliveConfig = 30; // Seconds
×
352

353
  private DataSource source;
354

355
  private AHRSHeadingType headingType;
356

NEW
357
  Set<Integer> msgIds_1HZ = new HashSet<>();
×
NEW
358
  Set<Integer> msgIds_5HZ = new HashSet<>();
×
359

UNCOV
360
  ConcurrentHashMap<String, GDL90Device> gdl90Devices =
×
361
      new ConcurrentHashMap<String, GDL90Device>();
362

NEW
363
  HashMap<HostPortPair, GDL90Device> blackList = new HashMap<HostPortPair, GDL90Device>();
×
364

365
  private String start;
366
  private String stop;
367
  private Timestamp startTimeStamp;
368
  private Timestamp stopTimeStamp;
369

370
  private boolean realtime;
371

372
  private int heartbeatRate;
373
  private int ownShipReportRate;
374
  private int ownShipGeoAltitudeRate;
375
  private int AHRSRate;
376
  private int WHLAHRSRate;
377

378
  private AHRS_MODE ahrsMode;
379
  private AHRS_ENCODING ahrsEncoding;
380

381
  static {
382
    gftdef = new TupleDefinition();
×
383
    gftdef.addColumn(new ColumnDefinition(RECTIME_CNAME, DataType.TIMESTAMP));
×
384

385
    gftdef.addColumn(new ColumnDefinition(MSG_NAME_CNAME, DataType.STRING));
×
386
    gftdef.addColumn(new ColumnDefinition(DATA_CNAME, DataType.BINARY));
×
387
  }
×
388

389
  @Override
390
  public Spec getSpec() {
391
    //          TODO: Do this properly eventually
392
    //    Spec spec = super.getDefaultSpec();
393

NEW
394
    return null;
×
395
  }
396

397
  @Override
398
  public void init(String yamcsInstance, String serviceName, YConfiguration config) {
399
    super.init(yamcsInstance, serviceName, config);
×
400

401
    try {
402
      foreFlightSocket = new DatagramSocket(63093);
×
403
      GDL90Socket = new DatagramSocket();
×
404
      if (this.getConfig().containsKey("gdl90Devices")) {
×
405
        List<Map<String, Object>> devices = this.getConfig().getList("gdl90Devices");
×
406
        for (Map<String, Object> d : devices) {
×
407
          {
NEW
408
            boolean blackListed = ((boolean) d.getOrDefault("blackListed", false));
×
NEW
409
            GDL90Device newDevice =
×
410
                new GDL90Device(
NEW
411
                    d.get("gdl90_host").toString(),
×
NEW
412
                    d.get("gdl90_port").toString(),
×
413
                    new DatagramPacket(
414
                        new byte[MAX_LENGTH],
415
                        MAX_LENGTH,
NEW
416
                        InetAddress.getByName(d.get("gdl90_host").toString()),
×
NEW
417
                        Integer.parseInt(d.get("gdl90_port").toString())),
×
418
                    true,
419
                    keepAliveConfig,
NEW
420
                    Instant.now(),
×
421
                    blackListed);
NEW
422
            if (newDevice.blackListed) {
×
NEW
423
              HostPortPair newPair =
×
NEW
424
                  new HostPortPair(d.get("gdl90_host").toString(), d.get("gdl90_port").toString());
×
NEW
425
              blackList.put(newPair, newDevice);
×
426
            }
427

NEW
428
            gdl90Devices.put(d.get("gdl90_host").toString(), newDevice);
×
429
          }
UNCOV
430
        }
×
431
      }
432

433
    } catch (SocketException | NumberFormatException | UnknownHostException e) {
×
434
      // TODO Auto-generated catch block
435
      e.printStackTrace();
×
436
    }
×
437

NEW
438
    String sourceString = this.getConfig().getString("DataSource", DataSource.BINARY.toString());
×
439

NEW
440
    source = DataSource.valueOf(sourceString);
×
441

NEW
442
    processorName = this.getConfig().getString("processor", "realtime");
×
443

NEW
444
    scheduler.scheduleAtFixedRate(
×
445
        () -> {
NEW
446
          if (isRunningAndEnabled()) {
×
NEW
447
            for (GDL90Device d : gdl90Devices.values()) {
×
NEW
448
              Instant now = Instant.now();
×
449

NEW
450
              Instant end = d.lastBroadcastTime;
×
NEW
451
              Duration timeElapsed = Duration.between(end, now);
×
452

NEW
453
              if (timeElapsed.toMillis() / 1000 > d.keepAliveSeconds) {
×
NEW
454
                gdl90Devices.remove(d.host);
×
455
              }
NEW
456
            }
×
457
          }
NEW
458
        },
×
459
        1,
460
        10,
461
        TimeUnit.SECONDS);
462

NEW
463
    initStreams();
×
NEW
464
  }
×
465

466
  private void initPVMode() {
NEW
467
    initGDL90Timers();
×
NEW
468
    yamcsHost = this.getConfig().getString("yamcsHost", "http://localhost");
×
NEW
469
    yamcsPort = this.getConfig().getInt("yamcsPort", 8090);
×
470

NEW
471
    pvMap =
×
NEW
472
        new ConcurrentHashMap<String, String>((Map) this.config.getMap("pvConfig").get("pvMap"));
×
473

NEW
474
    realtime = this.config.getBoolean("realtime", true);
×
475

NEW
476
    String sourceString = this.getConfig().getString("DataSource", DataSource.BINARY.toString());
×
477

NEW
478
    source = DataSource.valueOf(sourceString);
×
479

NEW
480
    String headingString =
×
NEW
481
        this.getConfig().getString("AHRSHeadingType", AHRSHeadingType.TRUE_HEADING.toString());
×
482

NEW
483
    headingType = AHRSHeadingType.valueOf(headingString);
×
484

NEW
485
    String ahrsModeString = (String) this.config.getMap("pvConfig").get("AHRS_Mode");
×
NEW
486
    String ahrsEncodingString = (String) this.config.getMap("pvConfig").get("AHRS_ENCODING");
×
487
    //    AHRS_ENCODING
488
    //    ahrsEncoding = AHRS_ENCODING.valueOf(ahrsEncodingString);
NEW
489
    ahrsMode = AHRS_MODE.valueOf(ahrsModeString);
×
490

NEW
491
    if (!this.realtime) {
×
NEW
492
      processorName = this.config.getString("processorName", "GDL90LinkReplay");
×
NEW
493
      start = this.config.getString("start");
×
NEW
494
      stop = this.config.getString("stop");
×
495
      try {
NEW
496
        startTimeStamp = Timestamps.parse(start);
×
NEW
497
      } catch (ParseException e) {
×
498
        // TODO Auto-generated catch block
NEW
499
        e.printStackTrace();
×
NEW
500
      }
×
501
      try {
NEW
502
        stopTimeStamp = Timestamps.parse(stop);
×
NEW
503
      } catch (ParseException e) {
×
504
        // TODO Auto-generated catch block
NEW
505
        e.printStackTrace();
×
NEW
506
      }
×
NEW
507
      replayOptions =
×
508
          new ReplayOptions(
NEW
509
              ReplayRequest.newBuilder()
×
NEW
510
                  .setStart(startTimeStamp)
×
NEW
511
                  .setStop(stopTimeStamp)
×
NEW
512
                  .setEndAction(EndAction.LOOP)
×
NEW
513
                  .setAutostart(true)
×
NEW
514
                  .build());
×
515

516
      try {
NEW
517
        processor =
×
NEW
518
            ProcessorFactory.create(
×
NEW
519
                yamcsInstance, processorName, "Archive", GDL90Link.class.toString(), replayOptions);
×
NEW
520
      } catch (ProcessorException
×
521
          | ConfigurationException
522
          | ValidationException
523
          | InitException e) {
524
        // TODO Auto-generated catch block
NEW
525
        e.printStackTrace();
×
NEW
526
      }
×
527
    } else {
NEW
528
      processorName = "realtime";
×
529
    }
530

531
    //    TODO: This is unnecessarily complicated
NEW
532
    yclient =
×
NEW
533
        YamcsClient.newBuilder(yamcsHost + ":" + yamcsPort)
×
534
            //            .withConnectionAttempts(config.getInt("connectionAttempts", 20))
535
            //            .withRetryDelay(reconnectionDelay)
536
            //            .withVerifyTls(config.getBoolean("verifyTls", true))
NEW
537
            .build();
×
NEW
538
    yclient.addConnectionListener(this);
×
539

540
    try {
NEW
541
      yclient.connectWebSocket();
×
NEW
542
    } catch (ClientException e) {
×
543
      // TODO Auto-generated catch block
NEW
544
      e.printStackTrace();
×
NEW
545
    }
×
NEW
546
  }
×
547

548
  /** Method only relevant when in PV mode */
549
  private void initGDL90Timers() {
550
    //          Defaults are based on
551
    // spec:https://www.faa.gov/sites/faa.gov/files/air_traffic/technology/adsb/archival/GDL90_Public_ICD_RevA.PDF,
552
    //          https://www.foreflight.com/connect/spec/
NEW
553
    heartbeatRate = this.config.getInt("heartbeatRate", 1);
×
NEW
554
    ownShipReportRate = this.config.getInt("ownShipReportRate", 1);
×
NEW
555
    ownShipGeoAltitudeRate = this.config.getInt("ownShipGeoAltitudeRate", 1);
×
NEW
556
    AHRSRate = this.config.getInt("AHRSRate", 5);
×
557

NEW
558
    WHLAHRSRate = this.config.getInt("WHLAHRSRate", 100);
×
UNCOV
559
    scheduler.scheduleAtFixedRate(
×
560
        () -> {
561
          if (isRunningAndEnabled()) {
×
562
            try {
563
              sendHeartbeat();
×
564

NEW
565
            } catch (IOException e) {
×
566
              // TODO Auto-generated catch block
NEW
567
              e.printStackTrace();
×
NEW
568
            }
×
569
          }
NEW
570
        },
×
571
        100,
572
        1000 / heartbeatRate,
573
        TimeUnit.MILLISECONDS);
574

NEW
575
    scheduler.scheduleAtFixedRate(
×
576
        () -> {
NEW
577
          if (isRunningAndEnabled()) {
×
578
            try {
579
              sendOwnshipReport();
×
580

NEW
581
            } catch (IOException e) {
×
582
              // TODO Auto-generated catch block
NEW
583
              e.printStackTrace();
×
NEW
584
            }
×
585
          }
NEW
586
        },
×
587
        100,
588
        1000 / ownShipReportRate,
589
        TimeUnit.MILLISECONDS);
590

NEW
591
    scheduler.scheduleAtFixedRate(
×
592
        () -> {
NEW
593
          if (isRunningAndEnabled()) {
×
594
            try {
595
              sendOwnshipGeoAltitude();
×
596

NEW
597
            } catch (IOException e) {
×
598
              // TODO Auto-generated catch block
NEW
599
              e.printStackTrace();
×
NEW
600
            }
×
601
          }
NEW
602
        },
×
603
        100,
604
        1000 / ownShipGeoAltitudeRate,
605
        TimeUnit.MILLISECONDS);
606

NEW
607
    scheduler.scheduleAtFixedRate(
×
608
        () -> {
NEW
609
          if (isRunningAndEnabled()) {
×
610
            try {
UNCOV
611
              sendForeFlightID();
×
612

613
            } catch (IOException e) {
×
614
              // TODO Auto-generated catch block
615
              e.printStackTrace();
×
616
            }
×
617
          }
618
        },
×
619
        100,
620
        1000,
621
        TimeUnit.MILLISECONDS);
622

623
    scheduler.scheduleAtFixedRate(
×
624
        () -> {
625
          if (isRunningAndEnabled()) {
×
626
            try {
627
              AHRSMessage();
×
628
            } catch (IOException e) {
×
629
              // TODO Auto-generated catch block
630
              e.printStackTrace();
×
631
            }
×
632
          }
633
        },
×
634
        100,
635
        1000 / AHRSRate,
636
        TimeUnit.MILLISECONDS);
637

638
    scheduler.scheduleAtFixedRate(
×
639
        () -> {
640
          if (isRunningAndEnabled()) {
×
641
            try {
NEW
642
              WHLAHRSMessage();
×
NEW
643
            } catch (IOException e) {
×
644
              // TODO Auto-generated catch block
NEW
645
              e.printStackTrace();
×
UNCOV
646
            }
×
647
          }
648
        },
×
649
        100,
650
        1000 / WHLAHRSRate,
651
        TimeUnit.MILLISECONDS);
UNCOV
652
  }
×
653

654
  private void initStreams() {
655
    YarchDatabaseInstance ydb = YarchDatabase.getInstance(this.yamcsInstance);
×
656

657
    heartbeatStreamName = this.getConfig().getString("heartbeatStream", null);
×
658

659
    if (heartbeatStreamName != null) {
×
660
      this.heartbeatStream = getStream(ydb, heartbeatStreamName);
×
661
    }
662

663
    ownShipReportStreamName = this.getConfig().getString("ownShipReportStreamName", null);
×
664

665
    if (ownShipReportStreamName != null) {
×
666
      this.ownShipReportStream = getStream(ydb, ownShipReportStreamName);
×
667
    }
668

669
    ownShipGeoAltitudeStreamName = this.getConfig().getString("ownShipGeoAltitudeStreamName", null);
×
670

671
    if (ownShipGeoAltitudeStreamName != null) {
×
672
      this.ownShipGeoAltitudeStream = getStream(ydb, ownShipGeoAltitudeStreamName);
×
673
    }
674

675
    ForeFlightIDStreamName = this.getConfig().getString("ForeFlightIDStreamName", null);
×
676

677
    if (ForeFlightIDStreamName != null) {
×
678
      this.ForeFlightIDStream = getStream(ydb, ForeFlightIDStreamName);
×
679
    }
680

681
    AHRSStreamName = this.getConfig().getString("AHRSStreamName", null);
×
682

683
    if (AHRSStreamName != null) {
×
684
      this.AHRSStream = getStream(ydb, AHRSStreamName);
×
685
    }
686

NEW
687
    WHLAHRSStreamName = this.getConfig().getString("WHLAHRSStreamName", null);
×
688

NEW
689
    if (WHLAHRSStreamName != null) {
×
NEW
690
      this.WHLAHRSStream = getStream(ydb, WHLAHRSStreamName);
×
691
    }
NEW
692
  }
×
693

694
  private void initBINARYMode() {
NEW
695
    init1HZ();
×
NEW
696
    init5HZ();
×
NEW
697
  }
×
698

699
  private void init1HZ() {
NEW
700
    YarchDatabaseInstance ydb = YarchDatabase.getInstance(this.yamcsInstance);
×
NEW
701
    _1HZ_MsgsStreamName = this.getConfig().getString("_1HZ_MsgsStreamName", "tm_realtime");
×
702

NEW
703
    if (_1HZ_MsgsStreamName != null) {
×
NEW
704
      this._1HZ_MsgsStream = getMsgStream(ydb, _1HZ_MsgsStreamName);
×
NEW
705
      _1HZ_MsgsStream.addSubscriber(this);
×
706
    }
707

NEW
708
    for (Object mid : this.getConfig().getList("1HZ_Messages")) {
×
NEW
709
      msgIds_1HZ.add((Integer) mid);
×
NEW
710
    }
×
NEW
711
  }
×
712

713
  private void init5HZ() {
NEW
714
    YarchDatabaseInstance ydb = YarchDatabase.getInstance(this.yamcsInstance);
×
NEW
715
    _5HZ_MsgsStreamName = this.getConfig().getString("_5HZ_MsgsStreamName", "tm_realtime");
×
716

NEW
717
    if (_5HZ_MsgsStreamName != null) {
×
NEW
718
      this._5HZ_MsgsStream = getMsgStream(ydb, _5HZ_MsgsStreamName);
×
719

720
      //      Do not subscribe twice to the same stream (such as realtime). Otherwise, the counts
721
      // will lie.
NEW
722
      if (!this._5HZ_MsgsStream.getSubscribers().contains(this)) {
×
NEW
723
        _5HZ_MsgsStream.addSubscriber(this);
×
724
      }
725
    }
726

NEW
727
    for (Object mid : this.getConfig().getList("5HZ_Messages")) {
×
NEW
728
      msgIds_5HZ.add((Integer) mid);
×
NEW
729
    }
×
UNCOV
730
  }
×
731

732
  private static Stream getStream(YarchDatabaseInstance ydb, String streamName) {
733
    Stream stream = ydb.getStream(streamName);
×
734
    if (stream == null) {
×
735
      try {
736
        ydb.execute("create stream " + streamName + gftdef.getStringDefinition());
×
737
      } catch (Exception e) {
×
738
        throw new ConfigurationException(e);
×
739
      }
×
740

741
      stream = ydb.getStream(streamName);
×
742

743
    } else {
744
      throw new ConfigurationException("Stream " + streamName + " already exists");
×
745
    }
746
    return stream;
×
747
  }
748

749
  /**
750
   * Our Message Streams MUST exist when in Binary mode
751
   *
752
   * @param ydb
753
   * @param streamName
754
   * @return
755
   */
756
  private static Stream getMsgStream(YarchDatabaseInstance ydb, String streamName) {
NEW
757
    Stream stream = ydb.getStream(streamName);
×
NEW
758
    if (stream == null) {
×
NEW
759
      throw new ConfigurationException("Stream " + streamName + " doesn't exist");
×
760
    }
NEW
761
    return stream;
×
762
  }
763

764
  @Override
765
  public void doDisable() {
766
    /* If the thread is created, interrupt it. */
767
    if (thread != null) {
×
768
      thread.interrupt();
×
769
    }
770
  }
×
771

772
  @Override
773
  public void doEnable() {
774
    /* Create and start the new thread. */
775
    thread = new Thread(this);
×
776
    thread.setName(this.getClass().getSimpleName() + "-" + linkName);
×
777
    thread.start();
×
778
  }
×
779

780
  @Override
781
  public String getDetailedStatus() {
782
    if (isDisabled()) {
×
783
      return String.format("DISABLED");
×
784
    } else {
785
      return String.format(
×
786
          "OK, Sent %d heartbeats, %d OwnshipReports, %d ownShipGeoAltitude(s), %d foreFlightIDs, %d AHRS(s), %d WHLAHRSCount(s) ",
787
          heartBeatCount,
×
788
          ownShipReportCount,
×
789
          ownshipGeoAltitudeCount,
×
790
          foreFlightIDCount,
×
NEW
791
          AHRSCount,
×
NEW
792
          WHLAHRSCount);
×
793
    }
794
  }
795

796
  @Override
797
  protected Status connectionStatus() {
798
    return Status.OK;
×
799
  }
800

801
  @Override
802
  protected void doStart() {
803
    if (!isDisabled()) {
×
804
      doEnable();
×
805
    }
NEW
806
    switch (source) {
×
807
      case BINARY:
808
        {
NEW
809
          initBINARYMode();
×
810
        }
811

NEW
812
        break;
×
813
      case PV:
814
        {
NEW
815
          initPVMode();
×
NEW
816
          if (!realtime) {
×
NEW
817
            log.info("Starting new processor '{}'", processor.getName());
×
NEW
818
            processor.startAsync();
×
NEW
819
            processor.awaitRunning();
×
820
          }
821
        }
822
        break;
823
      default:
824
        break;
825
    }
826
    notifyStarted();
×
827
  }
×
828

829
  @Override
830
  protected void doStop() {
831
    if (thread != null) {
×
832
      thread.interrupt();
×
833
    }
834

835
    notifyStopped();
×
836
  }
×
837

838
  @Override
839
  public void run() {
840
    /* Delay the start, if configured to do so. */
841
    if (initialDelay > 0) {
×
842
      try {
843
        Thread.sleep(initialDelay);
×
844
        initialDelay = -1;
×
845
      } catch (InterruptedException e) {
×
846
        Thread.currentThread().interrupt();
×
847
        return;
×
848
      }
×
849
    }
850

851
    /* Enter our main loop */
852
    while (isRunningAndEnabled()) {
×
853

854
      try {
855
        foreFlightSocket.receive(foreFlightdatagram);
×
856
        Gson gson = new Gson();
×
857
        if (!gdl90Devices.containsKey(foreFlightdatagram.getAddress().getHostAddress())) {
×
858
          String foreFlightJSON =
×
859
              new String(foreFlightdatagram.getData(), 0, foreFlightdatagram.getLength());
×
860
          ForeFlightBroadcast ffJSON = gson.fromJson(foreFlightJSON, ForeFlightBroadcast.class);
×
861

862
          gdl90Devices.put(
×
863
              foreFlightdatagram.getAddress().getHostAddress(),
×
864
              new GDL90Device(
865
                  foreFlightdatagram.getAddress().getHostAddress(),
×
866
                  Integer.toString(ffJSON.GDL90.port),
×
867
                  new DatagramPacket(
868
                      new byte[MAX_LENGTH],
869
                      MAX_LENGTH,
870
                      InetAddress.getByName(foreFlightdatagram.getAddress().getHostAddress()),
×
871
                      Integer.parseInt(Integer.toString(ffJSON.GDL90.port))),
×
872
                  true,
873
                  keepAliveConfig,
NEW
874
                  Instant.now(),
×
NEW
875
                  isBlackListed(
×
876
                      new HostPortPair(
NEW
877
                          foreFlightdatagram.getAddress().getHostAddress(),
×
NEW
878
                          Integer.toString(ffJSON.GDL90.port)))));
×
879
        } else {
×
880
          gdl90Devices.get(foreFlightdatagram.getAddress().getHostAddress()).lastBroadcastTime =
×
881
              Instant.now();
×
882
        }
883
      } catch (IOException e) {
×
884
        // TODO Auto-generated catch block
885
        e.printStackTrace();
×
886
      }
×
887
    }
888
  }
×
889

890
  private synchronized void sendHeartbeat() throws IOException {
891
    for (GDL90Device d : gdl90Devices.values()) {
×
NEW
892
      if (d.alive & !isBlackListed(new HostPortPair(d.host, d.port))) {
×
893
        GDL90Heartbeat beat = new GDL90Heartbeat();
×
894
        beat.GPSPosValid = true;
×
895
        beat.UATInitialized = true;
×
896
        beat.UTC_OK = true;
×
897
        byte[] gdlPacket = beat.toBytes();
×
898
        d.datagram.setData(gdlPacket);
×
899
        GDL90Socket.send(d.datagram);
×
NEW
900
        reportHeartbeatStatus(gdlPacket);
×
901
      }
902
    }
×
903
  }
×
904

905
  private void reportHeartbeatStatus(byte[] d) {
NEW
906
    heartBeatCount++;
×
NEW
907
    if (this.heartbeatStream != null) {
×
NEW
908
      this.heartbeatStream.emitTuple(
×
NEW
909
          new Tuple(gftdef, Arrays.asList(timeService.getMissionTime(), "Heartbeat", d)));
×
910
    }
NEW
911
  }
×
912

913
  private synchronized void sendForeFlightID() throws IOException {
914
    for (GDL90Device d : gdl90Devices.values()) {
×
NEW
915
      if (d.alive & !isBlackListed(new HostPortPair(d.host, d.port))) {
×
916

917
        ForeFlightIDMessage id = new ForeFlightIDMessage();
×
918

919
        id.DeviceSerialNum = 12;
×
920
        id.DeviceName = "Airliner";
×
921
        id.DeviceLongName = "Airliner";
×
922

923
        try {
924
          d.datagram.setData(id.toBytes());
×
925
        } catch (Exception e) {
×
926
          // TODO Auto-generated catch block
927
          e.printStackTrace();
×
928
        }
×
929
        GDL90Socket.send(d.datagram);
×
930

NEW
931
        reportForeFlightID(d.datagram.getData());
×
932
      }
933
    }
×
934
  }
×
935

936
  private void reportForeFlightID(byte[] d) {
NEW
937
    if (this.ForeFlightIDStream != null) {
×
NEW
938
      this.ForeFlightIDStream.emitTuple(
×
NEW
939
          new Tuple(gftdef, Arrays.asList(timeService.getMissionTime(), "ForeFlightID", d)));
×
940
    }
941

NEW
942
    foreFlightIDCount++;
×
NEW
943
  }
×
944

945
  private synchronized void sendOwnshipReport() throws IOException {
946

947
    for (GDL90Device d : gdl90Devices.values()) {
×
NEW
948
      if (d.alive & !isBlackListed(new HostPortPair(d.host, d.port))) {
×
949

950
        com.windhoverlabs.yamcs.gdl90.OwnshipReport ownship =
×
951
            new com.windhoverlabs.yamcs.gdl90.OwnshipReport();
952

953
        /**
954
         * Report Data: No Traffic Alert ICAO ADS-B Address (octal): 52642511 8 Latitude: 44.90708
955
         * (North) Longitude: -122.99488 (West) Altitude: 5,000 feet (pressure altitude) Airborne
956
         * with True Track HPL = 20 meters, HFOM = 25 meters (NIC = 10, NACp = 9) Horizontal
957
         * velocity: 123 knots at 45 degrees (True Track) Vertical velocity: 64 FPM climb
958
         * Emergency/Priority Code: none Emitter Category: Light Tail Number: N825
959
         */
960
        ownship.TrafficAlertStatus = false;
×
961
        ownship.AddressType = 0;
×
962
        //    The ParticipantAddress seems to impact the way Altitude gets displayed on ForeFlight
963
        ownship.ParticipantAddress = 0; // base 8
×
964
        ownship.Latitude = 44.90708;
×
965
        ownship.Longitude = -122.99488;
×
966
        //        TODO: Should be used for AHRS heading bit
NEW
967
        ownship.TrueHeading = this.config.getBoolean("TrueHeading", true);
×
968

969
        org.yamcs.protobuf.Pvalue.ParameterValue pvLatitude = paramsToSend.get("Latitude");
×
970

971
        if (pvLatitude != null) {
×
972
          switch (pvLatitude.getEngValue().getType()) {
×
973
            case AGGREGATE:
974
              break;
×
975
            case ARRAY:
976
              break;
×
977
            case BINARY:
978
              break;
×
979
            case BOOLEAN:
980
              break;
×
981
            case DOUBLE:
982
              ownship.Latitude = pvLatitude.getEngValue().getDoubleValue();
×
983
              break;
×
984
            case ENUMERATED:
985
              break;
×
986
            case FLOAT:
987
              ownship.Latitude = pvLatitude.getEngValue().getFloatValue();
×
988
              break;
×
989
            case NONE:
990
              break;
×
991
            case SINT32:
992
              break;
×
993
            case SINT64:
994
              break;
×
995
            case STRING:
996
              break;
×
997
            case TIMESTAMP:
998
              break;
×
999
            case UINT32:
1000
              break;
×
1001
            case UINT64:
1002
              break;
×
1003
            default:
1004
              break;
1005
          }
1006
        }
1007

1008
        org.yamcs.protobuf.Pvalue.ParameterValue pvLongitude = paramsToSend.get("Longitude");
×
1009

1010
        if (pvLongitude != null) {
×
1011
          switch (pvLongitude.getEngValue().getType()) {
×
1012
            case AGGREGATE:
1013
              break;
×
1014
            case ARRAY:
1015
              break;
×
1016
            case BINARY:
1017
              break;
×
1018
            case BOOLEAN:
1019
              break;
×
1020
            case DOUBLE:
1021
              ownship.Longitude = pvLongitude.getEngValue().getDoubleValue();
×
1022
              break;
×
1023
            case ENUMERATED:
1024
              break;
×
1025
            case FLOAT:
1026
              ownship.Longitude = pvLongitude.getEngValue().getFloatValue();
×
1027
              break;
×
1028
            case NONE:
1029
              break;
×
1030
            case SINT32:
1031
              break;
×
1032
            case SINT64:
1033
              break;
×
1034
            case STRING:
1035
              break;
×
1036
            case TIMESTAMP:
1037
              break;
×
1038
            case UINT32:
1039
              break;
×
1040
            case UINT64:
1041
              break;
×
1042
            default:
1043
              break;
1044
          }
1045
        }
1046

NEW
1047
        org.yamcs.protobuf.Pvalue.ParameterValue pvHorizontalSpeed =
×
NEW
1048
            paramsToSend.get("HorizontalSpeed");
×
1049

NEW
1050
        if (pvHorizontalSpeed != null) {
×
NEW
1051
          switch (pvHorizontalSpeed.getEngValue().getType()) {
×
1052
            case AGGREGATE:
1053
              break;
×
1054
            case ARRAY:
1055
              break;
×
1056
            case BINARY:
1057
              break;
×
1058
            case BOOLEAN:
1059
              break;
×
1060
            case DOUBLE:
1061
              //                    Assumes the PV is in meters/second. Convert to Knots
NEW
1062
              ownship.horizontalVelocity =
×
NEW
1063
                  (int) mpsToKnots((float) pvHorizontalSpeed.getEngValue().getDoubleValue());
×
UNCOV
1064
              break;
×
1065
            case ENUMERATED:
1066
              break;
×
1067
            case FLOAT:
NEW
1068
              ownship.horizontalVelocity =
×
NEW
1069
                  (int) mpsToKnots(pvHorizontalSpeed.getEngValue().getFloatValue());
×
UNCOV
1070
              break;
×
1071
            case NONE:
1072
              break;
×
1073
            case SINT32:
1074
              break;
×
1075
            case SINT64:
1076
              break;
×
1077
            case STRING:
1078
              break;
×
1079
            case TIMESTAMP:
1080
              break;
×
1081
            case UINT32:
1082
              break;
×
1083
            case UINT64:
1084
              break;
×
1085
            default:
1086
              break;
1087
          }
1088
        }
1089

NEW
1090
        ownship.Altitude = 1000;
×
NEW
1091
        ownship.TrueTrackAngle = true;
×
NEW
1092
        ownship.Airborne = true;
×
1093

NEW
1094
        ownship.i = 10;
×
NEW
1095
        ownship.a = 9;
×
1096

1097
        //        ownship.horizontalVelocity = 90; // Knots
1098

NEW
1099
        ownship.verticalVelocity = 64; // FPM
×
1100

NEW
1101
        ownship.trackHeading = 0; // Degrees
×
1102

NEW
1103
        ownship.ee = 1; // Should be an enum
×
1104

NEW
1105
        ownship.callSign = "N825V";
×
1106

1107
        try {
NEW
1108
          d.datagram.setData(ownship.toBytes());
×
NEW
1109
        } catch (Exception e) {
×
1110
          // TODO Auto-generated catch block
NEW
1111
          e.printStackTrace();
×
UNCOV
1112
        }
×
1113

NEW
1114
        ownship.px = 0;
×
NEW
1115
        GDL90Socket.send(d.datagram);
×
1116

NEW
1117
        reportOwnshipStatus(d.datagram.getData());
×
1118
      }
NEW
1119
    }
×
NEW
1120
  }
×
1121

1122
  private void reportOwnshipStatus(byte[] d) {
NEW
1123
    ownShipReportCount++;
×
1124

NEW
1125
    if (this.ownShipReportStream != null) {
×
NEW
1126
      this.ownShipReportStream.emitTuple(
×
NEW
1127
          new Tuple(gftdef, Arrays.asList(timeService.getMissionTime(), "ownShipReport", d)));
×
1128
    }
NEW
1129
  }
×
1130

1131
  private synchronized void AHRSMessage() throws IOException {
NEW
1132
    AHRS ahrs = newAHRS();
×
NEW
1133
    for (GDL90Device d : gdl90Devices.values()) {
×
1134

NEW
1135
      if (d.alive & !isBlackListed(new HostPortPair(d.host, d.port))) {
×
1136
        try {
NEW
1137
          d.datagram.setData(ahrs.toBytes());
×
NEW
1138
        } catch (Exception e) {
×
1139
          // TODO Auto-generated catch block
NEW
1140
          e.printStackTrace();
×
UNCOV
1141
        }
×
NEW
1142
        GDL90Socket.send(d.datagram);
×
NEW
1143
        reportAHRS(d.datagram.getData());
×
1144
      }
NEW
1145
    }
×
NEW
1146
  }
×
1147

1148
  private synchronized void WHLAHRSMessage() throws IOException {
NEW
1149
    WHL_AHRS ahrs = newWHLAHRS();
×
NEW
1150
    for (GDL90Device d : gdl90Devices.values()) {
×
1151

NEW
1152
      if (d.alive & !isBlackListed(new HostPortPair(d.host, d.port))) {
×
1153
        try {
1154
          d.datagram.setData(ahrs.toBytes());
×
1155
        } catch (Exception e) {
×
1156
          // TODO Auto-generated catch block
1157
          e.printStackTrace();
×
1158
        }
×
1159
        GDL90Socket.send(d.datagram);
×
NEW
1160
        reportWHLAHRS(d.datagram.getData());
×
1161
      }
NEW
1162
    }
×
NEW
1163
  }
×
1164

1165
  private AHRS newAHRS() {
NEW
1166
    AHRS ahrs = new AHRS();
×
NEW
1167
    getYPR(ahrs);
×
1168

NEW
1169
    ahrs.HeadingType = headingType;
×
NEW
1170
    return ahrs;
×
1171
  }
1172

1173
  private WHL_AHRS newWHLAHRS() {
NEW
1174
    WHL_AHRS ahrs = new WHL_AHRS();
×
NEW
1175
    getYPR(ahrs);
×
NEW
1176
    return ahrs;
×
1177
  }
1178

1179
  private void getYPR(AHRS ahrs) {
NEW
1180
    switch (ahrsMode) {
×
1181
      case QT:
NEW
1182
        calcQT(ahrs);
×
NEW
1183
        break;
×
1184
      case YPR:
NEW
1185
        calcYPR(ahrs);
×
NEW
1186
        break;
×
1187
      default:
1188
        break;
1189
    }
NEW
1190
  }
×
1191

1192
  private void getYPR(WHL_AHRS ahrs) {
NEW
1193
    switch (ahrsMode) {
×
1194
      case QT:
NEW
1195
        calcQT(ahrs);
×
NEW
1196
        break;
×
1197
      case YPR:
NEW
1198
        calcYPR(ahrs);
×
NEW
1199
        break;
×
1200
      default:
1201
        break;
1202
    }
NEW
1203
  }
×
1204

1205
  private void calcYPR(AHRS ahrs) {
NEW
1206
    org.yamcs.protobuf.Pvalue.ParameterValue pvRoll = paramsToSend.get("Roll");
×
1207

NEW
1208
    if (pvRoll != null) {
×
NEW
1209
      switch (pvRoll.getEngValue().getType()) {
×
1210
        case AGGREGATE:
NEW
1211
          break;
×
1212
        case ARRAY:
NEW
1213
          break;
×
1214
        case BINARY:
NEW
1215
          break;
×
1216
        case BOOLEAN:
NEW
1217
          break;
×
1218
        case DOUBLE:
NEW
1219
          ahrs.Roll = pvRoll.getEngValue().getDoubleValue();
×
NEW
1220
          break;
×
1221
        case ENUMERATED:
NEW
1222
          break;
×
1223
        case FLOAT:
NEW
1224
          ahrs.Roll = pvRoll.getEngValue().getFloatValue();
×
NEW
1225
          break;
×
1226
        case NONE:
NEW
1227
          break;
×
1228
        case SINT32:
NEW
1229
          break;
×
1230
        case SINT64:
NEW
1231
          break;
×
1232
        case STRING:
NEW
1233
          break;
×
1234
        case TIMESTAMP:
NEW
1235
          break;
×
1236
        case UINT32:
NEW
1237
          break;
×
1238
        case UINT64:
NEW
1239
          break;
×
1240
        default:
1241
          break;
1242
      }
1243
    }
1244

NEW
1245
    org.yamcs.protobuf.Pvalue.ParameterValue pvPitch = paramsToSend.get("Pitch");
×
1246

NEW
1247
    if (pvPitch != null) {
×
NEW
1248
      switch (pvPitch.getEngValue().getType()) {
×
1249
        case AGGREGATE:
NEW
1250
          break;
×
1251
        case ARRAY:
NEW
1252
          break;
×
1253
        case BINARY:
NEW
1254
          break;
×
1255
        case BOOLEAN:
NEW
1256
          break;
×
1257
        case DOUBLE:
NEW
1258
          ahrs.Pitch = pvPitch.getEngValue().getDoubleValue();
×
NEW
1259
          break;
×
1260
        case ENUMERATED:
NEW
1261
          break;
×
1262
        case FLOAT:
NEW
1263
          ahrs.Pitch = pvPitch.getEngValue().getFloatValue();
×
NEW
1264
          break;
×
1265
        case NONE:
NEW
1266
          break;
×
1267
        case SINT32:
NEW
1268
          break;
×
1269
        case SINT64:
NEW
1270
          break;
×
1271
        case STRING:
NEW
1272
          break;
×
1273
        case TIMESTAMP:
NEW
1274
          break;
×
1275
        case UINT32:
NEW
1276
          break;
×
1277
        case UINT64:
NEW
1278
          break;
×
1279
        default:
1280
          break;
1281
      }
1282
    }
1283

NEW
1284
    org.yamcs.protobuf.Pvalue.ParameterValue pvAHRS_Heading = paramsToSend.get("AHRS_Heading");
×
1285

NEW
1286
    if (pvAHRS_Heading != null) {
×
NEW
1287
      switch (pvAHRS_Heading.getEngValue().getType()) {
×
1288
        case AGGREGATE:
NEW
1289
          break;
×
1290
        case ARRAY:
NEW
1291
          break;
×
1292
        case BINARY:
NEW
1293
          break;
×
1294
        case BOOLEAN:
NEW
1295
          break;
×
1296
        case DOUBLE:
NEW
1297
          ahrs.Heading = pvAHRS_Heading.getEngValue().getDoubleValue();
×
NEW
1298
          break;
×
1299
        case ENUMERATED:
NEW
1300
          break;
×
1301
        case FLOAT:
NEW
1302
          ahrs.Heading = pvAHRS_Heading.getEngValue().getFloatValue();
×
NEW
1303
          break;
×
1304
        case NONE:
NEW
1305
          break;
×
1306
        case SINT32:
NEW
1307
          break;
×
1308
        case SINT64:
NEW
1309
          break;
×
1310
        case STRING:
NEW
1311
          break;
×
1312
        case TIMESTAMP:
NEW
1313
          break;
×
1314
        case UINT32:
NEW
1315
          break;
×
1316
        case UINT64:
NEW
1317
          break;
×
1318
        default:
1319
          break;
1320
      }
1321
    }
NEW
1322
  }
×
1323

1324
  private void calcYPR(WHL_AHRS ahrs) {
NEW
1325
    org.yamcs.protobuf.Pvalue.ParameterValue pvRoll = paramsToSend.get("Roll");
×
1326

NEW
1327
    org.yamcs.protobuf.Pvalue.ParameterValue pvAltitude = paramsToSend.get("Altitude");
×
1328

NEW
1329
    org.yamcs.protobuf.Pvalue.ParameterValue pvLatitude = paramsToSend.get("Latitude");
×
1330

NEW
1331
    if (pvLatitude != null) {
×
NEW
1332
      switch (pvLatitude.getEngValue().getType()) {
×
1333
        case AGGREGATE:
NEW
1334
          break;
×
1335
        case ARRAY:
NEW
1336
          break;
×
1337
        case BINARY:
NEW
1338
          break;
×
1339
        case BOOLEAN:
NEW
1340
          break;
×
1341
        case DOUBLE:
NEW
1342
          ahrs.Lat = pvLatitude.getEngValue().getDoubleValue();
×
NEW
1343
          break;
×
1344
        case ENUMERATED:
NEW
1345
          break;
×
1346
        case FLOAT:
NEW
1347
          ahrs.Lat = pvLatitude.getEngValue().getFloatValue();
×
NEW
1348
          break;
×
1349
        case NONE:
NEW
1350
          break;
×
1351
        case SINT32:
NEW
1352
          break;
×
1353
        case SINT64:
NEW
1354
          break;
×
1355
        case STRING:
NEW
1356
          break;
×
1357
        case TIMESTAMP:
NEW
1358
          break;
×
1359
        case UINT32:
NEW
1360
          break;
×
1361
        case UINT64:
NEW
1362
          break;
×
1363
        default:
1364
          break;
1365
      }
1366
    }
1367

NEW
1368
    org.yamcs.protobuf.Pvalue.ParameterValue pvLongitude = paramsToSend.get("Longitude");
×
1369

NEW
1370
    if (pvLongitude != null) {
×
NEW
1371
      switch (pvLongitude.getEngValue().getType()) {
×
1372
        case AGGREGATE:
NEW
1373
          break;
×
1374
        case ARRAY:
NEW
1375
          break;
×
1376
        case BINARY:
NEW
1377
          break;
×
1378
        case BOOLEAN:
NEW
1379
          break;
×
1380
        case DOUBLE:
NEW
1381
          ahrs.Lon = pvLongitude.getEngValue().getDoubleValue();
×
NEW
1382
          break;
×
1383
        case ENUMERATED:
NEW
1384
          break;
×
1385
        case FLOAT:
NEW
1386
          ahrs.Lon = pvLongitude.getEngValue().getFloatValue();
×
NEW
1387
          break;
×
1388
        case NONE:
NEW
1389
          break;
×
1390
        case SINT32:
NEW
1391
          break;
×
1392
        case SINT64:
NEW
1393
          break;
×
1394
        case STRING:
NEW
1395
          break;
×
1396
        case TIMESTAMP:
NEW
1397
          break;
×
1398
        case UINT32:
NEW
1399
          break;
×
1400
        case UINT64:
NEW
1401
          break;
×
1402
        default:
1403
          break;
1404
      }
1405
    }
1406

NEW
1407
    if (pvAltitude != null) {
×
NEW
1408
      switch (pvAltitude.getEngValue().getType()) {
×
1409
        case AGGREGATE:
NEW
1410
          break;
×
1411
        case ARRAY:
NEW
1412
          break;
×
1413
        case BINARY:
NEW
1414
          break;
×
1415
        case BOOLEAN:
NEW
1416
          break;
×
1417
        case DOUBLE:
1418
          //                    Meters to feet. Should be made configurable, maybe...
NEW
1419
          ahrs.Alt = (pvAltitude.getEngValue().getDoubleValue() * 3.28084);
×
NEW
1420
          break;
×
1421
        case ENUMERATED:
NEW
1422
          break;
×
1423
        case FLOAT:
1424
          //                    Meters to feet. Should be made configurable, maybe...
NEW
1425
          ahrs.Alt = (pvAltitude.getEngValue().getFloatValue() * 3.28084);
×
NEW
1426
          break;
×
1427
        case NONE:
NEW
1428
          break;
×
1429
        case SINT32:
NEW
1430
          break;
×
1431
        case SINT64:
NEW
1432
          break;
×
1433
        case STRING:
NEW
1434
          break;
×
1435
        case TIMESTAMP:
NEW
1436
          break;
×
1437
        case UINT32:
NEW
1438
          break;
×
1439
        case UINT64:
NEW
1440
          break;
×
1441
        default:
1442
          break;
1443
      }
1444
    }
1445

NEW
1446
    if (pvRoll != null) {
×
NEW
1447
      switch (pvRoll.getEngValue().getType()) {
×
1448
        case AGGREGATE:
NEW
1449
          break;
×
1450
        case ARRAY:
NEW
1451
          break;
×
1452
        case BINARY:
NEW
1453
          break;
×
1454
        case BOOLEAN:
NEW
1455
          break;
×
1456
        case DOUBLE:
NEW
1457
          ahrs.Roll = pvRoll.getEngValue().getDoubleValue();
×
NEW
1458
          break;
×
1459
        case ENUMERATED:
NEW
1460
          break;
×
1461
        case FLOAT:
NEW
1462
          ahrs.Roll = pvRoll.getEngValue().getFloatValue();
×
NEW
1463
          break;
×
1464
        case NONE:
NEW
1465
          break;
×
1466
        case SINT32:
NEW
1467
          break;
×
1468
        case SINT64:
NEW
1469
          break;
×
1470
        case STRING:
NEW
1471
          break;
×
1472
        case TIMESTAMP:
NEW
1473
          break;
×
1474
        case UINT32:
NEW
1475
          break;
×
1476
        case UINT64:
NEW
1477
          break;
×
1478
        default:
1479
          break;
1480
      }
1481
    }
1482

NEW
1483
    org.yamcs.protobuf.Pvalue.ParameterValue pvPitch = paramsToSend.get("Pitch");
×
1484

NEW
1485
    if (pvPitch != null) {
×
NEW
1486
      switch (pvPitch.getEngValue().getType()) {
×
1487
        case AGGREGATE:
NEW
1488
          break;
×
1489
        case ARRAY:
NEW
1490
          break;
×
1491
        case BINARY:
NEW
1492
          break;
×
1493
        case BOOLEAN:
NEW
1494
          break;
×
1495
        case DOUBLE:
NEW
1496
          ahrs.Pitch = pvPitch.getEngValue().getDoubleValue();
×
NEW
1497
          break;
×
1498
        case ENUMERATED:
NEW
1499
          break;
×
1500
        case FLOAT:
NEW
1501
          ahrs.Pitch = pvPitch.getEngValue().getFloatValue();
×
NEW
1502
          break;
×
1503
        case NONE:
NEW
1504
          break;
×
1505
        case SINT32:
NEW
1506
          break;
×
1507
        case SINT64:
NEW
1508
          break;
×
1509
        case STRING:
NEW
1510
          break;
×
1511
        case TIMESTAMP:
NEW
1512
          break;
×
1513
        case UINT32:
NEW
1514
          break;
×
1515
        case UINT64:
NEW
1516
          break;
×
1517
        default:
1518
          break;
1519
      }
1520
    }
1521

NEW
1522
    org.yamcs.protobuf.Pvalue.ParameterValue pvAHRS_Heading = paramsToSend.get("AHRS_Heading");
×
1523

NEW
1524
    if (pvAHRS_Heading != null) {
×
NEW
1525
      switch (pvAHRS_Heading.getEngValue().getType()) {
×
1526
        case AGGREGATE:
NEW
1527
          break;
×
1528
        case ARRAY:
NEW
1529
          break;
×
1530
        case BINARY:
NEW
1531
          break;
×
1532
        case BOOLEAN:
NEW
1533
          break;
×
1534
        case DOUBLE:
NEW
1535
          ahrs.Heading = pvAHRS_Heading.getEngValue().getDoubleValue();
×
NEW
1536
          break;
×
1537
        case ENUMERATED:
NEW
1538
          break;
×
1539
        case FLOAT:
NEW
1540
          ahrs.Heading = pvAHRS_Heading.getEngValue().getFloatValue();
×
NEW
1541
          break;
×
1542
        case NONE:
NEW
1543
          break;
×
1544
        case SINT32:
NEW
1545
          break;
×
1546
        case SINT64:
NEW
1547
          break;
×
1548
        case STRING:
NEW
1549
          break;
×
1550
        case TIMESTAMP:
NEW
1551
          break;
×
1552
        case UINT32:
NEW
1553
          break;
×
1554
        case UINT64:
NEW
1555
          break;
×
1556
        default:
1557
          break;
1558
      }
1559
    }
1560

NEW
1561
    org.yamcs.protobuf.Pvalue.ParameterValue northVel = paramsToSend.get("NorthVel");
×
1562

NEW
1563
    if (northVel != null) {
×
NEW
1564
      switch (northVel.getEngValue().getType()) {
×
1565
        case AGGREGATE:
NEW
1566
          break;
×
1567
        case ARRAY:
NEW
1568
          break;
×
1569
        case BINARY:
NEW
1570
          break;
×
1571
        case BOOLEAN:
NEW
1572
          break;
×
1573
        case DOUBLE:
1574
          //                    Assumes the PV is in meters/second. Convert to Knots
NEW
1575
          ahrs.northVel = northVel.getEngValue().getDoubleValue();
×
NEW
1576
          break;
×
1577
        case ENUMERATED:
NEW
1578
          break;
×
1579
        case FLOAT:
NEW
1580
          ahrs.northVel = northVel.getEngValue().getFloatValue();
×
NEW
1581
          break;
×
1582
        case NONE:
NEW
1583
          break;
×
1584
        case SINT32:
NEW
1585
          break;
×
1586
        case SINT64:
NEW
1587
          break;
×
1588
        case STRING:
NEW
1589
          break;
×
1590
        case TIMESTAMP:
NEW
1591
          break;
×
1592
        case UINT32:
NEW
1593
          break;
×
1594
        case UINT64:
NEW
1595
          break;
×
1596
        default:
1597
          break;
1598
      }
1599
    }
1600

NEW
1601
    org.yamcs.protobuf.Pvalue.ParameterValue eastVel = paramsToSend.get("EastVel");
×
1602

NEW
1603
    if (eastVel != null) {
×
NEW
1604
      switch (eastVel.getEngValue().getType()) {
×
1605
        case AGGREGATE:
NEW
1606
          break;
×
1607
        case ARRAY:
NEW
1608
          break;
×
1609
        case BINARY:
NEW
1610
          break;
×
1611
        case BOOLEAN:
NEW
1612
          break;
×
1613
        case DOUBLE:
1614
          //                    Assumes the PV is in meters/second. Convert to Knots
NEW
1615
          ahrs.eastVel = eastVel.getEngValue().getDoubleValue();
×
NEW
1616
          break;
×
1617
        case ENUMERATED:
NEW
1618
          break;
×
1619
        case FLOAT:
NEW
1620
          ahrs.eastVel = eastVel.getEngValue().getFloatValue();
×
NEW
1621
          break;
×
1622
        case NONE:
NEW
1623
          break;
×
1624
        case SINT32:
NEW
1625
          break;
×
1626
        case SINT64:
NEW
1627
          break;
×
1628
        case STRING:
NEW
1629
          break;
×
1630
        case TIMESTAMP:
NEW
1631
          break;
×
1632
        case UINT32:
NEW
1633
          break;
×
1634
        case UINT64:
NEW
1635
          break;
×
1636
        default:
1637
          break;
1638
      }
1639
    }
1640

NEW
1641
    org.yamcs.protobuf.Pvalue.ParameterValue downVel = paramsToSend.get("DownVel");
×
1642

NEW
1643
    if (downVel != null) {
×
NEW
1644
      switch (downVel.getEngValue().getType()) {
×
1645
        case AGGREGATE:
NEW
1646
          break;
×
1647
        case ARRAY:
NEW
1648
          break;
×
1649
        case BINARY:
NEW
1650
          break;
×
1651
        case BOOLEAN:
NEW
1652
          break;
×
1653
        case DOUBLE:
1654
          //                    Assumes the PV is in meters/second. Convert to Knots
NEW
1655
          ahrs.downVel = downVel.getEngValue().getDoubleValue();
×
NEW
1656
          break;
×
1657
        case ENUMERATED:
NEW
1658
          break;
×
1659
        case FLOAT:
NEW
1660
          ahrs.downVel = downVel.getEngValue().getFloatValue();
×
NEW
1661
          break;
×
1662
        case NONE:
NEW
1663
          break;
×
1664
        case SINT32:
NEW
1665
          break;
×
1666
        case SINT64:
NEW
1667
          break;
×
1668
        case STRING:
NEW
1669
          break;
×
1670
        case TIMESTAMP:
NEW
1671
          break;
×
1672
        case UINT32:
NEW
1673
          break;
×
1674
        case UINT64:
NEW
1675
          break;
×
1676
        default:
1677
          break;
1678
      }
1679
    }
NEW
1680
  }
×
1681

1682
  private void calcQT(AHRS ahrs) {
NEW
1683
    org.yamcs.protobuf.Pvalue.ParameterValue qt = paramsToSend.get("Qt");
×
NEW
1684
    QT newQT = new QT();
×
NEW
1685
    if (qt != null) {
×
NEW
1686
      switch (qt.getEngValue().getType()) {
×
1687
        case AGGREGATE:
NEW
1688
          break;
×
1689
        case ARRAY:
NEW
1690
          java.util.List<org.yamcs.protobuf.Yamcs.Value> l = qt.getEngValue().getArrayValueList();
×
NEW
1691
          for (int i = 0; i < l.size(); i++) {
×
NEW
1692
            switch (l.get(i).getType()) {
×
1693
              case AGGREGATE:
NEW
1694
                break;
×
1695
              case ARRAY:
NEW
1696
                break;
×
1697
              case BINARY:
NEW
1698
                break;
×
1699
              case BOOLEAN:
NEW
1700
                break;
×
1701
              case DOUBLE:
NEW
1702
                newQT.data[i] = l.get(i).getDoubleValue();
×
NEW
1703
                break;
×
1704
              case ENUMERATED:
NEW
1705
                break;
×
1706
              case FLOAT:
NEW
1707
                newQT.data[i] = l.get(i).getFloatValue();
×
1708
              case NONE:
NEW
1709
                break;
×
1710
              case SINT32:
NEW
1711
                break;
×
1712
              case SINT64:
NEW
1713
                break;
×
1714
              case STRING:
NEW
1715
                break;
×
1716
              case TIMESTAMP:
NEW
1717
                break;
×
1718
              case UINT32:
NEW
1719
                break;
×
1720
              case UINT64:
NEW
1721
                break;
×
1722
              default:
1723
                break;
1724
            }
1725
          }
NEW
1726
          break;
×
1727
        case BINARY:
NEW
1728
          break;
×
1729
        case BOOLEAN:
NEW
1730
          break;
×
1731
        case DOUBLE:
NEW
1732
          break;
×
1733
        case ENUMERATED:
NEW
1734
          break;
×
1735
        case FLOAT:
NEW
1736
          break;
×
1737
        case NONE:
NEW
1738
          break;
×
1739
        case SINT32:
NEW
1740
          break;
×
1741
        case SINT64:
NEW
1742
          break;
×
1743
        case STRING:
NEW
1744
          break;
×
1745
        case TIMESTAMP:
NEW
1746
          break;
×
1747
        case UINT32:
NEW
1748
          break;
×
1749
        case UINT64:
NEW
1750
          break;
×
1751
        default:
1752
          break;
1753
      }
1754
    }
1755

NEW
1756
    YPR newYPR = qtToYPR(newQT);
×
NEW
1757
    ahrs.Heading = newYPR.yaw;
×
NEW
1758
    ahrs.Pitch = newYPR.pitch;
×
NEW
1759
    ahrs.Roll = newYPR.roll;
×
NEW
1760
  }
×
1761

1762
  private void calcQT(WHL_AHRS ahrs) {
NEW
1763
    org.yamcs.protobuf.Pvalue.ParameterValue qt = paramsToSend.get("Qt");
×
1764

NEW
1765
    org.yamcs.protobuf.Pvalue.ParameterValue pvAltitude = paramsToSend.get("Altitude");
×
1766

NEW
1767
    org.yamcs.protobuf.Pvalue.ParameterValue pvLatitude = paramsToSend.get("Latitude");
×
1768

NEW
1769
    if (pvLatitude != null) {
×
NEW
1770
      switch (pvLatitude.getEngValue().getType()) {
×
1771
        case AGGREGATE:
NEW
1772
          break;
×
1773
        case ARRAY:
NEW
1774
          break;
×
1775
        case BINARY:
NEW
1776
          break;
×
1777
        case BOOLEAN:
NEW
1778
          break;
×
1779
        case DOUBLE:
NEW
1780
          ahrs.Lat = pvLatitude.getEngValue().getDoubleValue();
×
NEW
1781
          break;
×
1782
        case ENUMERATED:
NEW
1783
          break;
×
1784
        case FLOAT:
NEW
1785
          ahrs.Lat = pvLatitude.getEngValue().getFloatValue();
×
NEW
1786
          break;
×
1787
        case NONE:
NEW
1788
          break;
×
1789
        case SINT32:
NEW
1790
          break;
×
1791
        case SINT64:
NEW
1792
          break;
×
1793
        case STRING:
NEW
1794
          break;
×
1795
        case TIMESTAMP:
NEW
1796
          break;
×
1797
        case UINT32:
NEW
1798
          break;
×
1799
        case UINT64:
NEW
1800
          break;
×
1801
        default:
1802
          break;
1803
      }
1804
    }
1805

NEW
1806
    org.yamcs.protobuf.Pvalue.ParameterValue pvLongitude = paramsToSend.get("Longitude");
×
1807

NEW
1808
    if (pvLongitude != null) {
×
NEW
1809
      switch (pvLongitude.getEngValue().getType()) {
×
1810
        case AGGREGATE:
NEW
1811
          break;
×
1812
        case ARRAY:
NEW
1813
          break;
×
1814
        case BINARY:
NEW
1815
          break;
×
1816
        case BOOLEAN:
NEW
1817
          break;
×
1818
        case DOUBLE:
NEW
1819
          ahrs.Lon = pvLongitude.getEngValue().getDoubleValue();
×
NEW
1820
          break;
×
1821
        case ENUMERATED:
NEW
1822
          break;
×
1823
        case FLOAT:
NEW
1824
          ahrs.Lon = pvLongitude.getEngValue().getFloatValue();
×
NEW
1825
          break;
×
1826
        case NONE:
NEW
1827
          break;
×
1828
        case SINT32:
NEW
1829
          break;
×
1830
        case SINT64:
NEW
1831
          break;
×
1832
        case STRING:
NEW
1833
          break;
×
1834
        case TIMESTAMP:
NEW
1835
          break;
×
1836
        case UINT32:
NEW
1837
          break;
×
1838
        case UINT64:
NEW
1839
          break;
×
1840
        default:
1841
          break;
1842
      }
1843
    }
1844

NEW
1845
    if (pvAltitude != null) {
×
NEW
1846
      switch (pvAltitude.getEngValue().getType()) {
×
1847
        case AGGREGATE:
NEW
1848
          break;
×
1849
        case ARRAY:
NEW
1850
          break;
×
1851
        case BINARY:
NEW
1852
          break;
×
1853
        case BOOLEAN:
NEW
1854
          break;
×
1855
        case DOUBLE:
1856
          //                    Meters to feet. Should be made configurable, maybe...
NEW
1857
          ahrs.Alt = (pvAltitude.getEngValue().getDoubleValue() * 3.28084);
×
NEW
1858
          break;
×
1859
        case ENUMERATED:
NEW
1860
          break;
×
1861
        case FLOAT:
1862
          //                    Meters to feet. Should be made configurable, maybe...
NEW
1863
          ahrs.Alt = (pvAltitude.getEngValue().getFloatValue() * 3.28084);
×
NEW
1864
          break;
×
1865
        case NONE:
NEW
1866
          break;
×
1867
        case SINT32:
NEW
1868
          break;
×
1869
        case SINT64:
NEW
1870
          break;
×
1871
        case STRING:
NEW
1872
          break;
×
1873
        case TIMESTAMP:
NEW
1874
          break;
×
1875
        case UINT32:
NEW
1876
          break;
×
1877
        case UINT64:
NEW
1878
          break;
×
1879
        default:
1880
          break;
1881
      }
1882
    }
1883

NEW
1884
    org.yamcs.protobuf.Pvalue.ParameterValue northVel = paramsToSend.get("NorthVel");
×
1885

NEW
1886
    if (northVel != null) {
×
NEW
1887
      switch (northVel.getEngValue().getType()) {
×
1888
        case AGGREGATE:
NEW
1889
          break;
×
1890
        case ARRAY:
NEW
1891
          break;
×
1892
        case BINARY:
NEW
1893
          break;
×
1894
        case BOOLEAN:
NEW
1895
          break;
×
1896
        case DOUBLE:
1897
          //                    Assumes the PV is in meters/second. Convert to Knots
NEW
1898
          ahrs.northVel = northVel.getEngValue().getDoubleValue();
×
NEW
1899
          break;
×
1900
        case ENUMERATED:
NEW
1901
          break;
×
1902
        case FLOAT:
NEW
1903
          ahrs.northVel = northVel.getEngValue().getFloatValue();
×
NEW
1904
          break;
×
1905
        case NONE:
NEW
1906
          break;
×
1907
        case SINT32:
NEW
1908
          break;
×
1909
        case SINT64:
NEW
1910
          break;
×
1911
        case STRING:
NEW
1912
          break;
×
1913
        case TIMESTAMP:
NEW
1914
          break;
×
1915
        case UINT32:
NEW
1916
          break;
×
1917
        case UINT64:
NEW
1918
          break;
×
1919
        default:
1920
          break;
1921
      }
1922
    }
1923

NEW
1924
    org.yamcs.protobuf.Pvalue.ParameterValue eastVel = paramsToSend.get("EastVel");
×
1925

NEW
1926
    if (eastVel != null) {
×
NEW
1927
      switch (eastVel.getEngValue().getType()) {
×
1928
        case AGGREGATE:
NEW
1929
          break;
×
1930
        case ARRAY:
NEW
1931
          break;
×
1932
        case BINARY:
NEW
1933
          break;
×
1934
        case BOOLEAN:
NEW
1935
          break;
×
1936
        case DOUBLE:
1937
          //                    Assumes the PV is in meters/second. Convert to Knots
NEW
1938
          ahrs.eastVel = eastVel.getEngValue().getDoubleValue();
×
NEW
1939
          break;
×
1940
        case ENUMERATED:
NEW
1941
          break;
×
1942
        case FLOAT:
NEW
1943
          ahrs.eastVel = eastVel.getEngValue().getFloatValue();
×
NEW
1944
          break;
×
1945
        case NONE:
NEW
1946
          break;
×
1947
        case SINT32:
NEW
1948
          break;
×
1949
        case SINT64:
NEW
1950
          break;
×
1951
        case STRING:
NEW
1952
          break;
×
1953
        case TIMESTAMP:
NEW
1954
          break;
×
1955
        case UINT32:
NEW
1956
          break;
×
1957
        case UINT64:
NEW
1958
          break;
×
1959
        default:
1960
          break;
1961
      }
1962
    }
1963

NEW
1964
    org.yamcs.protobuf.Pvalue.ParameterValue downVel = paramsToSend.get("DownVel");
×
1965

NEW
1966
    if (downVel != null) {
×
NEW
1967
      switch (downVel.getEngValue().getType()) {
×
1968
        case AGGREGATE:
NEW
1969
          break;
×
1970
        case ARRAY:
NEW
1971
          break;
×
1972
        case BINARY:
NEW
1973
          break;
×
1974
        case BOOLEAN:
NEW
1975
          break;
×
1976
        case DOUBLE:
1977
          //                    Assumes the PV is in meters/second. Convert to Knots
NEW
1978
          ahrs.downVel = downVel.getEngValue().getDoubleValue();
×
NEW
1979
          break;
×
1980
        case ENUMERATED:
NEW
1981
          break;
×
1982
        case FLOAT:
NEW
1983
          ahrs.downVel = downVel.getEngValue().getFloatValue();
×
NEW
1984
          break;
×
1985
        case NONE:
NEW
1986
          break;
×
1987
        case SINT32:
NEW
1988
          break;
×
1989
        case SINT64:
NEW
1990
          break;
×
1991
        case STRING:
NEW
1992
          break;
×
1993
        case TIMESTAMP:
NEW
1994
          break;
×
1995
        case UINT32:
NEW
1996
          break;
×
1997
        case UINT64:
NEW
1998
          break;
×
1999
        default:
2000
          break;
2001
      }
2002
    }
NEW
2003
    QT newQT = new QT();
×
NEW
2004
    if (qt != null) {
×
NEW
2005
      switch (qt.getEngValue().getType()) {
×
2006
        case AGGREGATE:
NEW
2007
          break;
×
2008
        case ARRAY:
NEW
2009
          java.util.List<org.yamcs.protobuf.Yamcs.Value> l = qt.getEngValue().getArrayValueList();
×
NEW
2010
          for (int i = 0; i < l.size(); i++) {
×
NEW
2011
            switch (l.get(i).getType()) {
×
2012
              case AGGREGATE:
NEW
2013
                break;
×
2014
              case ARRAY:
NEW
2015
                break;
×
2016
              case BINARY:
NEW
2017
                break;
×
2018
              case BOOLEAN:
NEW
2019
                break;
×
2020
              case DOUBLE:
NEW
2021
                newQT.data[i] = l.get(i).getDoubleValue();
×
NEW
2022
                break;
×
2023
              case ENUMERATED:
NEW
2024
                break;
×
2025
              case FLOAT:
NEW
2026
                newQT.data[i] = l.get(i).getFloatValue();
×
2027
              case NONE:
NEW
2028
                break;
×
2029
              case SINT32:
NEW
2030
                break;
×
2031
              case SINT64:
NEW
2032
                break;
×
2033
              case STRING:
NEW
2034
                break;
×
2035
              case TIMESTAMP:
NEW
2036
                break;
×
2037
              case UINT32:
NEW
2038
                break;
×
2039
              case UINT64:
NEW
2040
                break;
×
2041
              default:
2042
                break;
2043
            }
2044
          }
NEW
2045
          break;
×
2046
        case BINARY:
NEW
2047
          break;
×
2048
        case BOOLEAN:
NEW
2049
          break;
×
2050
        case DOUBLE:
NEW
2051
          break;
×
2052
        case ENUMERATED:
NEW
2053
          break;
×
2054
        case FLOAT:
NEW
2055
          break;
×
2056
        case NONE:
NEW
2057
          break;
×
2058
        case SINT32:
NEW
2059
          break;
×
2060
        case SINT64:
NEW
2061
          break;
×
2062
        case STRING:
NEW
2063
          break;
×
2064
        case TIMESTAMP:
NEW
2065
          break;
×
2066
        case UINT32:
NEW
2067
          break;
×
2068
        case UINT64:
NEW
2069
          break;
×
2070
        default:
2071
          break;
2072
      }
2073
    }
2074

NEW
2075
    YPR newYPR = qtToYPR(newQT);
×
NEW
2076
    ahrs.Heading = newYPR.yaw;
×
NEW
2077
    ahrs.Pitch = newYPR.pitch;
×
NEW
2078
    ahrs.Roll = newYPR.roll;
×
NEW
2079
  }
×
2080

2081
  public void reportAHRS(byte[] d) {
2082

NEW
2083
    if (this.AHRSStream != null) {
×
2084
      try {
NEW
2085
        this.AHRSStream.emitTuple(
×
NEW
2086
            new Tuple(gftdef, Arrays.asList(timeService.getMissionTime(), "AHRSStream", d)));
×
NEW
2087
      } catch (Exception e) {
×
2088
        // TODO Auto-generated catch block
NEW
2089
        e.printStackTrace();
×
NEW
2090
      }
×
2091
    }
2092

NEW
2093
    AHRSCount++;
×
NEW
2094
  }
×
2095

2096
  public void reportWHLAHRS(byte[] d) {
2097

NEW
2098
    if (this.WHLAHRSStream != null) {
×
2099
      try {
NEW
2100
        this.WHLAHRSStream.emitTuple(
×
NEW
2101
            new Tuple(gftdef, Arrays.asList(timeService.getMissionTime(), "WHLAHRSStream", d)));
×
NEW
2102
      } catch (Exception e) {
×
2103
        // TODO Auto-generated catch block
NEW
2104
        e.printStackTrace();
×
NEW
2105
      }
×
2106
    }
2107

NEW
2108
    WHLAHRSCount++;
×
UNCOV
2109
  }
×
2110

2111
  private synchronized void sendOwnshipGeoAltitude() throws IOException {
2112

2113
    for (GDL90Device d : gdl90Devices.values()) {
×
NEW
2114
      if (d.alive & !isBlackListed(new HostPortPair(d.host, d.port))) {
×
2115

2116
        com.windhoverlabs.yamcs.gdl90.OwnshipGeoAltitude geoAlt =
×
2117
            new com.windhoverlabs.yamcs.gdl90.OwnshipGeoAltitude();
2118

2119
        geoAlt.ownshipAltitude = 3000;
×
2120

2121
        org.yamcs.protobuf.Pvalue.ParameterValue pvAltitude = paramsToSend.get("Altitude");
×
2122

2123
        if (pvAltitude != null) {
×
2124
          switch (pvAltitude.getEngValue().getType()) {
×
2125
            case AGGREGATE:
2126
              break;
×
2127
            case ARRAY:
2128
              break;
×
2129
            case BINARY:
2130
              break;
×
2131
            case BOOLEAN:
2132
              break;
×
2133
            case DOUBLE:
2134
              //                    Meters to feet. Should be made configurable, maybe...
NEW
2135
              geoAlt.ownshipAltitude = (int) (pvAltitude.getEngValue().getDoubleValue() * 3.28084);
×
UNCOV
2136
              break;
×
2137
            case ENUMERATED:
2138
              break;
×
2139
            case FLOAT:
2140
              //                    Meters to feet. Should be made configurable, maybe...
NEW
2141
              geoAlt.ownshipAltitude = (int) (pvAltitude.getEngValue().getFloatValue() * 3.28084);
×
UNCOV
2142
              break;
×
2143
            case NONE:
2144
              break;
×
2145
            case SINT32:
2146
              break;
×
2147
            case SINT64:
2148
              break;
×
2149
            case STRING:
2150
              break;
×
2151
            case TIMESTAMP:
2152
              break;
×
2153
            case UINT32:
2154
              break;
×
2155
            case UINT64:
2156
              break;
×
2157
            default:
2158
              break;
2159
          }
2160
        }
2161
        geoAlt.verticalFigureOfMerit = 50;
×
2162
        geoAlt.verticalWarningIndicator = false;
×
2163

2164
        try {
2165
          d.datagram.setData(geoAlt.toBytes());
×
2166
        } catch (Exception e) {
×
2167
          // TODO Auto-generated catch block
2168
          e.printStackTrace();
×
2169
        }
×
2170
        GDL90Socket.send(d.datagram);
×
2171

NEW
2172
        reportOwnshipGeoAltitude(d.datagram.getData());
×
2173
      }
2174
    }
×
2175
  }
×
2176

2177
  private void reportOwnshipGeoAltitude(byte[] d) {
NEW
2178
    if (this.ownShipGeoAltitudeStream != null) {
×
NEW
2179
      this.ownShipGeoAltitudeStream.emitTuple(
×
NEW
2180
          new Tuple(gftdef, Arrays.asList(timeService.getMissionTime(), "ownShipGeoAltitude", d)));
×
2181
    }
2182

NEW
2183
    ownshipGeoAltitudeCount++;
×
NEW
2184
  }
×
2185

2186
  @Override
2187
  public void setupSystemParameters(SystemParametersService sysParamCollector) {
2188
    super.setupSystemParameters(sysParamCollector);
×
2189
    outOfSyncParam =
×
2190
        sysParamCollector.createSystemParameter(
×
2191
            linkName + "/outOfSync",
2192
            Yamcs.Value.Type.BOOLEAN,
2193
            "Are the downlinked events not in sync wtih the ones from the log?");
2194
    streamEventCountParam =
×
2195
        sysParamCollector.createSystemParameter(
×
2196
            linkName + "/streamEventCountParam",
2197
            Yamcs.Value.Type.UINT64,
2198
            "Event count in realtime event stream");
2199
    logEventCountParam =
×
2200
        sysParamCollector.createSystemParameter(
×
2201
            linkName + "/logEventCountParam",
2202
            Yamcs.Value.Type.UINT64,
2203
            "Event count from log files");
2204

NEW
2205
    devicesParam =
×
NEW
2206
        sysParamCollector.createSystemParameter(
×
2207
            linkName + "/GDL90Devices",
2208
            Yamcs.Value.Type.STRING,
2209
            "Current gdl90 devices and status");
2210

NEW
2211
    blackListParam =
×
NEW
2212
        sysParamCollector.createSystemParameter(
×
2213
            linkName + "/Blacklist", Yamcs.Value.Type.STRING, "Blacklisted gdl90 devices");
UNCOV
2214
  }
×
2215

2216
  @Override
2217
  public List<ParameterValue> getSystemParameters(long gentime) {
2218

2219
    ArrayList<ParameterValue> list = new ArrayList<>();
×
2220
    try {
NEW
2221
      collectSystemParameters(gentime, list);
×
2222
    } catch (Exception e) {
×
2223
      log.error("Exception caught when collecting link system parameters", e);
×
2224
    }
×
2225
    return list;
×
2226
  }
2227

2228
  @Override
2229
  protected void collectSystemParameters(long time, List<ParameterValue> list) {
2230
    super.collectSystemParameters(time, list);
×
2231
    list.add(SystemParametersService.getPV(outOfSyncParam, time, outOfSync));
×
2232
    list.add(SystemParametersService.getPV(streamEventCountParam, time, streamEventCount));
×
2233
    list.add(SystemParametersService.getPV(logEventCountParam, time, logEventCount));
×
NEW
2234
    list.add(SystemParametersService.getPV(devicesParam, time, gdl90Devices.toString()));
×
NEW
2235
    list.add(SystemParametersService.getPV(blackListParam, time, blackList.toString()));
×
UNCOV
2236
  }
×
2237

2238
  @Override
2239
  public void connecting() {
2240
    // TODO Auto-generated method stub
2241

2242
  }
×
2243

2244
  public static NamedObjectId identityOf(String pvName) {
2245
    return NamedObjectId.newBuilder().setName(pvName).build();
×
2246
  }
2247

2248
  /** Async adds a Yamcs PV for receiving updates. */
2249
  public void register(String pvName, String processor) {
2250
    NamedObjectId id = identityOf(pvName);
×
2251
    try {
2252
      subscription.sendMessage(
×
2253
          SubscribeParametersRequest.newBuilder()
×
2254
              .setInstance(this.yamcsInstance)
×
NEW
2255
              .setProcessor(processor)
×
2256
              .setSendFromCache(true)
×
2257
              .setAbortOnInvalid(false)
×
2258
              .setUpdateOnExpiration(false)
×
2259
              .addId(id)
×
2260
              .setAction(Action.ADD)
×
2261
              .build());
×
2262
    } catch (Exception e) {
×
2263
      System.out.println("e:" + e);
×
2264
    }
×
2265
  }
×
2266

2267
  @Override
2268
  public void connected() {
2269
    // TODO Auto-generated method stub
2270

2271
    subscription = yclient.createParameterSubscription();
×
2272
    subscription.addListener(this);
×
2273
    // TODO:Make this configurable
2274
    for (Map.Entry<String, String> pvName : pvMap.entrySet()) {
×
NEW
2275
      register(pvName.getValue(), processorName);
×
2276
    }
×
2277
  }
×
2278

2279
  @Override
2280
  public void connectionFailed(Throwable cause) {
2281
    // TODO Auto-generated method stub
2282

2283
  }
×
2284

2285
  @Override
2286
  public void disconnected() {
2287
    // TODO Auto-generated method stub
2288

2289
  }
×
2290

2291
  @Override
2292
  public void onData(List<org.yamcs.protobuf.Pvalue.ParameterValue> values) {
2293
    // TODO Auto-generated method stub
2294

2295
    for (org.yamcs.protobuf.Pvalue.ParameterValue p : values) {
×
2296
      if (pvMap.containsValue(p.getId().getName())) {
×
2297
        String pvLabel =
×
2298
            pvMap.entrySet().stream()
×
2299
                .filter(entry -> entry.getValue().equals(p.getId().getName()))
×
2300
                .map(Entry::getKey)
×
2301
                .collect(Collectors.toList())
×
2302
                .get(0);
×
2303
        paramsToSend.put(pvLabel, p);
×
2304
      }
2305
    }
×
2306
  }
×
2307

2308
  @Override
2309
  public long getDataInCount() {
2310
    // TODO Auto-generated method stub
2311
    return 0;
×
2312
  }
2313

2314
  @Override
2315
  public long getDataOutCount() {
2316
    // TODO Auto-generated method stub
2317
    return heartBeatCount
×
2318
        + ownShipReportCount
2319
        + ownshipGeoAltitudeCount
2320
        + foreFlightIDCount
2321
        + AHRSCount
2322
        + WHLAHRSCount;
2323
  }
2324

2325
  @Override
2326
  public void resetCounters() {
2327
    // TODO Auto-generated method stub
2328
    heartBeatCount = 0;
×
2329
    ownshipGeoAltitudeCount = 0;
×
2330
    foreFlightIDCount = 0;
×
2331
    AHRSCount = 0;
×
NEW
2332
    WHLAHRSCount = 0;
×
NEW
2333
  }
×
2334

2335
  @Override
2336
  public void onTuple(Stream stream, Tuple t) {
2337
    // TODO Auto-generated method stub
2338

NEW
2339
    byte[] packet = (byte[]) t.getColumn("packet");
×
2340

NEW
2341
    int msgId = ByteArrayUtils.decodeUnsignedShort(packet, 0);
×
2342

NEW
2343
    if (msgIds_1HZ.contains(msgId)) {
×
NEW
2344
      long rectime = (Long) t.getColumn(TM_RECTIME_COLUMN);
×
NEW
2345
      long gentime = (Long) t.getColumn(GENTIME_COLUMN);
×
2346

2347
      try {
NEW
2348
        processPacket(rectime, gentime, packet);
×
NEW
2349
      } catch (Exception e) {
×
NEW
2350
        log.warn("Failed to process event packet", e);
×
NEW
2351
      }
×
NEW
2352
    } else if (msgIds_5HZ.contains(msgId)) {
×
NEW
2353
      long rectime = (Long) t.getColumn(TM_RECTIME_COLUMN);
×
NEW
2354
      long gentime = (Long) t.getColumn(GENTIME_COLUMN);
×
2355

2356
      try {
NEW
2357
        processPacket(rectime, gentime, packet);
×
NEW
2358
      } catch (Exception e) {
×
NEW
2359
        log.warn("Failed to process event packet", e);
×
NEW
2360
      }
×
2361
    }
NEW
2362
  }
×
2363

2364
  private void processPacket(long rectime, long gentime, byte[] packet) {
NEW
2365
    byte[] GDL90Payload = Arrays.copyOfRange(packet, 12, packet.length);
×
2366

NEW
2367
    ArrayList<ArrayList<Byte>> allMessages = new ArrayList<ArrayList<Byte>>();
×
NEW
2368
    for (int i = 0; i < GDL90Payload.length; ) {
×
NEW
2369
      int sizeOfCurrentMessage = 0;
×
NEW
2370
      if (GDL90Payload[i] == 0x7E) {
×
NEW
2371
        boolean completeMsg = false;
×
NEW
2372
        ArrayList<Byte> msg = new ArrayList<Byte>();
×
NEW
2373
        msg.add(GDL90Payload[i]);
×
NEW
2374
        sizeOfCurrentMessage++;
×
NEW
2375
        for (int j = i + 1; j < GDL90Payload.length; j++) {
×
NEW
2376
          sizeOfCurrentMessage++;
×
NEW
2377
          msg.add(GDL90Payload[j]);
×
NEW
2378
          if (GDL90Payload[j] == 0x7E) {
×
NEW
2379
            completeMsg = true;
×
NEW
2380
            i++;
×
NEW
2381
            break;
×
2382
          }
2383
        }
NEW
2384
        i += sizeOfCurrentMessage;
×
NEW
2385
        if (completeMsg) {
×
NEW
2386
          allMessages.add(msg);
×
2387
        }
NEW
2388
      } else {
×
NEW
2389
        i += 1;
×
2390
      }
NEW
2391
    }
×
2392

NEW
2393
    for (GDL90Device d : gdl90Devices.values()) {
×
NEW
2394
      if (d.alive & !isBlackListed(new HostPortPair(d.host, d.port))) {
×
2395

NEW
2396
        for (ArrayList<Byte> msg : allMessages) {
×
NEW
2397
          ByteBuffer msgBuffer = ByteBuffer.allocate(msg.size());
×
2398

NEW
2399
          for (Byte b : msg) {
×
NEW
2400
            msgBuffer.put(b);
×
NEW
2401
          }
×
2402

NEW
2403
          byte[] payload = msgBuffer.array();
×
NEW
2404
          byte payloadMsgId = 0x00;
×
NEW
2405
          if (payload.length > 2) {
×
NEW
2406
            payloadMsgId = payload[1];
×
2407
          } else {
2408
            //                  Should not happen. Add Error event/log message
NEW
2409
            return;
×
2410
          }
2411

NEW
2412
          d.datagram.setData(payload);
×
2413
          try {
NEW
2414
            GDL90Socket.send(d.datagram);
×
NEW
2415
          } catch (IOException e) {
×
2416
            // TODO Auto-generated catch block
NEW
2417
            e.printStackTrace();
×
NEW
2418
          }
×
NEW
2419
          switch (payloadMsgId) {
×
2420
            case GDL90Heartbeat.MessageID:
2421
              {
NEW
2422
                reportHeartbeatStatus(payload);
×
NEW
2423
                break;
×
2424
              }
2425
            case OwnshipReport.MessageID:
2426
              {
NEW
2427
                reportOwnshipStatus(payload);
×
NEW
2428
                break;
×
2429
              }
2430

2431
            case OwnshipGeoAltitude.MessageID:
2432
              {
NEW
2433
                reportOwnshipGeoAltitude(payload);
×
NEW
2434
                break;
×
2435
              }
2436
            case ForeFlightIDMessage.MessageID:
2437
              {
NEW
2438
                byte ForeFlightSubMsgId = payload[2];
×
2439

NEW
2440
                switch (ForeFlightSubMsgId) {
×
2441
                  case ForeFlightIDMessage.ForeFlightSubMessageID:
2442
                    {
NEW
2443
                      reportForeFlightID(payload);
×
NEW
2444
                      break;
×
2445
                    }
2446
                  case AHRS.AHRSSubMessageID:
2447
                    {
NEW
2448
                      reportAHRS(payload);
×
2449
                      break;
2450
                    }
2451
                }
2452

NEW
2453
                break;
×
2454
              }
2455
            default:
2456
              /** Unknown MID. Report event/log message. */
2457
              break;
2458
          }
NEW
2459
        }
×
2460
      }
NEW
2461
    }
×
NEW
2462
  }
×
2463

2464
  private double mpsToKnots(float mps) {
NEW
2465
    return ((1.943844) * (mps));
×
2466
  }
2467

2468
  private boolean isBlackListed(HostPortPair p) {
NEW
2469
    return blackList.containsKey(p);
×
2470
  }
2471

2472
  private YPR qtToYPR(QT qt) {
NEW
2473
    YPR ypr = new YPR();
×
NEW
2474
    Matrix3F3 _R = qt.RotationMatrix();
×
NEW
2475
    Vector3F euler_angles = new Vector3F();
×
NEW
2476
    euler_angles = _R.ToEuler();
×
2477

NEW
2478
    ypr.roll = Math.toDegrees(euler_angles.data[0]);
×
NEW
2479
    ypr.pitch = Math.toDegrees(euler_angles.data[1]);
×
NEW
2480
    ypr.yaw = Math.toDegrees((euler_angles.data[2]));
×
2481

NEW
2482
    return ypr;
×
2483
  }
2484
}
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