Subversion Repositories group.NITPanels

Rev

Rev 14 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 pfowler 1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
using System.Threading.Tasks;
6
using System.Timers;
7
 
8
using Microsoft.FlightSimulator.SimConnect;
9
 
10
using LibUsbDotNet;
11
using LibUsbDotNet.Main;
12
using LibUsbDotNet.DeviceNotify;
13
 
14
namespace NITNavComm {
15
    public class NITNavCommDevice : NITDevice  {
16
 
17
        enum UsbCommands : byte {
18
            CMD_LATCH_DISPLAY = 20,
19
            CMD_SET_DISPLAY = 21,
20
        };
21
 
22
        private byte[,] display { get; set; }
23
        private byte[] buttons {get; set; }
24
        private sbyte[,] rotary;
25
        private ushort[] points { get; set; }
26
 
27
        public int flipcomm { get; set; }
28
        public int flipnav { get; set; }
29
 
30
        public uint simStatus { get; set; }
14 pfowler 31
        private bool SimButtonsOn;
3 pfowler 32
 
33
        public int comStatus { get; set; }
34
        public bool navAvailable { get; set; }
35
        public bool avionicsMaster { get; set; }
36
 
15 pfowler 37
        // Debounce timers for each 4 buttons (Nav/Comm flip & swap)
3 pfowler 38
        private const int TIMER_COUNT = 4;
39
        private const int TIMER_COMMSWAP = 0;
40
        private const int TIMER_COMMFLIP = 1;
41
        private const int TIMER_NAVSWAP = 2;
42
        private const int TIMER_NAVFLIP = 3;
43
        Timer[] timers = new Timer[TIMER_COUNT];
44
 
15 pfowler 45
        // Timer for getting input from the device
46
        //  Interval is in NITPanels.CFG_INPUT_TIMER_INTERVAL
5 pfowler 47
        Timer inputTimer = new Timer();
15 pfowler 48
 
49
        // What decimal points to show on the display board
50
        private const int POINT_NONE = 0x0000;      // _ _ _ _ _   _ _ _ _ _
51
        private const int POINT_FREQ = 0x0084;      // _ _ . _ _   _ _ . _ _
52
        private const int POINT_MHZ = 0x00a4;       // _ _ . _ _   . _ . _ _
53
        private const int POINT_KHZ = 0x0284;       // _ _ . _ _   _ _ . _ .
54
        // Timer to control how long the cursor decimal point should be shown ( 1 sec )
12 pfowler 55
        private const int TIMER_FLIP_SHOW_COUNT = 1000;
56
        Timer flipShowTimer = new Timer();
57
 
3 pfowler 58
        public NITNavCommDevice(NITDevice nitDevice) :
59
            base(nitDevice.usbRegistry, "NITNavComm", nitDevice.vid, nitDevice.pid) {
60
            this.init();
61
        }
62
 
63
        public NITNavCommDevice(UsbRegistry usbRegistry, string type, int vid, int pid) :
64
            base(usbRegistry, "NITNavComm", 0x20a0, 0x4236) {
65
            this.init();
66
        }
67
 
68
        private void init()
69
        {
70
            base.Open();
71
 
72
            this.display = new byte[2, 10];
73
            this.points = new ushort[2];
74
            this.blankDisplay();
75
 
76
            this.buttons = new byte[2];
77
            this.buttons[0] = 0x00;
78
            this.buttons[1] = 0x00;
79
 
80
            this.rotary = new sbyte[2, 2];
81
            this.resetAllRotary();
82
 
83
            this.flipcomm = 0;
84
            this.flipnav = 0;
85
 
11 pfowler 86
            this.simStatus = 2;
3 pfowler 87
            this.assigned = 1;
88
 
89
            this.comStatus = 0;
90
            this.navAvailable = true;
91
            this.avionicsMaster = false;
14 pfowler 92
            this.SimButtonsOn = false;
3 pfowler 93
 
94
            for (int i = 0; i < TIMER_COUNT; i++) {
95
                Timer timer = new Timer();
96
                timer.Enabled = false;
97
                timer.AutoReset = false;
98
                timer.Interval = NITPanels.CFG_BUTTON_DEBOUNCE_TIME;
99
                timer.Elapsed += OnDebounceTimer;
100
                timers[i] = timer;
101
            }
5 pfowler 102
 
103
            inputTimer.Enabled = false;
104
            inputTimer.AutoReset = true;
105
            inputTimer.Interval = NITPanels.CFG_INPUT_TIMER_INTERVAL;
106
            inputTimer.Elapsed += inputTimer_Elapsed;
12 pfowler 107
 
108
            flipShowTimer.Enabled = false;
109
            flipShowTimer.AutoReset = false;
110
            flipShowTimer.Interval = NITNavCommDevice.TIMER_FLIP_SHOW_COUNT;
111
            flipShowTimer.Elapsed += flipShowTimer_Elapsed;
3 pfowler 112
 
113
        }
114
 
12 pfowler 115
        void flipShowTimer_Elapsed(object sender, ElapsedEventArgs e) {
116
            this.points[0] = NITNavCommDevice.POINT_FREQ;
117
            this.points[1] = NITNavCommDevice.POINT_FREQ;
118
            this.UpdatePoints();
119
        }
120
 
5 pfowler 121
        void inputTimer_Elapsed(object sender, ElapsedEventArgs e) {
122
            this.SimButtons();
123
        }
124
 
3 pfowler 125
        private static void OnDebounceTimer(Object source, ElapsedEventArgs e) {
126
            Timer timer = (Timer)source;
127
            timer.Enabled = false;
128
        }
129
 
130
        public override bool Close() {
5 pfowler 131
            this.powerDown();
3 pfowler 132
            return base.Close();
133
        }
134
 
135
        public void powerDown() {
5 pfowler 136
            this.simStatus = 2;
3 pfowler 137
            this.resetAllRotary();
11 pfowler 138
 
3 pfowler 139
            this.blankDisplay();
5 pfowler 140
            this.inputTimer.Enabled = false;
3 pfowler 141
        }
142
 
143
        public void powerUp() {
5 pfowler 144
            this.simStatus = 0;
3 pfowler 145
            this.resetAllRotary();
5 pfowler 146
            this.inputTimer.Enabled = true;
11 pfowler 147
 
15 pfowler 148
            this.points[0] = NITNavCommDevice.POINT_FREQ;
149
            this.points[1] = NITNavCommDevice.POINT_FREQ;
11 pfowler 150
 
12 pfowler 151
            this.UpdatePoints();
11 pfowler 152
 
3 pfowler 153
            if (this.assigned == 1)
154
                this.fsx.requestNavComm1Data();
155
            else if (this.assigned == 2)
156
                this.fsx.requestNavComm2Data();
157
        }
158
 
159
        public void blankDisplay() {
160
            byte[] blank = { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a };
161
            for (byte i = 0; i < 4; i++)
162
                setFreq(i, ref blank);
163
            this.points[0] = 0x0000;
164
            this.points[1] = 0x0000;
11 pfowler 165
            this.sendPoints();
14 pfowler 166
            this.UpdateAllDisplays();
3 pfowler 167
        }
168
 
169
        public byte[] getFreq(byte freq) {
170
            byte[] ret = new byte[5];
171
            switch (freq) {
172
                case 0:
173
                    for (byte i = 0; i < 5; i++)
174
                        ret[i] = display[0, i];
175
                    break;
176
                case 1:
177
                    for (byte i = 0; i < 5; i++)
178
                        ret[i] = display[0, i + 5];
179
                    break;
180
                case 2:
181
                    for (byte i = 0; i < 5; i++)
182
                        ret[i] = display[1, i];
183
                    break;
184
                case 3:
185
                    for (byte i = 0; i < 5; i++)
186
                        ret[i] = display[1, i + 5];
187
                    break;
188
            }
189
            return ret;
190
        }
191
 
192
        public void setFreq(byte freq, ref byte[] data) {
193
            switch (freq) {
194
                case 0:
195
                    for (byte i = 0; i < 5; i++)
196
                        display[0, i] = data[i];
197
                    break;
198
                case 1:
199
                    for (byte i = 0; i < 5; i++)
200
                        display[0, i+5] = data[i];
201
                    break;
202
                case 2:
203
                    for (byte i = 0; i < 5; i++)
204
                        display[1, i] = data[i];
205
                    break;
206
                case 3:
207
                    for (byte i = 0; i < 5; i++)
208
                        display[1, i + 5] = data[i];
209
                    break;
210
            }
211
        }
212
 
213
        public void setNavComFreqs(FSXObject.NavCom_Data data) {
214
            byte[] freq0 = this.charArrayToBytes(data.Freq0.ToString().ToCharArray());
215
            byte[] freq1 = this.charArrayToBytes(data.Freq1.ToString().ToCharArray());
216
            byte[] freq2 = this.charArrayToBytes(data.Freq2.ToString().ToCharArray());
217
            byte[] freq3 = this.charArrayToBytes(data.Freq3.ToString().ToCharArray());
218
 
14 pfowler 219
            byte[] ofreq0 = this.getFreq(0);
220
            byte[] ofreq1 = this.getFreq(1);
221
            byte[] ofreq2 = this.getFreq(2);
222
            byte[] ofreq3 = this.getFreq(3);
223
 
3 pfowler 224
            this.setFreq(0, ref freq0);
225
            this.setFreq(1, ref freq1);
14 pfowler 226
 
3 pfowler 227
            this.setFreq(2, ref freq2);
228
            this.setFreq(3, ref freq3);
229
 
14 pfowler 230
            if (freq0 != ofreq0 || freq1 != ofreq1) this.UpdateDisplay(0);
231
            if (freq2 != ofreq2 || freq3 != ofreq3) this.UpdateDisplay(1);
232
 
3 pfowler 233
        }
234
 
235
        private byte[] charArrayToBytes(char[] digits) {
236
            byte[] bytes = new byte[5];
237
            for (byte i = 0; i < 5; i++) {
238
                bytes[i] = (byte)(digits[i] - '0');
239
            }
240
            return bytes;
241
        }
242
 
11 pfowler 243
        private void sendData(byte dis) {
244
            for (byte i = 0; i < 10; i++) {
245
                this.sendDigit(dis, i, display[dis, i]);
246
            }
247
        }
248
 
14 pfowler 249
 
250
        public void UpdateAllDisplays() {
15 pfowler 251
            this.UpdateDisplay(0);
252
            this.UpdateDisplay(1);            
11 pfowler 253
        }
254
 
255
        public void UpdateDisplay(byte dis) {
15 pfowler 256
            if (this.SimButtonsOn)              // Dont do anything if we checking input
257
                return;
258
 
259
            this.inputTimer.Enabled = false;    // Disable the input timer to ensure we dont start checking input
260
 
261
            this.sendData(dis);                 // Send the display data
262
            this.latchDisplay(dis);             // Latch it at the same time
263
 
264
            this.inputTimer.Enabled = true;     // Re-enable input checking
11 pfowler 265
        }
266
 
12 pfowler 267
        public void UpdatePoints() {
15 pfowler 268
            //if (this.SimButtonsOn)            // Points are updated from within SimButtons, so needs to be enabled
269
            //   return;                        // Should be ok as points arnt updated from FSX Events
270
                                                // Also, dont reenable input timer as it is already done in SimButtons
271
 
272
            if (this.simStatus != 0)
273
                return;
274
 
275
            this.sendPoints();                  // Send the decimal points for both display boards
276
 
12 pfowler 277
        }
278
 
3 pfowler 279
        public void setDisplay(byte dis, ref byte[] data) {
280
            for (byte i = 0; i < data.Length; i++) {
281
                display[dis, i] = data[i];
282
            }
283
        }
284
 
11 pfowler 285
        private void sendDigit(byte dis, byte dig, byte val) {
3 pfowler 286
            ushort wxValue = (ushort)(dis <<8);
287
            wxValue |= dig;
11 pfowler 288
            ushort wxIndex = val;
3 pfowler 289
 
290
            base.SendCommand(21, (short)wxValue, (short)wxIndex);
291
        }
292
 
11 pfowler 293
        private void sendPoints() {
294
            base.SendCommand(23, (short)this.points[0], (short)this.points[1]);
295
        }
296
 
3 pfowler 297
        private void sendLatch(byte dis) {
298
            if (!this.isOpen())
299
                return;
300
 
301
            base.SendCommand(20, (short)dis, 0);
302
        }
303
 
15 pfowler 304
        // @TODO: This should only be called from SimButtons, but as its required
305
        //   to be called from the testing form, will stay open for now
3 pfowler 306
        public void updateInput() {
307
            byte[] data = new byte[8];
308
            int transferred;
309
            base.SendCommand(30, 0, 0, data, out transferred);
310
            this.buttons[0] = data[0];
311
            this.rotary[0, 0] += (sbyte)data[1];
312
            this.buttons[1] = data[2];
313
            this.rotary[1, 0] += (sbyte)data[3];
314
        }
315
 
316
        public bool isSwapSet(byte dis) {
317
            if ((this.buttons[dis] & 0x01)>0)
318
                return true;
319
            return false;
320
        }
321
 
322
        public bool isFlipSet(byte dis) {
323
            if ((this.buttons[dis] & 0x02) > 0)
324
                return true;
325
            return false;
326
        }
327
 
328
        public sbyte getRotary(byte dis, byte rotary) {
329
            return this.rotary[dis, rotary];
330
        }
331
 
332
        public void resetRotary(byte display, byte rotary) {
333
            this.rotary[display, rotary] = 0x00;
334
        }
335
 
336
        public void resetAllRotary() {
337
            this.rotary[0, 0] = 0x00;
338
            this.rotary[0, 1] = 0x00;
339
            this.rotary[1, 0] = 0x00;
340
            this.rotary[1, 1] = 0x00;
341
        }
342
 
343
        private byte GetBit(ushort b, byte bitNumber) {
344
            if ((b & (1 << bitNumber)) != 0)
345
                return 1;
346
            return 0;
347
        }
348
 
349
        private void latchDisplay(byte dis) {
350
            this.sendLatch(dis);
351
        }
352
 
353
        public void swapFreq(byte display) {
354
            if (display == 0) {
355
                byte[] left = this.getFreq(0);
356
                byte[] right = this.getFreq(1);
357
                this.setFreq(0, ref right);
358
                this.setFreq(1, ref left);
359
            } else if (display == 1) {
360
                byte[] left = this.getFreq(2);
361
                byte[] right = this.getFreq(3);
362
                this.setFreq(2, ref right);
363
                this.setFreq(3, ref left);
364
            }
365
        }
366
 
5 pfowler 367
        public override void FsxReady() {
368
            this.powerUp();
3 pfowler 369
        }
370
 
7 pfowler 371
        public override void reAssign() {
372
            if (this.simStatus != 0)
373
                return;
374
 
375
            if (this.assigned == 1)
376
                this.fsx.requestNavComm1Data();
377
            else
378
                this.fsx.requestNavComm2Data();
379
        }
380
 
3 pfowler 381
        public override void FsxEvent(SIMCONNECT_RECV_SIMOBJECT_DATA data) {
382
            if (data.dwRequestID == (uint)FSXObject.DATA_REQUESTS.AVIONICS) {
383
 
384
                FSXObject.Avionics_Data avionics = (FSXObject.Avionics_Data)data.dwData[0];
385
 
386
                this.avionicsMaster = avionics.avionics_master;
387
                if (this.assigned == 1)
388
                    this.comStatus = (int)avionics.com1_status;
389
                else
390
                    this.comStatus = (int)avionics.com2_status;
391
 
392
                if (this.assigned == 1)
393
                    this.navAvailable = avionics.nav1_available;
394
                else if (this.assigned == 2)
395
                    this.navAvailable = avionics.nav2_available;
396
 
397
                if (!this.avionicsMaster || this.comStatus != 0) {
398
                    this.powerDown();
399
                    return;
400
                }
401
 
402
                if (this.avionicsMaster && this.comStatus == 0 && this.simStatus != 0) {
403
                    this.powerUp();
404
                    return;
405
                }
406
            }
407
 
408
            if (this.simStatus != 0)
409
                return;
410
 
411
            if (this.assigned == 1 && data.dwRequestID == (uint)FSXObject.DATA_REQUESTS.NAVCOM1_REQ) {
412
                FSXObject.NavCom_Data navcomdata = (FSXObject.NavCom_Data)data.dwData[0];
413
                this.setNavComFreqs(navcomdata);
4 pfowler 414
            } 
415
 
416
            if (this.assigned == 2 && data.dwRequestID == (uint)FSXObject.DATA_REQUESTS.NAVCOM2_REQ) {
3 pfowler 417
                FSXObject.NavCom_Data navcomdata = (FSXObject.NavCom_Data)data.dwData[0];
418
                this.setNavComFreqs(navcomdata);
419
            }
420
 
11 pfowler 421
 
5 pfowler 422
        }     
3 pfowler 423
 
424
        public override void SimButtons() {
15 pfowler 425
            if (this.SimButtonsOn)              // Dont run SimButtons if its already running
14 pfowler 426
                return;
427
 
3 pfowler 428
            if (this.simStatus != 0)
429
                return;
430
 
15 pfowler 431
            this.inputTimer.Enabled = false;
432
            this.SimButtonsOn = true;
433
 
3 pfowler 434
            this.updateInput();
435
 
436
            if (!timers[TIMER_COMMSWAP].Enabled && this.isSwapSet(0)) {
437
                if (this.assigned == 1)
438
                    fsx.Comm1SwapFreq();
439
                else
440
                    fsx.Comm2SwapFreq();
441
                timers[TIMER_COMMSWAP].Enabled = true;
442
            }
443
 
444
            if (!timers[TIMER_NAVSWAP].Enabled && this.isSwapSet(1)) {
445
                if (this.assigned == 1)
446
                    fsx.Nav1SwapFreq();
447
                else
448
                    fsx.Nav2SwapFreq();
449
 
450
                timers[TIMER_NAVSWAP].Enabled = true;
451
            }
452
 
453
            // Check if the MHz/KHz has been pressed
454
            if (!timers[TIMER_COMMFLIP].Enabled && this.isFlipSet(0)) {
455
                this.flipcomm = 1 - this.flipcomm;
456
                timers[TIMER_COMMFLIP].Enabled = true;
12 pfowler 457
 
458
                if (this.flipcomm == 0) {
459
                    this.points[0] = NITNavCommDevice.POINT_MHZ;
460
                } else {
461
                    this.points[0] = NITNavCommDevice.POINT_KHZ;
462
                }
463
                this.UpdatePoints();
15 pfowler 464
                flipShowTimer.Interval = NITNavCommDevice.TIMER_FLIP_SHOW_COUNT;
12 pfowler 465
                this.flipShowTimer.Enabled = true;
466
 
3 pfowler 467
            }
468
 
469
            if (!timers[TIMER_NAVFLIP].Enabled && this.isFlipSet(1)) {
470
                this.flipnav = 1 - this.flipnav;
471
                timers[TIMER_NAVFLIP].Enabled = true;
12 pfowler 472
 
473
                if (this.flipnav == 0) {
474
                    this.points[1] = NITNavCommDevice.POINT_MHZ;
475
                } else {
476
                    this.points[1] = NITNavCommDevice.POINT_KHZ;
477
                }
478
                this.UpdatePoints();
15 pfowler 479
                flipShowTimer.Interval = NITNavCommDevice.TIMER_FLIP_SHOW_COUNT;
12 pfowler 480
                this.flipShowTimer.Enabled = true;
3 pfowler 481
            }
482
 
483
            // Process the rotary encoders COMM1
484
            sbyte delta = this.getRotary(0, 0);
485
            this.resetRotary(0, 0);
486
            if (delta != 0) {
14 pfowler 487
                commRotaryPressed(delta);
488
            }
489
 
490
            // Process the rotary encoders NAV1
491
            delta = this.getRotary(1, 0);
492
            this.resetRotary(1, 0);
493
            if (delta != 0) {
494
                navRotaryPressed(delta);
495
            }
496
            this.inputTimer.Enabled = true;
15 pfowler 497
            this.SimButtonsOn = false;
14 pfowler 498
 
499
        } // End SimButtons
500
 
15 pfowler 501
        private void commRotaryPressed(sbyte delta) {
502
            if (delta < 0) {
503
                delta = (sbyte)-delta;
504
                for (int i = 0; i<delta; i++) {
505
                    if (this.flipcomm == 1)
506
                        if (this.assigned == 1)
507
                            fsx.Comm1DecFract();
3 pfowler 508
                        else
15 pfowler 509
                            fsx.Comm2DecFract();
510
                    else
511
                        if (this.assigned == 1)
512
                            fsx.Comm1DecWhole();
3 pfowler 513
                        else
15 pfowler 514
                            fsx.Comm2DecWhole();
3 pfowler 515
                }
15 pfowler 516
            } else {
517
                for (int i = 0; i < delta; i++) {
518
                    if (this.flipcomm == 1)
519
                        if (this.assigned == 1)
520
                            fsx.Comm1IncFract();
521
                        else
522
                            fsx.Comm2IncFract();
523
                    else
524
                        if (this.assigned == 1)
525
                            fsx.Comm1IncWhole();
526
                        else
527
                            fsx.Comm2IncWhole();
528
                }
3 pfowler 529
            }
15 pfowler 530
        }
3 pfowler 531
 
15 pfowler 532
        private void navRotaryPressed(sbyte delta) {
533
            if (delta < 0) {
534
                delta = (sbyte)-delta;
535
                for (int i = 0; i < delta; i++) {
536
                    if (this.flipnav == 1)
537
                        if (this.assigned == 1)
538
                            fsx.Nav1DecFract();
3 pfowler 539
                        else
15 pfowler 540
                            fsx.Nav2DecFract();
541
                    else
542
                        if (this.assigned == 1)
543
                            fsx.Nav1DecWhole();
3 pfowler 544
                        else
15 pfowler 545
                            fsx.Nav2DecWhole();
3 pfowler 546
                }
15 pfowler 547
            } else {
548
                for (int i = 0; i < delta; i++) {
549
                    if (this.flipnav == 1)
550
                        if (this.assigned == 1)
551
                            fsx.Nav1IncFract();
552
                        else
553
                            fsx.Nav2IncFract();
554
                    else
555
                        if (this.assigned == 1)
556
                            fsx.Nav1IncWhole();
557
                        else
558
                            fsx.Nav2IncWhole();
559
                }
3 pfowler 560
            }
14 pfowler 561
 
15 pfowler 562
        }
563
 
3 pfowler 564
    }
14 pfowler 565
 
566
 
3 pfowler 567
}