Skip to content

File ConsoleControl.xaml.cs

File List > PGRControls > ConsoleControl.xaml.cs

Go to the documentation of this file

//=============================================================================
// Copyright (c) 2026 FLIR Integrated Imaging Solutions, Inc. All Rights Reserved.
//
// This software is the confidential and proprietary information of FLIR
// Integrated Imaging Solutions, Inc. ("Confidential Information"). You
// shall not disclose such Confidential Information and shall use it only in
// accordance with the terms of the license agreement you entered into
// with FLIR Integrated Imaging Solutions, Inc. (FLIR)
//
// FLIR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
// SOFTWARE, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE, OR NON-INFRINGEMENT. FLIR SHALL NOT BE LIABLE FOR ANY DAMAGES
// SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
// THIS SOFTWARE OR ITS DERIVATIVES.
//=============================================================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Collections.ObjectModel;
using SpinnakerNET;
using SpinnakerNET.GenApi;
using SpinnakerNET.GUI.WPFControls;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using System.Text.RegularExpressions;

namespace SpinnakerNET.GUI
{
    namespace WPFControls
    {


        public sealed partial class ConsoleControl : BaseClass
        {
#region Fields
            public ObservableCollection<Color>myColors;

            private readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(ConsoleControl));
            private EventLogger _eventLogger;
            private bool _enableLogging = false;
            string consoleInput = string.Empty;
            bool echoInput = false;
            bool _autoScroll = true;
            string _txNodeName = "";
            string _rxNodeName = "";
            IManagedCamera _camera;
            IValue _txNode;
            IInteger _integerNode;
            IFloat _floatNode;
            IString _stringNode;
            Dictionary<string, DeviceEventHandler>_specificEventHandlers;
            List<DeviceEventHandler>_generalHandlers;
            ObservableCollection<string>consoleOutput =
                new ObservableCollection<string>(){"Welcome to SpinConsole Control"};
            bool _eventCleanedUp = false;
#endregion

#region Properties

            public string ConsoleInput
            {
                get
                {
                    return consoleInput;
                }
                set
                {
                    consoleInput = value;
                    NotifyPropertyChanged("ConsoleInput");
                }
            }

            public ObservableCollection<string>ConsoleOutput
            {
                get
                {
                    return consoleOutput;
                }
                set
                {
                    consoleOutput = value;
                    NotifyPropertyChanged("ConsoleOutput");
                }
            }

            public bool LoggingEnabled
            {
                get
                {
                    return _enableLogging;
                }
                set
                {
                    _enableLogging = value;
                    NotifyPropertyChanged("LoggingEnabled");
                    NotifyPropertyChanged("LoggingNotEnabled");
                }
            }

            public bool LoggingNotEnabled
            {
                get
                {
                    return !_enableLogging;
                }
            }

            public bool AutoScroll
            {
                get
                {
                    return _autoScroll;
                }
                set
                {
                    _autoScroll = value;
                    NotifyPropertyChanged("AutoScroll");
                }
            }

            public bool EchoInput
            {
                get
                {
                    return echoInput;
                }
                set
                {
                    echoInput = value;
                    NotifyPropertyChanged("EchoInput");
                }
            }

            public string TxNodeName
            {
                get
                {
                    return _txNodeName;
                }
                set
                {
                    _txNodeName = value;
                    NotifyPropertyChanged("TxNodeName");
                }
            }

            public string RxNodeName
            {
                get
                {
                    return _rxNodeName;
                }
                set
                {
                    _rxNodeName = value;
                    NotifyPropertyChanged("RxNodeName");
                }
            }
#endregion

            public ConsoleControl()
            {
                InitializeComponent();

                // Populate color combobox
                myColors = new ObservableCollection<Color>();
                Type colors = typeof (System.Drawing.Color);
                PropertyInfo[] colorInfo = colors.GetProperties(BindingFlags.Public | BindingFlags.Static);
                foreach(PropertyInfo info in colorInfo)
                {
                    mycbo.Items.Add(info.Name);
                }

                // Set datacontext
                DataContext = this;

                Loaded += ConsoleControl_Loaded;
                _specificEventHandlers = new Dictionary<string, DeviceEventHandler>();
                _generalHandlers = new List<DeviceEventHandler>();
            }

#region Public Methods
            public void Connect(IManagedCamera cam)
            {
                _camera = cam;
                _nodeMap = cam.GetNodeMap();

                if (string.IsNullOrWhiteSpace(_serialNumber))
                {
                    _serialNumber = RetrieveSerialNumber(_nodeMap);
                }

                // Use Dispatcher to catch the closing event
                Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
            }

