/// <summary> /// Asynchronously updates the firmware of the Harp device on the specified port. /// </summary> /// <param name="portName">The name of the serial port used to communicate with the Harp device.</param> /// <param name="firmware">The binary firmware image to upload to the device.</param> /// <param name="forceUpdate"> /// <b>true</b> to indicate that the firmware should be uploaded even if the device reports unsupported hardware, /// or is in bootloader mode; <b>false</b> to throw an exception if the firmware is not supported, or the device /// is in an invalid state. /// </param> /// <param name="progress">The optional <see cref="IProgress{Int32}"/> object used to report update progress.</param> /// <returns> /// The task object representing the asynchronous firmware update operation. /// </returns> public static async Task UpdateFirmwareAsync(string portName, DeviceFirmware firmware, bool forceUpdate, IProgress <int> progress = default) { var flushDelay = TimeSpan.FromMilliseconds(FlushDelayMilliseconds); using (var device = new AsyncDevice(portName)) { try { var hardwareVersion = await device.ReadHardwareVersionAsync().WithTimeout(FlushDelayMilliseconds); var deviceName = await device.ReadDeviceNameAsync().WithTimeout(FlushDelayMilliseconds); if (!firmware.Metadata.Supports(deviceName, hardwareVersion) && !forceUpdate) { throw new ArgumentException("The specified firmware is not supported.", nameof(firmware)); } const byte BootEeprom = 0x80; const byte BootDefault = 0x40; const byte ResetDefault = 0x1; const byte ResetEeprom = 0x2; var reset = await device.ReadByteAsync(Registers.Reset); if ((reset & BootEeprom) != 0) { await device.WriteByteAsync(Registers.Reset, ResetEeprom); } else if ((reset & BootDefault) != 0) { await device.WriteByteAsync(Registers.Reset, ResetDefault); } else { throw new HarpException("The device is in an unexpected boot mode."); } await Observable.Timer(flushDelay); progress?.Report(20); } catch (TimeoutException) { if (!forceUpdate) { throw; } } } const int DefaultBaudRate = 1000000; using (var bootloader = new SerialPort(portName, DefaultBaudRate, Parity.None, 8, StopBits.One)) { bootloader.Handshake = Handshake.None; bootloader.Open(); await Observable.Timer(flushDelay); var pageSize = await ReadPageSizeAsync(bootloader.BaseStream); progress?.Report(40); var bytesWritten = 0; var reportSize = pageSize * 8; var dataMessage = new byte[pageSize + HeaderSize]; while (bytesWritten < firmware.Data.Length) { CreateBootloaderMessage(dataMessage, WritePage, bytesWritten, firmware.Data, bytesWritten, pageSize); await BootloaderCommandAsync(bootloader.BaseStream, dataMessage); bytesWritten += pageSize; if (bytesWritten % reportSize == 0) { progress?.Report(40 + bytesWritten * 50 / firmware.Data.Length); } } progress?.Report(90); CreateBootloaderMessage(dataMessage, ExitBootloader, 0, firmware.Data, 0, pageSize); await BootloaderCommandAsync(bootloader.BaseStream, dataMessage); progress?.Report(100); }; }
/// <summary> /// Asynchronously updates the firmware of the Harp device on the specified port. /// </summary> /// <param name="portName">The name of the serial port used to communicate with the Harp device.</param> /// <param name="firmware">The binary firmware image to upload to the device.</param> /// <param name="progress">The optional <see cref="IProgress{Int32}"/> object used to report update progress.</param> /// <returns> /// The task object representing the asynchronous firmware update operation. /// </returns> public static Task UpdateFirmwareAsync(string portName, DeviceFirmware firmware, IProgress <int> progress = default) { return(UpdateFirmwareAsync(portName, firmware, forceUpdate: false, progress: progress)); }