private static void DownloadRom(AsyncTaskData taskData) { SingleInstanceApplication.Instance.IsBusy = true; var data = (DownloadTaskData)taskData; var romPath = PrepareRom(data); data.UpdateTaskProgress(0, string.Format(CultureInfo.CurrentCulture, Resources.Strings.DownloadRom_Update_Format, romPath)); var cancelled = data.AcceptCancelIfRequested(); if (!cancelled) { using (var rom = FileUtilities.OpenFileStream(romPath)) { var configData = new Dictionary <string, object>() { { SerialPortConnection.PortNameConfigDataName, data.Intellicart.SerialPort } }; using (var port = SerialPortConnection.Create(configData)) { port.BaudRate = data.Intellicart.BaudRate; port.WriteTimeout = data.Intellicart.Timeout * 1000; // default port settings are 8,N,1 with no handshaking var bytesRemaining = (int)rom.Length; var totalBytes = rom.Length; var bytesPerSecond = data.Intellicart.BaudRate / 8; var bytesWritten = 0; var estimatedDownloadTime = ((double)rom.Length / bytesPerSecond) + 4; // give it time to finish var estimatedTimeRemaining = estimatedDownloadTime; var percentDone = 0.0; // Would like to respond to cancel requests somewhat quickly. So, let's // write out small enough chunks even at the slowest baud rate... var bytesPerWrite = (data.Intellicart.BaudRate / 2400) * 128; System.Diagnostics.Debug.Assert(bytesPerWrite > 0, "How did we get zero bytes to write?!"); port.Open(); var stopwatch = System.Diagnostics.Stopwatch.StartNew(); byte[] buffer = new byte[bytesPerWrite]; while (!cancelled && (bytesRemaining > 0)) { var updateText = string.Format(CultureInfo.CurrentCulture, Resources.Strings.DownloadRom_UpdateTitle_Format, data.Name, Math.Max(0, (int)estimatedTimeRemaining)); data.UpdateTaskTitle(updateText); bytesPerWrite = Math.Min(bytesPerWrite, bytesRemaining); var bytesRead = rom.Read(buffer, 0, bytesPerWrite); bytesWritten += bytesRead; bytesRemaining -= bytesRead; updateText = string.Format(CultureInfo.CurrentCulture, Resources.Strings.DownloadRom_Update_Format, romPath); estimatedTimeRemaining = estimatedDownloadTime - stopwatch.Elapsed.TotalSeconds; percentDone = stopwatch.Elapsed.TotalSeconds / estimatedDownloadTime; data.UpdateTaskProgress(percentDone, updateText); port.WriteStream.Write(buffer, 0, bytesRead); cancelled = data.AcceptCancelIfRequested(); } // If we close the port too soon after writing, the Intellicart will time out reading data from the stream. // This is likely due to buffering, and that the streams get disposed when the port and file streams are // disposed. On Mac in particular, the write out to the port may complete far more quickly than what the // math would indicate, based on observation. This implies one of the following: // a) Even though the synchronous write was called, the underlying implementation is asynchronous // b) It could be that the driver itself is "lying" to the underlying implementation // c) Buffering, either in the driver, kernel, or other API layers, misleads the higher-level APIs var timedOut = false; while (!cancelled && !timedOut) { var message = string.Format(Resources.Strings.DownloadRom_UpdateTitle_Format, data.Name, Math.Max(0, (int)estimatedTimeRemaining)); data.UpdateTaskTitle(message); System.Threading.Thread.Sleep(250); cancelled = data.AcceptCancelIfRequested(); var updateText = string.Format(CultureInfo.CurrentCulture, Resources.Strings.DownloadRom_Update_Format, romPath); estimatedTimeRemaining = estimatedDownloadTime - stopwatch.Elapsed.TotalSeconds; percentDone = Math.Max(100, stopwatch.Elapsed.TotalSeconds / estimatedDownloadTime); data.UpdateTaskProgress(percentDone, updateText); timedOut = estimatedTimeRemaining < 0; } } } } }
private static void CheckDevices(AsyncTaskData taskData) { var data = (CheckForDevicesTaskData)taskData; var validPorts = new HashSet <string>(); data.ValidDevicePorts = validPorts; var potentialPorts = data.LtoFlashViewModel.AvailableDevicePorts.Except(data.CurrentDevices).ToList(); if (!string.IsNullOrWhiteSpace(data.LastKnownPort) && (potentialPorts.Count > 1) && potentialPorts.Remove(data.LastKnownPort)) { potentialPorts.Insert(0, data.LastKnownPort); } foreach (var portName in potentialPorts) { var maxRetries = 1; for (var retry = 0; retry < maxRetries; ++retry) { if (data.AcceptCancelIfRequested()) { break; } var errorLogger = Properties.Settings.Default.EnablePortLogging ? new Logger(Configuration.Instance.GetPortLogPath(portName)) : null; try { var isValidDevicePort = false; var configData = new Dictionary <string, object>() { { SerialPortConnection.PortNameConfigDataName, portName } }; using (var port = SerialPortConnection.Create(configData)) { if (Properties.Settings.Default.EnablePortLogging) { port.EnableLogging(Configuration.Instance.GetPortLogPath(portName)); } port.LogPortMessage("CheckForDevices: BEGIN"); data.UpdateTaskProgress(0, string.Format(Resources.Strings.DeviceSearch_Task_Progress_Format, portName)); port.BaudRate = Device.DefaultBaudRate; port.Handshake = Device.Handshake; port.Open(); var numRetry = 4; var timeout = 1100; for (var i = 0; !data.AcceptCancelIfRequested() && (i < numRetry); ++i) { if (!data.AcceptCancelIfRequested()) { if (port.IsOpen && port.WaitForBeacon(timeout)) { isValidDevicePort = true; } } } port.LogPortMessage("CheckForDevices: END"); } if (!data.AcceptCancelIfRequested() && isValidDevicePort) { if (Properties.Settings.Default.AutomaticallyConnectToDevices && data.AutoConnect) { data.ReportedAnyAutoConnectDevices |= true; var creationInfo = new Dictionary <string, object>() { { DeviceCreationInfo.ConfigName, new DeviceCreationInfo(true, true, ActivationMode.ActivateIfFirst) } }; INTV.Shared.Interop.DeviceManagement.DeviceChange.ReportDeviceAdded(data, portName, Core.Model.Device.ConnectionType.Serial, creationInfo); data.Task.CancelTask(); } else { validPorts.Add(portName); } } } catch (UnauthorizedAccessException) { // Access is denied to the port or the current process, or another process on the system, // already has the specified COM port open either by a SerialPort instance or in unmanaged code. if (errorLogger != null) { errorLogger.Log("CheckForDevices: UnauthorizedAccessException on port " + portName); } maxRetries = RetryCount; System.Threading.Thread.Sleep(500); } catch (ArgumentOutOfRangeException) { // One or more of the properties for this instance are invalid. For example, the Parity, DataBits, // or Handshake properties are not valid values; the BaudRate is less than or equal to zero; the // ReadTimeout or WriteTimeout property is less than zero and is not InfiniteTimeout. if (errorLogger != null) { errorLogger.Log("CheckForDevices: ArgumentOutOfRangeException on port " + portName); } } catch (ArgumentException) { // The port name does not begin with "COM", or the file type of the port is not supported. if (errorLogger != null) { errorLogger.Log("CheckForDevices: ArgumentException on port " + portName); } } catch (System.IO.IOException) { // The port is in an invalid state, or an attempt to set the state of the underlying port failed. // For example, the parameters passed from this SerialPort object were invalid. if (errorLogger != null) { errorLogger.Log("CheckForDevices: IOException on port " + portName); } } catch (InvalidOperationException) { // The specified port on the current instance of the SerialPort is already open. if (errorLogger != null) { errorLogger.Log("CheckForDevices: InvalidOperationException on port " + portName); } } catch (Exception e) { // Caught some unexpected exception. if (errorLogger != null) { errorLogger.Log("CheckForDevices: Exception on port " + portName + " with message: " + e.Message); } throw; } } } if (data.CancelRequsted) { validPorts.Clear(); } }