aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Touch/Controls/SelectionMode.cs
blob: a570a0863beffb9458f440151dcbd689dbd8f5a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tango.Touch.Controls
{
    public enum SelectionMode
    {
        None,
        Single,
        Multiple
    }
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using Tango.Core;

namespace Tango.FirmwareUpdateLib.WPF
{
    public class FirmwareUpgradeManager : ExtendedObject
    {
        private FirmwareUpdateManager _updater;
        private List<DFUDevice> _current_devices;

        #region Events

        /// <summary>
        /// Reports about the progress of an on-going firmware upgrade.
        /// </summary>
        public event EventHandler<FirmwareUpgradeProgressEventArgs> UpgradeProgress;

        #endregion

        #region Properties

        private FirmwareUpgradeManagerState _state;
        /// <summary>
        /// Gets or sets the current manager state.
        /// </summary>
        public FirmwareUpgradeManagerState State
        {
            get { return _state; }
            private set { _state = value; RaisePropertyChangedAuto(); }
        }

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="FirmwareUpgradeManager"/> class.
        /// </summary>
        public FirmwareUpgradeManager()
        {
            _current_devices = new List<DFUDevice>();
        }

        /// <summary>
        /// Performs a full automatic upgrade by getting the first DFU device switching to DFU mode if necessary.
        /// Uploading, verifying, resetting the device, then checking device existence.
        /// </summary>
        /// <param name="mcuFilePath">The MCU bin file path.</param>
        /// <returns></returns>
        public Task PerformUpgrade(byte[] mcuData)
        {
            EnsureStateIdle();

            State = FirmwareUpgradeManagerState.Busy;

            TaskCompletionSource<object> taskSource = new TaskCompletionSource<object>();

            ProgressDispatcher progressDispatcher = new ProgressDispatcher();

            Task.Factory.StartNew(() =>
            {
                try
                {
                    OnUpgradeProgressChanged(100, 0, FirmwareUpgradeManagerState.Initializing);
                    Initialize();
                    Thread.Sleep(1000);

                    LogManager.Log("Initializing progress dispatcher...");

                    OnUpgradeProgressChanged(100, 10, State);

                    LogManager.Log("Starting automatic full upgrade...");

                    OnUpgradeProgressChanged(100, 20, FirmwareUpgradeManagerState.EnumeratingDevices);
                    var device = GetAvailableDevices().FirstOrDefault();
                    Thread.Sleep(1000);

                    State = FirmwareUpgradeManagerState.Busy;

                    OnUpgradeProgressChanged(100, 30, State);

                    Thread.Sleep(1000);

                    if (device == null)
                    {
                        throw LogManager.Log(new NullReferenceException("No DFU device found on the system."));
                    }

                    LogManager.Log("Found DFU device...");
                    LogManager.Log($"Name: {device.DeviceName}");
                    LogManager.Log($"Mode: {device.Mode}");

                    if (device.Mode == DFUMode.RunTime)
                    {
                        State = FirmwareUpgradeManagerState.SwitchingToDFU;
                        LogManager.Log("Switching to DFU mode...");
                        OnUpgradeProgressChanged(100, 40, State);
                        Thread.Sleep(1000);

                        device.SwitchToDFUMode();
                        LogManager.Log("Waiting for the device to comeback (3 sec)...");

                        State = FirmwareUpgradeManagerState.Waiting;
                        OnUpgradeProgressChanged(100, 50, State);
                        Thread.Sleep(3000);

                        LogManager.Log("Looking for the modified DFU device...");
                        OnUpgradeProgressChanged(100, 60, FirmwareUpgradeManagerState.EnumeratingDevices);
                        Thread.Sleep(1000);

                        device = GetAvailableDevices().FirstOrDefault();

                        State = FirmwareUpgradeManagerState.SwitchingToDFU;
                        OnUpgradeProgressChanged(100, 60, State);

                        if (device == null)
                        {
                            throw LogManager.Log(new NullReferenceException("Could not locate the modified DFU device."));
                        }

                        if (device.Mode == DFUMode.RunTime)
                        {
                            throw LogManager.Log(new InvalidOperationException("The DFU device was found but has failed to switch into DFU mode."));
                        }

                        LogManager.Log("DFU device successfully switched to DFU mode.");
                        LogManager.Log($"Name: {device.DeviceName}");
                        LogManager.Log($"Mode: {device.Mode}");
                    }
                    else
                    {
                        LogManager.Log("Device is in DFU mode. Skipping DFU switching...");
                    }

                    State = FirmwareUpgradeManagerState.StartingUpload;
                    OnUpgradeProgressChanged(100, 100, State);

                    LogManager.Log("Starting DFU upload...");

                    ProgressMode current_mode = ProgressMode.Verifying;

                    progressDispatcher.Initialize();

                    progressDispatcher.Invoke(() =>
                    {
                        device.Upload(mcuData, (mode, current, total) =>
                        {
                            try
                            {
                                if (current_mode != mode)
                                {
                                    current_mode = mode;
                                    LogManager.Log($"DFU Upload Status: {current_mode}");
                                }

                                if (mode == ProgressMode.Uploading)
                                {
                                    OnUpgradeProgressChanged(total, current, FirmwareUpgradeManagerState.Uploading);
                                }
                                else if (mode == ProgressMode.Verifying)
                                {
                                    OnUpgradeProgressChanged(total, current, FirmwareUpgradeManagerState.Verifying);
                                }

                                if (mode == ProgressMode.Error)
                                {
                                    throw LogManager.Log(new ApplicationException("DFU upload got an error notification!"));
                                }
                                else if (mode == ProgressMode.Completed)
                                {
                                    LogManager.Log("DFU upload completed successfully.");
                                    LogManager.Log("Resetting the device...");
                                    State = FirmwareUpgradeManagerState.Resetting;
                                    OnUpgradeProgressChanged(100, 0, State);
                                    device.Reset();
                                    LogManager.Log("Waiting for the device to comeback (3 sec)...");

                                    State = FirmwareUpgradeManagerState.Waiting;
                                    OnUpgradeProgressChanged(100, 30, State);
                                    Thread.Sleep(3000);

                                    LogManager.Log("Looking for the modified DFU device...");
                                    OnUpgradeProgressChanged(100, 70, FirmwareUpgradeManagerState.EnumeratingDevices);
                                    device = GetAvailableDevices().FirstOrDefault();
                                    Thread.Sleep(1000);

                                    State = FirmwareUpgradeManagerState.Busy;
                                    OnUpgradeProgressChanged(100, 90, State);
                                    Thread.Sleep(1000);

                                    if (device == null)
                                    {
                                        throw LogManager.Log(new NullReferenceException("Could not locate the modified DFU device."));
                                    }

                                    if (device.Mode == DFUMode.DFU)
                                    {
                                        throw LogManager.Log(new InvalidOperationException("The DFU device was found but has failed to switch back into RunTime mode."));
                                    }

                                    LogManager.Log("DFU device successfully upgraded!");
                                    LogManager.Log($"Name: {device.DeviceName}");
                                    LogManager.Log($"Mode: {device.Mode}");

                                    State = FirmwareUpgradeManagerState.Completed;
                                    OnUpgradeProgressChanged(100, 100, State);

                                    taskSource.SetResult(true);

                                    progressDispatcher.Close();
                                }


                                DoEvents();
                            }
                            catch (Exception ex)
                            {
                                taskSource.SetException(ex);
                                progressDispatcher.Close();
                            }
                            finally
                            {
                                State = FirmwareUpgradeManagerState.Idle;
                            }
                        });
                    });
                }
                catch (Exception ex)
                {
                    taskSource.SetException(ex);
                }
                finally
                {
                    State = FirmwareUpgradeManagerState.Idle;
                }
            });

            return taskSource.Task;
        }

        /// <summary>
        /// Ensures the state idle.
        /// </summary>
        /// <exception cref="System.InvalidOperationException"></exception>
        private void EnsureStateIdle()
        {
            if (State != FirmwareUpgradeManagerState.Idle) throw new InvalidOperationException($"Operation can be performed only on {FirmwareUpgradeManagerState.Idle} state.");
        }

        /// <summary>
        /// Gets the available devices.
        /// </summary>
        /// <returns></returns>
        private List<DFUDevice> GetAvailableDevices()
        {
            State = FirmwareUpgradeManagerState.EnumeratingDevices;

            LogManager.Log("Disposing previous devices...");
            foreach (var device in _current_devices)
            {
                try
                {
                    LogManager.Log($"Disposing previous device {device.DeviceName}...");
                    device.Dispose();
                }
                catch { }
            }

            try
            {
                LogManager.Log("Enumerating available DFU devices...");
                _current_devices = _updater.GetAvailableDevices(false).Where(x => !x.DeviceName.Contains("In-Circuit Debug Interface")).ToList();
            }
            catch (Exception ex)
            {
                throw LogManager.Log(ex, "Error enumerating available DFU devices.");
            }

            return _current_devices;
        }

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        public void Initialize()
        {
            State = FirmwareUpgradeManagerState.Initializing;
            try
            {
                LogManager.Log("Initializing firmware upgrade API...");
                _updater = new FirmwareUpdateManager();
                _updater.Initialize();
            }
            catch (Exception ex)
            {
                throw LogManager.Log(ex, "Error initializing firmware upgrade API.");
            }
        }

        private void DoEvents()
        {
            Application.Current.Dispatcher.Invoke(DispatcherPriority.Background,
                                                  new Action(delegate { }));
        }

        /// <summary>
        /// Raises the <see cref="UpgradeProgress"/> event.
        /// </summary>
        /// <param name="total">The total.</param>
        /// <param name="progress">The progress.</param>
        /// <param name="state">The state.</param>
        protected virtual void OnUpgradeProgressChanged(double total, double progress, FirmwareUpgradeManagerState state)
        {
            UpgradeProgress?.Invoke(this, new FirmwareUpgradeProgressEventArgs()
            {
                Progress = progress,
                Total = total,
                State = state,
            });
        }
    }
}