private static void GetErrorLogComplete(INTV.LtoFlash.Model.ErrorLog errorLog)
        {
            var message = "Retrieved error log:\n\n";

            if (errorLog == null)
            {
                message += "<null>";
            }
            else
            {
                message += errorLog.GetDetailedErrorReport(INTV.LtoFlash.Model.FirmwareRevisions.UnavailableFirmwareVersion);
            }
            INTV.Shared.View.OSMessageBox.Show(message, "Error Log Retrieved");
        }
        /// <summary>
        /// This is a general-purpose command completion routine for use with the asynchronous task system for executing commands on a Locutus device.
        /// </summary>
        /// <param name="taskData">The task data.</param>
        /// <remarks>This function will be called on the main thread when a Locutus command has finished executing. It will report whether the command
        /// successfully executed, and execute an optional callback upon success.</remarks>
        private static void OnComplete(AsyncTaskData taskData)
        {
            var data = (ExecuteDeviceCommandAsyncTaskData)taskData;

#if REPORT_COMMAND_PERFORMANCE
            var portName = data.Device.Port == null ? "NO_PORT" : data.Device.Port.Name;
            try
            {
#endif // REPORT_COMMAND_PERFORMANCE
            data.Device.IsCommandInProgress = false;
            data.ExitedCommand = true;
            data.Device.Port.LogPortMessage("<<<< ExecuteDeviceCommandAsyncTaskData COMPLETE: CommandInProgress: FALSE");
            var exception                 = data.Error;
            var exceptionErrorDetail      = data.DeviceExceptionDetail;
            var failureMessage            = data.FailureMessage;
            var currentlyExecutingCommand = data.CurrentlyExecutingCommand;
            bool succeeded                = data.Succeeded && (exception == null);
            if (succeeded && (data.OnSuccess != null))
            {
                data.OnSuccess(data.Cancelled, data.DidShowProgress, data.Result);
            }
            var goIdle = !succeeded;
            if (goIdle)
            {
                data.Device.ConnectionState = ConnectionState.Idle;
            }
            if (!succeeded && (data.OnFailure != null))
            {
                var errorMessageBuilder = new System.Text.StringBuilder();
                errorMessageBuilder.Append(string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.DeviceCommand_Generic_FailedFormat, currentlyExecutingCommand));
                if (!string.IsNullOrWhiteSpace(exceptionErrorDetail))
                {
                    if (errorMessageBuilder.Length > 0)
                    {
                        errorMessageBuilder.AppendLine();
                    }
                    errorMessageBuilder.Append(exceptionErrorDetail.Trim());
                }
                exceptionErrorDetail = errorMessageBuilder.ToString();
                if (exception != null)
                {
                    ErrorLog errorLog = null;
                    var      errorLogMessageString = string.Empty;
                    if (exception is DeviceCommandExecuteFailedException)
                    {
                        try
                        {
                            data.Device.Port.LogPortMessage(">>>> ExecuteDeviceCommandAsyncTaskData COMPLETE: FETCH ERROR LOG: CommandInProgress: TRUE");
                            data.Device.IsCommandInProgress = true;
                            var gotErrorSucceeded = false;
                            errorLog = Commands.DownloadErrorLog.Instance.Execute(data.Device.Port, null, out gotErrorSucceeded) as ErrorLog;
                            const int MaxDownloadErrorRetryCount = 3;
                            for (int i = 0; !gotErrorSucceeded && (errorLog == null) && (i < MaxDownloadErrorRetryCount); ++i)
                            {
                                DebugOutput("Retry download error log attempt #" + i + 1);

                                // Wait for a beacon and try again.
                                if (data.Device.WaitForBeacon(ProtocolCommand.WaitForBeaconTimeout))
                                {
                                    errorLog = Commands.DownloadErrorLog.Instance.Execute(data.Device.Port, null, out gotErrorSucceeded) as ErrorLog;
                                }
                            }
                            errorMessageBuilder.AppendLine();
                            if (gotErrorSucceeded)
                            {
                                if (errorLog.ErrorIds.All(id => id == ErrorLogId.Luigi))
                                {
                                    errorLogMessageString = Resources.Strings.ErrorLog_DecodeLuigiErrorMessage;
                                }
                                else
                                {
                                    var errorLogContents = errorLog.GetDetailedErrorReport(data.Device.FirmwareRevisions.Current);
                                    if (string.IsNullOrWhiteSpace(errorLogContents))
                                    {
                                        errorLogContents = Resources.Strings.ErrorBufferReport_Empty;
                                    }
                                    errorMessageBuilder.AppendLine().AppendFormat(System.Globalization.CultureInfo.CurrentCulture, Resources.Strings.ErrorBufferReport_Format, errorLogContents);
                                    errorLog = null;     // we don't want to use the error log mechanism in this case
                                }
                            }
                            else
                            {
                                errorMessageBuilder.AppendLine().AppendLine(Resources.Strings.ErrorBufferReport_FailedToRetrieve);
                            }
                        }
                        catch (Exception e)
                        {
                            errorMessageBuilder.AppendLine().AppendLine(Resources.Strings.ErrorBufferReport_ThrewException).AppendLine().AppendLine(e.ToString());
                        }
                        finally
                        {
                            data.Device.IsCommandInProgress = false;
                            data.Device.Port.LogPortMessage(">>>> ExecuteDeviceCommandAsyncTaskData COMPLETE: FETCH ERROR LOG: CommandInProgress: FALSE");
                        }
                        exceptionErrorDetail = errorMessageBuilder.ToString();
                    }
                    if ((errorLog != null) && !string.IsNullOrEmpty(errorLogMessageString))
                    {
                        exception = new DeviceCommandFailedException(errorLogMessageString, errorLog, exception as DeviceCommandExecuteFailedException);
                    }
                    else
                    {
                        exception = new DeviceCommandFailedException(currentlyExecutingCommand, exception, exceptionErrorDetail);
                    }
                }
                else
                {
                    exception = new DeviceCommandFailedException(currentlyExecutingCommand, exceptionErrorDetail);
                }
                if (string.IsNullOrWhiteSpace(failureMessage))
                {
                    var endOfFirstLine = exceptionErrorDetail.IndexOf(Environment.NewLine);
                    if (endOfFirstLine > 0)
                    {
                        failureMessage = exceptionErrorDetail.Substring(0, endOfFirstLine).Trim();
                    }
                    else
                    {
                        failureMessage = exceptionErrorDetail.Trim();
                    }
                }
                succeeded = data.OnFailure(failureMessage, exception);
            }
            if (goIdle)
            {
                data.Device.ConnectionState = ConnectionState.WaitForBeacon;
            }
            data.Dispose();
            if (!succeeded)
            {
                if (string.IsNullOrWhiteSpace(failureMessage))
                {
                    throw new DeviceCommandFailedException(currentlyExecutingCommand, exception, exceptionErrorDetail);
                }
                else
                {
                    throw new DeviceCommandFailedException(currentlyExecutingCommand, failureMessage, exception, exceptionErrorDetail);
                }
            }
#if REPORT_COMMAND_PERFORMANCE
        }

        finally
        {
            data.Stopwatch.Stop();
            DebugOutput(portName + ": DEVICECOMMAND FINISH: " + data.DoWorkMethodName + " DURATION: " + data.Stopwatch.Elapsed.ToString());
        }
#endif // REPORT_COMMAND_PERFORMANCE
            // I don't like doing this here -- it's too "UI-ey" for being in the Model, but
            // it fixes various problems and is easier than adding a universal 'on command complete' handler.
            INTV.Shared.ComponentModel.CommandManager.InvalidateRequerySuggested();
        }