            public override void Disconnect()
            {
                UnregisterEvents();

                if (_eventLogger != null)
                {
                    _eventLogger.ShutDownLogger();
                }

                _camera = null;
                _nodeMap = null;
            }

            private bool EnableEvent(string eventName)
            {
                // Retrieve EventNotification Node
                IEnum enumEventNotification = _nodeMap.GetNode<IEnum>("EventNotification");

                // Retrieve EventSelector Node
                IEnum enumEventSelector = _nodeMap.GetNode<IEnum>("EventSelector");

                for (uint i = 0; i < enumEventSelector.Entries.Length; i++)
                {
                    // Get current enum entry node
                    EnumEntry enumEntry = enumEventSelector.Entries[i];
                    if (!CheckNodeAccessibility(enumEntry))
                    {
                        // Go to next entry node
                        continue;
                    }

                    // Enable Event

                    // Set Selector Entry
                    if (!string.IsNullOrEmpty(eventName) && !eventName.Contains(enumEntry.Symbolic))
                    {
                        // Toggling a specific event and its not this entry
                        continue;
                    }

                    try
                    {
                        if (!enumEventSelector.IsWritable)
                        {
                            continue;
                        }

                        enumEventSelector.Value = enumEntry.Value;

                        // Enable ChunkData for corresponding entry
                        if (enumEventNotification.IsWritable)
                        {
                            enumEventNotification.Value = 1;
                            Console.Out.WriteLine(enumEventSelector.Value.String + " : enabled");
                        }
                        else
                        {
                            Console.Out.WriteLine(enumEventSelector.Value.String + " : not writable");
                        }
                    }
                    catch (SpinnakerException ex)
                    {
                        Console.Out.WriteLine("Spinnaker Error: " + ex.Message);
                    }
                    catch (Exception ex)
                    {
                        Console.Out.WriteLine("Error: " + ex.Message);
                    }
                }

                return true;
            }

            private static string SanitizeFileNameComponent(string value)
            {
                if (string.IsNullOrWhiteSpace(value))
                {
                    return "camera";
                }

                string sanitized = value;
                foreach (char invalidChar in Path.GetInvalidFileNameChars())
                {
                    sanitized = sanitized.Replace(invalidChar, '_');
                }

                sanitized = sanitized.Replace("..", "_").Trim('_', ' ');
                if (string.IsNullOrWhiteSpace(sanitized))
                {
                    sanitized = "camera";
                }

                return sanitized;
            }

            private void Dispatcher_ShutdownStarted(object sender, EventArgs e)
            {
                Disconnect();
            }

            public override void Connect(INodeMap nodemap, string nodename, string label = "")
            {
                throw new NotImplementedException("See Connect(IManagedCamera cam)");
            }

            public override void Refresh()
            {
            }
#endregion

#region UI Event Handlers
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                System.Windows.Forms.SaveFileDialog fileDlg = new System.Windows.Forms.SaveFileDialog();
                fileDlg.Filter = "Log file Path (*.txt,*.log)|*.txt;*.log";
                fileDlg.Title = "Select log file to save";
                fileDlg.DefaultExt = ".txt";

                System.Windows.Forms.DialogResult result = fileDlg.ShowDialog();

                if (result != System.Windows.Forms.DialogResult.OK)
                {
                    return;
                }
                else
                {
                    txt_logPath.Text = fileDlg.FileName;
                    LoggingEnabled = true;
                }
            }

