Subversion Repositories group.NITPanels

Rev

Rev 4 | Rev 6 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

using Microsoft.FlightSimulator.SimConnect;

using LibUsbDotNet;
using LibUsbDotNet.Main;
using LibUsbDotNet.DeviceNotify;

namespace NITNavComm {
    public class NITNavCommDevice : NITDevice  {

        enum UsbCommands : byte {
            CMD_LATCH_DISPLAY = 20,
            CMD_SET_DISPLAY = 21,
        };

        private byte[,] display { get; set; }
        private byte[] buttons {get; set; }
        private sbyte[,] rotary;
        private ushort[] points { get; set; }

        public int flipcomm { get; set; }
        public int flipnav { get; set; }

        public uint simStatus { get; set; }

        public int comStatus { get; set; }
        public bool navAvailable { get; set; }
        public bool avionicsMaster { get; set; }

        
        private const int TIMER_COUNT = 4;
        private const int TIMER_COMMSWAP = 0;
        private const int TIMER_COMMFLIP = 1;
        private const int TIMER_NAVSWAP = 2;
        private const int TIMER_NAVFLIP = 3;
        Timer[] timers = new Timer[TIMER_COUNT];

        Timer inputTimer = new Timer();

        public NITNavCommDevice(NITDevice nitDevice) :
            base(nitDevice.usbRegistry, "NITNavComm", nitDevice.vid, nitDevice.pid) {
            this.init();
        }

        public NITNavCommDevice(UsbRegistry usbRegistry, string type, int vid, int pid) :
            base(usbRegistry, "NITNavComm", 0x20a0, 0x4236) {
            this.init();
        }

        private void init()
        {
            base.Open();
            
            this.display = new byte[2, 10];
            this.points = new ushort[2];
            this.blankDisplay();
            
            this.buttons = new byte[2];
            this.buttons[0] = 0x00;
            this.buttons[1] = 0x00;

            this.rotary = new sbyte[2, 2];
            this.resetAllRotary();

            this.flipcomm = 0;
            this.flipnav = 0;

            this.simStatus = 0;
            this.assigned = 1;

            this.comStatus = 0;
            this.navAvailable = true;
            this.avionicsMaster = false;

            for (int i = 0; i < TIMER_COUNT; i++) {
                Timer timer = new Timer();
                timer.Enabled = false;
                timer.AutoReset = false;
                timer.Interval = NITPanels.CFG_BUTTON_DEBOUNCE_TIME;
                timer.Elapsed += OnDebounceTimer;
                timers[i] = timer;
            }

            inputTimer.Enabled = false;
            inputTimer.AutoReset = true;
            inputTimer.Interval = NITPanels.CFG_INPUT_TIMER_INTERVAL;
            inputTimer.Elapsed += inputTimer_Elapsed;
            
        }

        void inputTimer_Elapsed(object sender, ElapsedEventArgs e) {
            this.SimButtons();
        }

        private static void OnDebounceTimer(Object source, ElapsedEventArgs e) {
            Timer timer = (Timer)source;
            timer.Enabled = false;
        }

        public override bool Close() {
            this.powerDown();
            return base.Close();
        }

        public void powerDown() {
            this.simStatus = 2;
            this.resetAllRotary();
            this.blankDisplay();
            this.inputTimer.Enabled = false;
        }

        public void powerUp() {
            this.simStatus = 0;
            this.resetAllRotary();
            this.inputTimer.Enabled = true;
            
            if (this.assigned == 1)
                this.fsx.requestNavComm1Data();
            else if (this.assigned == 2)
                this.fsx.requestNavComm2Data();
        }

        public void blankDisplay() {
            byte[] blank = { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a };
            for (byte i = 0; i < 4; i++)
                setFreq(i, ref blank);
            this.points[0] = 0x0000;
            this.points[1] = 0x0000;
            this.UpdateDisplay();
        }

        public byte[] getFreq(byte freq) {
            byte[] ret = new byte[5];
            switch (freq) {
                case 0:
                    for (byte i = 0; i < 5; i++)
                        ret[i] = display[0, i];
                    break;
                case 1:
                    for (byte i = 0; i < 5; i++)
                        ret[i] = display[0, i + 5];
                    break;
                case 2:
                    for (byte i = 0; i < 5; i++)
                        ret[i] = display[1, i];
                    break;
                case 3:
                    for (byte i = 0; i < 5; i++)
                        ret[i] = display[1, i + 5];
                    break;
            }
            return ret;
        }

