private static async Task PerformFirmwareUpdate() { // Notify clients that we are now installing a firmware update using (await Model.Provider.AccessReadWriteAsync()) { Model.Provider.Get.State.Status = MachineStatus.Updating; } // Get the CRC16 checksum of the firmware binary byte[] firmwareBlob = new byte[_firmwareStream.Length]; await _firmwareStream.ReadAsync(firmwareBlob, 0, (int)_firmwareStream.Length); ushort crc16 = CRC16.Calculate(firmwareBlob); // Send the IAP binary to the firmware Console.Write("[info] Flashing IAP binary"); bool dataSent; do { dataSent = DataTransfer.WriteIapSegment(_iapStream); DataTransfer.PerformFullTransfer(); Console.Write('.'); }while (dataSent); Console.WriteLine(); _iapStream.Close(); _iapStream = null; // Start the IAP binary DataTransfer.StartIap(); // Send the firmware binary to the IAP program int numRetries = 0; do { if (numRetries != 0) { Console.WriteLine("Error"); } Console.Write("[info] Flashing RepRapFirmware"); _firmwareStream.Seek(0, SeekOrigin.Begin); while (DataTransfer.FlashFirmwareSegment(_firmwareStream)) { Console.Write('.'); } Console.WriteLine(); Console.Write("[info] Verifying checksum... "); }while (++numRetries < 3 && !DataTransfer.VerifyFirmwareChecksum(_firmwareStream.Length, crc16)); if (numRetries == 3) { Console.WriteLine("Error"); // Failed to flash the firmware await Utility.Logger.LogOutput(MessageType.Error, "Could not flash the firmware binary after 3 attempts. Please install it manually via bossac."); Program.CancelSource.Cancel(); } else { Console.WriteLine("OK"); // Wait for the IAP binary to restart the controller DataTransfer.WaitForIapReset(); Console.WriteLine("[info] Firmware update successful!"); } _firmwareStream.Close(); _firmwareStream = null; using (_firmwareUpdateLock.Lock()) { _firmwareUpdateRequest.SetResult(null); _firmwareUpdateRequest = null; } }
/// <summary> /// Perform a full data transfer synchronously /// </summary> /// <param name="mustSucceed">Keep retrying until the transfer succeeds</param> /// <returns>Whether new data could be transferred</returns> public static bool PerformFullTransfer(bool mustSucceed = true) { _lastTransferNumber = _rxHeader.SequenceNumber; // Reset RX transfer header _rxHeader.FormatCode = Communication.Consts.InvalidFormatCode; _rxHeader.NumPackets = 0; _rxHeader.ProtocolVersion = 0; _rxHeader.DataLength = 0; _rxHeader.ChecksumData = 0; _rxHeader.ChecksumHeader = 0; // Set up TX transfer header _txHeader.NumPackets = _packetId; _txHeader.SequenceNumber++; _txHeader.DataLength = (ushort)_txPointer; _txHeader.ChecksumData = CRC16.Calculate(_txBuffers[_txBufferIndex].Slice(0, _txPointer).Span); MemoryMarshal.Write(_txHeaderBuffer.Span, ref _txHeader); _txHeader.ChecksumHeader = CRC16.Calculate(_txHeaderBuffer.Slice(0, Marshal.SizeOf(_txHeader) - Marshal.SizeOf(typeof(ushort))).Span); MemoryMarshal.Write(_txHeaderBuffer.Span, ref _txHeader); do { try { // Exchange transfer headers. This also deals with transfer responses if (!ExchangeHeader()) { continue; } // Exchange data if there is anything to transfer if ((_rxHeader.DataLength != 0 || _txPointer != 0) && !ExchangeData()) { continue; } // Deal with timeouts if (_hadTimeout) { using (Model.Provider.AccessReadWrite()) { if (Model.Provider.Get.State.Status == MachineStatus.Off) { Model.Provider.Get.State.Status = MachineStatus.Idle; } Model.Provider.Get.Messages.Add(new Message(MessageType.Success, "Connection to Duet established")); Console.WriteLine("[info] Connection to Duet established"); } _hadTimeout = _resetting = false; } // Deal with the first transmission if (!_started) { _lastTransferNumber = (ushort)(_rxHeader.SequenceNumber - 1); _started = true; } // Transfer OK Interlocked.Increment(ref _numMeasuredTransfers); _txBufferIndex = (_txBufferIndex == 0) ? 1 : 0; _rxPointer = _txPointer = 0; _packetId = 0; // Deal with reset requests if (_resetting) { _waitingForFirstTransfer = _hadTimeout = true; return(PerformFullTransfer(mustSucceed)); } return(true); } catch (OperationCanceledException e) { if (!Program.CancelSource.IsCancellationRequested && !_hadTimeout && _started) { // If this is the first unexpected timeout event, report it unless the firmware is being updated using (Model.Provider.AccessReadWrite()) { if (Model.Provider.Get.State.Status == MachineStatus.Updating) { _waitingForFirstTransfer = _hadTimeout = true; Model.Provider.Get.State.Status = MachineStatus.Off; Model.Provider.Get.Messages.Add(new Message(MessageType.Warning, $"Lost connection to Duet ({e.Message})")); Console.WriteLine($"[warn] Lost connection to Duet ({e.Message})"); } } } } } while (mustSucceed && !Program.CancelSource.IsCancellationRequested); return(false); }
/// <summary> /// Perform the firmware update internally /// </summary> /// <returns>Asynchronous task</returns> private static async Task PerformFirmwareUpdate() { using (await Model.Provider.AccessReadWriteAsync()) { Model.Provider.Get.State.Status = MachineStatus.Updating; } DataTransfer.Updating = true; try { // Get the CRC16 checksum of the firmware binary byte[] firmwareBlob = new byte[_firmwareStream.Length]; await _firmwareStream.ReadAsync(firmwareBlob, 0, (int)_firmwareStream.Length); ushort crc16 = CRC16.Calculate(firmwareBlob); // Send the IAP binary to the firmware _logger.Info("Flashing IAP binary"); bool dataSent; do { dataSent = DataTransfer.WriteIapSegment(_iapStream); DataTransfer.PerformFullTransfer(); if (_logger.IsDebugEnabled) { Console.Write('.'); } }while (dataSent); if (_logger.IsDebugEnabled) { Console.WriteLine(); } // Start the IAP binary DataTransfer.StartIap(); // Send the firmware binary to the IAP program int numRetries = 0; do { if (numRetries != 0) { _logger.Error("Firmware checksum verification failed"); } _logger.Info("Flashing RepRapFirmware"); _firmwareStream.Seek(0, SeekOrigin.Begin); while (DataTransfer.FlashFirmwareSegment(_firmwareStream)) { if (_logger.IsDebugEnabled) { Console.Write('.'); } } if (_logger.IsDebugEnabled) { Console.WriteLine(); } _logger.Info("Verifying checksum"); }while (++numRetries < 3 && !DataTransfer.VerifyFirmwareChecksum(_firmwareStream.Length, crc16)); if (numRetries == 3) { // Failed to flash the firmware await Logger.LogOutput(MessageType.Error, "Could not flash the firmware binary after 3 attempts. Please install it manually via bossac."); Program.CancelSource.Cancel(); } else { // Wait for the IAP binary to restart the controller await DataTransfer.WaitForIapReset(); _logger.Info("Firmware update successful"); } } finally { DataTransfer.Updating = false; // Machine state is reset when the next status response is processed } }