            private void btn_enableLogging_Click(object sender, RoutedEventArgs e)
            {
                if ((bool) btn_enableLogging.IsChecked)
                {
                    if (txt_logPath.Text.Length == 0)
                    {
                        // Using device serial number as path
                        string safeSerial = SanitizeFileNameComponent(_serialNumber);
                        string filename = "SN" + safeSerial + "_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".txt";
                        txt_logPath.Text = filename;
                    }

                    if (_eventLogger != null)
                    {
                        _eventLogger.ShutDownLogger();
                    }

                    try
                    {
                        _eventLogger = new EventLogger(txt_logPath.Text);
                    }
                    catch (Exception ex)
                    {
                        _eventLogger = null;
                        btn_enableLogging.IsChecked = false;
                        MessageBox.Show(
                            ex.Message, "Error creating log file", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }

            void ConsoleControl_Loaded(object sender, RoutedEventArgs e)
            {
                InputBlock.KeyDown += InputBlock_KeyDown;
                InputBlock.Focus();
            }

            void InputBlock_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.Key == Key.Enter)
                {
                    ConsoleInput = InputBlock.Text;

                    // Update Tx node
                    UpdateNodeValue(ConsoleInput);

                    // Clear input field
                    ResetInput();

                    InputBlock.Focus();

                    e.Handled = true;
                }
            }

            private void Clear_Click(object sender, RoutedEventArgs e)
            {
                Clear();
            }

            private void Copy_Click(object sender, RoutedEventArgs e)
            {
                Copy();
            }

            private void chk_txNode_Click(object sender, RoutedEventArgs e)
            {
                if ((bool) chk_txNode.IsChecked)
                {
                    if (string.IsNullOrEmpty(txt_txNode.Text))
                    {
                        MessageBox.Show(
                            "Please make sure a valid TxNode name was entered.",
                            "Invalid TxNode",
                            MessageBoxButton.OK,
                            MessageBoxImage.Exclamation);
                        chk_txNode.IsChecked = false;
                        e.Handled = true;
                        return;
                    }

                    if (_camera == null)
                    {
                        MessageBox.Show(
                            "Please make sure a valid device was connected.",
                            "Not Connected",
                            MessageBoxButton.OK,
                            MessageBoxImage.Exclamation);
                        chk_txNode.IsChecked = false;
                        e.Handled = true;
                        return;
                    }

                    try
                    {
                        if (!SetTxNode(TxNodeName))
                        {
                            chk_txNode.IsChecked = false;
                            e.Handled = true;
                            return;
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(
                            ex.Message, "Problem registering event", MessageBoxButton.OK, MessageBoxImage.Error);
                        chk_txNode.IsChecked = false;
                        e.Handled = true;
                        return;
                    }
                }
            }

            private void chk_rxNode_Click(object sender, RoutedEventArgs e)
            {
                if ((bool) chk_rxNode.IsChecked)
                {
                    if (_camera == null)
                    {
                        MessageBox.Show(
                            "Please make sure a valid device was connected.",
                            "Not Connected",
                            MessageBoxButton.OK,
                            MessageBoxImage.Exclamation);
                        chk_rxNode.IsChecked = false;
                        e.Handled = true;
                        return;
                    }

                    try
                    {
                        // Try enabling event
                        if (!EnableEvent(RxNodeName))
                        {
                            MessageBox.Show(
                                string.Format("There was a problem enabling {0} on device.", RxNodeName),
                                "Error",
                                MessageBoxButton.OK,
                                MessageBoxImage.Exclamation);
                            chk_rxNode.IsChecked = false;
                            e.Handled = true;
                            return;
                        }

                        // Register event
                        if (string.IsNullOrEmpty(RxNodeName))
                        {
                            if (_generalHandlers.Count == 1)
                            {
                                MessageBox.Show(
                                    "There was already a general event handler registered.",
                                    "Error",
                                    MessageBoxButton.OK,
                                    MessageBoxImage.Exclamation);
                                chk_rxNode.IsChecked = false;
                                e.Handled = true;
                                return;
                            }

                            DeviceEventHandler handler = new DeviceEventHandler();
                            handler.OnMessageReceived += OnMessageReceived;

                            // General handler
                            _camera.RegisterEventHandler(handler);

                            _generalHandlers.Add(handler);
                        }
                        else
                        {
                            if (_specificEventHandlers.ContainsKey(RxNodeName))
                            {
                                // Handler for this event already exist
                                MessageBox.Show(
                                    string.Format("{0} was already been monitored.", txt_rxNode.Text),
                                    "Error",
                                    MessageBoxButton.OK,
                                    MessageBoxImage.Exclamation);
                            }
                            else
                            {
                                DeviceEventHandler handler = new DeviceEventHandler();
                                handler.OnMessageReceived += OnMessageReceived;

#pragma warning disable CS0618
                                _camera.RegisterEventHandler(handler, RxNodeName);
#pragma warning restore CS0618

                                _specificEventHandlers.Add(RxNodeName, handler);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(
                            ex.Message,
                            "Problem registering device event",
                            MessageBoxButton.OK,
                            MessageBoxImage.Exclamation);
                        chk_rxNode.IsChecked = false;
                        e.Handled = true;
                        return;
                    }
                }
                else
                {
                    UnregisterEvents();
                }
            }
#endregion

#region DeviceEvent Related
            public void Clear()
            {
                ConsoleOutput.Clear();
            }

            public void Copy()
            {
                try
                {
                    StringBuilder sb = new StringBuilder();

                    foreach(string message in ConsoleOutput)
                    {
                        sb.Append(message);
                        sb.AppendLine();
                    }

                    Clipboard.SetText(sb.ToString());
                }
                catch (Exception ex)
                {
                    // log.Error("Error copying text to clipboard.", ex);
                    throw new Exception(string.Format("Error copying text to clipboard. {0}", ex.Message));
                }
            }

            internal void ResetInput()
            {
                if (EchoInput)
                {
                    // Echo input
                    ConsoleOutput.Add(">" + ConsoleInput);

                    if (LoggingEnabled)
                    {
                        try
                        {
                            _eventLogger.LogMessage(">" + ConsoleInput);
                        }
                        catch (Exception ex)
                        {
                            log.Warn("There was a problem logging console message to file.", ex);
                        }
                    }
                }

                if (AutoScroll)
                {
                    Scroller.ScrollToBottom();
                }

                ConsoleInput = String.Empty;
            }

            internal void AppendMessage(string message)
            {
                ConsoleOutput.Add(message);

                if (AutoScroll)
                {
                    Scroller.ScrollToBottom();
                }
            }

            void OnMessageReceived(string message)
            {
                if (LoggingEnabled)
                {
                    try
                    {
                        var result = Regex.Split(message, "\r\n|\r|\n");
                        foreach(string msg in result)
                        {
                            _eventLogger.LogMessage(msg);
                        }
                    }
                    catch (Exception ex)
                    {
                        log.Warn("There was a problem logging console message to file.", ex);
                    }
                }

                AppendMessage(message);
            }

            private void UnregisterEvents()
            {
                if (_camera == null)
                {
                    return;
                }

                if (_eventCleanedUp)
                {
                    return;
                }

                try
                {
                    // Unregister
                    foreach(DeviceEventHandler handler in _specificEventHandlers.Values)
                    {
                        _camera.UnregisterEventHandler(handler);
                    }

                    foreach(DeviceEventHandler handler in _generalHandlers)
                    {
                        _camera.UnregisterEventHandler(handler);
                    }
                }
                catch (Exception)
                {
                }

                _specificEventHandlers.Clear();
                _generalHandlers.Clear();

                _eventCleanedUp = true;
            }

            private void UpdateNodeValue(string input)
            {
                if (_nodeType == typeof (Integer) || _nodeType == typeof (IntReg))
                {
                    try
                    {
                        if (_integerNode != null && _integerNode.IsWritable)
                        {
                            long convertedInput = 0;

                            if (long.TryParse(input, out convertedInput))
                            {
                                _integerNode.Value = convertedInput;
                            }
                            else
                            {
                                throw new Exception(string.Format(
                                    "Node {0}: can't convert string {1} to long", _propertyToControl, input));
                            }
                        }
                        else
                        {
                            log.Debug(string.Format("{0} node is currently not writable.", _propertyToControl));
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception(string.Format("Problem updating node value. {0}", ex.Message));
                    }
                }
                else if (_nodeType == typeof (StringNode) || _nodeType == typeof (StringReg))
                {
                    try
                    {
                        if (_stringNode != null && _stringNode.IsWritable)
                        {
                            // Write new value back to node
                            _stringNode.Value = input;
                        }
                        else
                        {
                            log.Debug(string.Format(
                                "{1}{0} node is currently not writable.", _propertyToControl, FormattedSerialNumber));
                        }
                    }
                    catch (Exception ex)
                    {
                        log.Warn(
                            string.Format("{1}Problem updating node value. {0}", ex.Message, FormattedSerialNumber));
                    }
                }
                else if (_nodeType == typeof (Float))
                {
                    try
                    {
                        if (_floatNode != null && _floatNode.IsWritable)
                        {
                            float convertedInput = 0;

                            if (float.TryParse(input, out convertedInput))
                            {
                                _floatNode.Value = convertedInput;
                            }
                            else
                            {
                                // Abort updating node's value
                                // show old value on screen
                                log.Error(string.Format(
                                    "Node {0}: can't convert string {1} to long", _propertyToControl, input));
                            }
                        }
                        else
                        {
                            log.Error(string.Format(
                                "{1}{0} node is currently not writable.", _propertyToControl, FormattedSerialNumber));
                        }
                    }
                    catch (Exception ex)
                    {
                        log.Error(string.Format("Problem updating node value. {0}", ex.Message));
                    }
                }
            }

            public bool SetTxNode(string nodeName)
            {
                _txNode = _nodeMap.GetNode<IValue>(nodeName);

                if (_txNode == null)
                {
                    MessageBox.Show(
                        string.Format("Feature \"{0}\" not found on device.", nodeName),
                        "Error connecting to Tx Node",
                        MessageBoxButton.OK,
                        MessageBoxImage.Error);
                    return false;
                }

                _propertyToControl = nodeName;
                _nodeType = _txNode.GetType();

                if (_nodeType == typeof (Float))
                {
                    try
                    {
                        if (_floatNode == null)
                        {
                            _floatNode = _nodeMap.GetNode<IFloat>(nodeName);
                        }
                    }
                    catch (System.Exception ex)
                    {
                        MessageBox.Show(
                            ex.Message, "Error connecting to Tx Node", MessageBoxButton.OK, MessageBoxImage.Error);
                        return false;
                    }
                }
                if (_nodeType == typeof (StringNode) || _nodeType == typeof (StringReg))
                {
                    try
                    {
                        if (_stringNode == null)
                        {
                            _stringNode = _nodeMap.GetNode<IString>(nodeName);
                        }
                    }
                    catch (System.Exception ex)
                    {
                        MessageBox.Show(
                            ex.Message, "Error connecting to Tx Node", MessageBoxButton.OK, MessageBoxImage.Error);
                        return false;
                    }
                }
                else if (_nodeType == typeof (Integer) || _nodeType == typeof (IntReg))
                {
                    try
                    {

                        if (_integerNode == null)
                        {
                            _integerNode = _nodeMap.GetNode<IInteger>(nodeName);
                        }
                    }
                    catch (System.Exception ex)
                    {
                        MessageBox.Show(
                            ex.Message, "Error connecting to Tx Node", MessageBoxButton.OK, MessageBoxImage.Error);
                        return false;
                    }
                }
                else
                {
                    // Unhandled node type detected
                    Console.Out.WriteLine("Unexpected control type!");
                    MessageBox.Show(
                        "Unexpected control type. Please choose another node.",
                        "Error connecting to node",
                        MessageBoxButton.OK,
                        MessageBoxImage.Error);
                    return false;
                }

                return true;
            }
#endregion

#region HELPERS
            private bool CheckNodeAccessibility(INode node)
            {
                return (node.IsReadable || node.IsWritable);
            }

            private void InputBlock_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
            {
                try
                {
                    if (Scroller != null)
                    {
                        // Set scroller size to make vertical scroll bar show up
                        Scroller.Height = Scroller.ActualHeight;
                    }
                }
                catch (Exception)
                {
                }
            }

            private void InputBlock_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                try
                {
                    // Setting height to NaN so Scroller will auto resize with parent
                    Scroller.Height = double.NaN;
                }
                catch (Exception)
                {
                }
            }
#endregion
        }


#pragma warning disable CS0618
        internal class DeviceEventHandler : ManagedDeviceEventHandler
#pragma warning restore CS0618
        {
            public delegate void MessageReceived(string message);

            public event MessageReceived OnMessageReceived;

            unsafe protected override void OnDeviceEvent(string eventName)
            {
                try
                {
                    int payloadSize = (int) this.GetEventPayloadDataSize();
                    UnmanagedMemoryStream stream = new UnmanagedMemoryStream(GetDeviceEventPayloadData(), payloadSize);
                    BinaryReader reader = new BinaryReader(stream);

                    string message = new string(reader.ReadChars(payloadSize));
                    reader.Close();
                    if (!string.IsNullOrEmpty(message) && OnMessageReceived != null)
                    {
                        Application.Current.Dispatcher.BeginInvoke(
                            (Action)(() => {
                                // Append callback message to console
                                OnMessageReceived(message);
                            }),
                            System.Windows.Threading.DispatcherPriority.Background,
                            null);
                    }
                }
                catch (Exception ex)
                {
                    Console.Out.WriteLine(ex.Message);
                }
            }
        }

        internal class EventLogger
        {
            private StreamWriter _logger;
            private bool _closed = false;

            public EventLogger(string path)
            {
                _logger = new StreamWriter(path, true);
            }

            ~EventLogger()
            {
                _logger.Close();
            }

            public void ShutDownLogger()
            {
                if (_closed)
                {
                    return;
                }

                _logger.Close();
                _closed = true;
            }

            public void LogMessage(string message)
            {
                _logger.WriteLine(message);
                _logger.Flush();
            }
        }
    }
}