        public void setFreq(byte freq, ref byte[] data) {
            switch (freq) {
                case 0:
                    for (byte i = 0; i < 5; i++)
                        display[0, i] = data[i];
                    break;
                case 1:
                    for (byte i = 0; i < 5; i++)
                        display[0, i+5] = data[i];
                    break;
                case 2:
                    for (byte i = 0; i < 5; i++)
                        display[1, i] = data[i];
                    break;
                case 3:
                    for (byte i = 0; i < 5; i++)
                        display[1, i + 5] = data[i];
                    break;
            }
        }

        public void setNavComFreqs(FSXObject.NavCom_Data data) {
            byte[] freq0 = this.charArrayToBytes(data.Freq0.ToString().ToCharArray());
            byte[] freq1 = this.charArrayToBytes(data.Freq1.ToString().ToCharArray());
            byte[] freq2 = this.charArrayToBytes(data.Freq2.ToString().ToCharArray());
            byte[] freq3 = this.charArrayToBytes(data.Freq3.ToString().ToCharArray());

            this.setFreq(0, ref freq0);
            this.setFreq(1, ref freq1);
            this.setFreq(2, ref freq2);
            this.setFreq(3, ref freq3);

            this.UpdateDisplay();
        }

        private byte[] charArrayToBytes(char[] digits) {
            byte[] bytes = new byte[5];
            for (byte i = 0; i < 5; i++) {
                bytes[i] = (byte)(digits[i] - '0');
            }
            return bytes;
        }

        public void setDisplay(byte dis, ref byte[] data) {
            for (byte i = 0; i < data.Length; i++) {
                display[dis, i] = data[i];
            }
        }

        private void sendDigit(byte dis, byte dig, byte val, byte dp) {
            ushort wxValue = (ushort)(dis <<8);
            wxValue |= dig;
            ushort wxIndex = (ushort)(dp << 8);
            wxIndex |= val;

            base.SendCommand(21, (short)wxValue, (short)wxIndex);
        }

        private void sendLatch(byte dis) {
            if (!this.isOpen())
                return;

            base.SendCommand(20, (short)dis, 0);
        }

        public void updateInput() {
            byte[] data = new byte[8];
            int transferred;
            base.SendCommand(30, 0, 0, data, out transferred);
            this.buttons[0] = data[0];
            this.rotary[0, 0] += (sbyte)data[1];
            this.buttons[1] = data[2];
            this.rotary[1, 0] += (sbyte)data[3];
        }

        public bool isSwapSet(byte dis) {
            if ((this.buttons[dis] & 0x01)>0)
                return true;
            return false;
        }

        public bool isFlipSet(byte dis) {
            if ((this.buttons[dis] & 0x02) > 0)
                return true;
            return false;
        }

        public sbyte getRotary(byte dis, byte rotary) {
            return this.rotary[dis, rotary];
        }

        public void resetRotary(byte display, byte rotary) {
            this.rotary[display, rotary] = 0x00;
        }

        public void resetAllRotary() {
            this.rotary[0, 0] = 0x00;
            this.rotary[0, 1] = 0x00;
            this.rotary[1, 0] = 0x00;
            this.rotary[1, 1] = 0x00;
        }

        private void sendData(byte dis) {
            for (byte i = 0; i < 10; i++) {
                //this.sendDigit(dis, i, display[dis, i], this.GetBit(this.points[dis], i));
                this.sendDigit(dis, i, display[dis, i], 0);
            }            
        }

        public void UpdateDisplay() {
            this.sendData(0);
            this.sendData(1);
            this.latchDisplay(0);
            this.latchDisplay(1);
        }

        public void UpdateDisplay(byte dis) {
            this.sendData(dis);
            this.latchDisplay(dis);
        }

        private byte GetBit(ushort b, byte bitNumber) {
            if ((b & (1 << bitNumber)) != 0)
                return 1;
            return 0;
        }

        private void latchDisplay(byte dis) {
            this.sendLatch(dis);
        }

        public void swapFreq(byte display) {
            if (display == 0) {
                byte[] left = this.getFreq(0);
                byte[] right = this.getFreq(1);
                this.setFreq(0, ref right);
                this.setFreq(1, ref left);
            } else if (display == 1) {
                byte[] left = this.getFreq(2);
                byte[] right = this.getFreq(3);
                this.setFreq(2, ref right);
                this.setFreq(3, ref left);
            }
        }

        // @TODO: Remove these, not unneeded
        public override void FsxInit() { }
        public override void MapEvents() { }

        public override void FsxReady() {
            this.powerUp();
        }

        //public override void FsxClose() {
        //    this.powerDown();
        //}

        public override void FsxEvent(SIMCONNECT_RECV_SIMOBJECT_DATA data) {

            if (data.dwRequestID == (uint)FSXObject.DATA_REQUESTS.AVIONICS) {
                
                FSXObject.Avionics_Data avionics = (FSXObject.Avionics_Data)data.dwData[0];
                
                this.avionicsMaster = avionics.avionics_master;
                if (this.assigned == 1)
                    this.comStatus = (int)avionics.com1_status;
                else
                    this.comStatus = (int)avionics.com2_status;

                if (this.assigned == 1)
                    this.navAvailable = avionics.nav1_available;
                else if (this.assigned == 2)
                    this.navAvailable = avionics.nav2_available;

                if (!this.avionicsMaster || this.comStatus != 0) {
                    this.powerDown();
                    return;
                }

                if (this.avionicsMaster && this.comStatus == 0 && this.simStatus != 0) {
                    this.powerUp();
                    return;
                }
            }

            if (this.simStatus != 0)
                return;

            if (this.assigned == 1 && data.dwRequestID == (uint)FSXObject.DATA_REQUESTS.NAVCOM1_REQ) {
                FSXObject.NavCom_Data navcomdata = (FSXObject.NavCom_Data)data.dwData[0];
                this.setNavComFreqs(navcomdata);
            } 
            
            if (this.assigned == 2 && data.dwRequestID == (uint)FSXObject.DATA_REQUESTS.NAVCOM2_REQ) {
                FSXObject.NavCom_Data navcomdata = (FSXObject.NavCom_Data)data.dwData[0];
                this.setNavComFreqs(navcomdata);
            }

        }     

        public override void SimButtons() {

            if (this.simStatus != 0)
                return;

            this.updateInput();
            
            if (!timers[TIMER_COMMSWAP].Enabled && this.isSwapSet(0)) {
                if (this.assigned == 1)
                    fsx.Comm1SwapFreq();
                else
                    fsx.Comm2SwapFreq();
                timers[TIMER_COMMSWAP].Enabled = true;
            }

            if (!timers[TIMER_NAVSWAP].Enabled && this.isSwapSet(1)) {
                if (this.assigned == 1)
                    fsx.Nav1SwapFreq();
                else
                    fsx.Nav2SwapFreq();

                timers[TIMER_NAVSWAP].Enabled = true;
            }

            // Check if the MHz/KHz has been pressed
            if (!timers[TIMER_COMMFLIP].Enabled && this.isFlipSet(0)) {
                this.flipcomm = 1 - this.flipcomm;
                timers[TIMER_COMMFLIP].Enabled = true;
            }

            if (!timers[TIMER_NAVFLIP].Enabled && this.isFlipSet(1)) {
                this.flipnav = 1 - this.flipnav;
                timers[TIMER_NAVFLIP].Enabled = true;
            }

            // Process the rotary encoders COMM1
            sbyte delta = this.getRotary(0, 0);
            this.resetRotary(0, 0);
            if (delta != 0) {
                if (delta < 0) {
                    delta = (sbyte)-delta;

                    if (this.flipcomm == 1)
                        if (this.assigned == 1)
                            fsx.Comm1DecFract();
                        else
                            fsx.Comm2DecFract();
                    else
                        if (this.assigned == 1)
                            fsx.Comm1DecWhole();
                        else
                            fsx.Comm2DecWhole();
                } else {

                    if (this.flipcomm == 1)
                        if (this.assigned == 1)
                            fsx.Comm1IncFract();
                        else
                            fsx.Comm2IncFract();
                    else
                        if (this.assigned == 1)
                            fsx.Comm1IncWhole();
                        else
                            fsx.Comm2IncWhole();
                }
            }

            // Process the rotary encoders NAV1
            delta = this.getRotary(1, 0);
            this.resetRotary(1, 0);
            if (delta != 0) {
                if (delta < 0) {
                    delta = (sbyte)-delta;

                    if (this.flipnav == 1)
                        if (this.assigned == 1)
                            fsx.Nav1DecFract();
                        else
                            fsx.Nav2DecFract();
                    else
                        if (this.assigned == 1)
                            fsx.Nav1DecWhole();
                        else
                            fsx.Nav2DecWhole();
                } else {

                    if (this.flipcomm == 1)
                        if (this.assigned == 1)
                            fsx.Nav1IncFract();
                        else
                            fsx.Nav2IncFract();
                    else
                        if (this.assigned == 1)
                            fsx.Nav1IncWhole();
                        else
                            fsx.Nav2IncWhole();
                }
            }

        }
    }
}