/// <summary> /// Initialize physical transfer and perform initial data transfer. /// This is only called once on initialization /// </summary> /// <returns>Asynchronous task</returns> public static bool Connect() => DataTransfer.PerformFullTransfer(false);
/// <summary> /// Perform communication with the RepRapFirmware controller /// </summary> /// <returns>Asynchronous task</returns> public static async Task Run() { do { // Check if an emergency stop has been requested if (_emergencyStopRequested && DataTransfer.WriteEmergencyStop()) { _emergencyStopRequested = false; Console.WriteLine("[info] Emergency stop"); DataTransfer.PerformFullTransfer(); } // Check if a firmware reset has been requested if (_resetRequested && DataTransfer.WriteReset()) { _resetRequested = false; Console.WriteLine("[info] Resetting controller"); DataTransfer.PerformFullTransfer(); } // Check if a firmware update is supposed to be performed if (_iapStream != null && _firmwareStream != null) { await Invalidate("Firmware update imminent"); await PerformFirmwareUpdate(); if (Program.UpdateOnly) { // Stop after installing the firmware update break; } } // Invalidate data if a controller reset has been performed if (DataTransfer.HadReset()) { _emergencyStopRequested = _resetRequested = false; await Invalidate("Controller has been reset"); } // Check for changes of the print status. // The packet providing file info has be sent first because it includes a time_t value that must reside on a 64-bit boundary! if (_printStarted) { using (Model.Provider.AccessReadOnly()) { _printStarted = !DataTransfer.WritePrintStarted(Model.Provider.Get.Job.File); } } else if (_printStoppedReason.HasValue && DataTransfer.WritePrintStopped(_printStoppedReason.Value)) { _printStoppedReason = null; } // Deal with heightmap requests using (await _heightmapLock.LockAsync()) { // Check if the heightmap is supposed to be set if (_setHeightmapRequest != null && DataTransfer.WriteHeightMap(_heightmapToSet)) { _setHeightmapRequest.SetResult(null); _setHeightmapRequest = null; } // Check if the heightmap is requested if (_getHeightmapRequest != null && !_isHeightmapRequested) { _isHeightmapRequested = DataTransfer.WriteGetHeightMap(); } } // Process incoming packets for (int i = 0; i < DataTransfer.PacketsToRead; i++) { PacketHeader?packet; try { packet = DataTransfer.ReadPacket(); if (!packet.HasValue) { Console.WriteLine("[err] Read invalid packet"); break; } await ProcessPacket(packet.Value); } catch (ArgumentOutOfRangeException) { DataTransfer.DumpMalformedPacket(); throw; } } _bytesReserved = 0; // Process pending codes, macro files and requests for resource locks/unlocks as well as flush requests bool dataProcessed; do { dataProcessed = false; foreach (ChannelInformation channel in _channels) { using (channel.Lock()) { if (!channel.IsBlocked) { if (channel.ProcessRequests()) { // Something could be processed dataProcessed = true; } else { // Cannot do any more on this channel channel.IsBlocked = true; } } } } }while (dataProcessed); // Request object model updates if (DateTime.Now - _lastQueryTime > TimeSpan.FromMilliseconds(Settings.ModelUpdateInterval)) { DataTransfer.WriteGetObjectModel(_moduleToQuery); _lastQueryTime = DateTime.Now; } // Update filament assignment per extruder drive lock (_extruderFilamentUpdates) { if (_extruderFilamentUpdates.TryPeek(out Tuple <int, string> filamentMapping) && DataTransfer.WriteAssignFilament(filamentMapping.Item1, filamentMapping.Item2)) { _extruderFilamentUpdates.Dequeue(); } } // Do another full SPI transfer DataTransfer.PerformFullTransfer(); _channels.ResetBlockedChannels(); // Wait a moment await Task.Delay(Settings.SpiPollDelay, Program.CancelSource.Token); }while (!Program.CancelSource.IsCancellationRequested); }
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 communication with the RepRapFirmware controller /// </summary> /// <returns>Asynchronous task</returns> public static async Task Run() { do { // Check if an emergency stop has been requested if (_emergencyStopRequested && DataTransfer.WriteEmergencyStop()) { _emergencyStopRequested = false; Console.WriteLine("[info] Emergency stop"); DataTransfer.PerformFullTransfer(); } // Check if a firmware reset has been requested if (_resetRequested && DataTransfer.WriteReset()) { _resetRequested = false; Console.WriteLine("[info] Resetting controller"); DataTransfer.PerformFullTransfer(); } // Check if a firmware update is supposed to be performed if (_iapStream != null && _firmwareStream != null) { await InvalidateData("Firmware update imminent"); await PerformFirmwareUpdate(); } // Invalidate data if a controller reset has been performed if (DataTransfer.HadReset()) { Console.WriteLine("[info] Controller has been reset"); await InvalidateData("Controller reset"); } // Check for changes of the print status. // The packet providing file info has be sent first because it includes a time_t value that must reside on a 64-bit boundary! if (_printStarted) { using (Model.Provider.AccessReadOnly()) { _printStarted = !DataTransfer.WritePrintStarted(Model.Provider.Get.Job.File); } } else if (_printStoppedReason.HasValue && DataTransfer.WritePrintStopped(_printStoppedReason.Value)) { _printStoppedReason = null; } // Deal with heightmap requests using (_heightmapLock.Lock()) { // Check if the heightmap is supposed to be set if (_heightmapToSet != null && DataTransfer.WriteHeightMap(_heightmapToSet)) { _heightmapToSet = null; _setHeightmapRequest.SetResult(null); _setHeightmapRequest = null; } // Check if the heightmap is requested if (_getHeightmapRequest != null && !_heightmapRequested) { _heightmapRequested = DataTransfer.WriteGetHeightMap(); } } // Process incoming packets DateTime startTime = DateTime.Now; for (int i = 0; i < DataTransfer.PacketsToRead; i++) { Communication.PacketHeader?packet; try { packet = DataTransfer.ReadPacket(); if (!packet.HasValue) { Console.WriteLine("[err] Read invalid packet"); break; } } catch (ArgumentOutOfRangeException) { DataTransfer.DumpMalformedPacket(); throw; } await ProcessPacket(packet.Value); if (DateTime.Now - startTime > TimeSpan.FromMilliseconds(250)) { Console.WriteLine($"WARN: Packet with request {packet?.Request} took longer than 250ms!"); } startTime = DateTime.Now; } _bytesReserved = 0; // Process pending codes, macro files and requests for resource locks/unlocks as well as flush requests bool dataProcessed; List <CodeChannel> blockedChannels = new List <CodeChannel>(); do { dataProcessed = false; foreach (CodeChannel channel in CodeChannels) { if (!blockedChannels.Contains(channel)) { using (Channels[channel].Lock()) { if (Channels[channel].ProcessRequests()) { // Something could be done on this channel dataProcessed = true; } else { // Don't call Process() again for this channel if it returned false before blockedChannels.Add(channel); } } } } } while (dataProcessed); if (DateTime.Now - startTime > TimeSpan.FromMilliseconds(250)) { Console.WriteLine("WARN: Channel processing took longer than 250ms!"); } startTime = DateTime.Now; // Request object model updates if (IsIdle || DateTime.Now - _lastQueryTime > TimeSpan.FromMilliseconds(Settings.MaxUpdateDelay)) { DataTransfer.WriteGetObjectModel(_moduleToQuery); _lastQueryTime = DateTime.Now; } if (DateTime.Now - startTime > TimeSpan.FromMilliseconds(250)) { Console.WriteLine("WARN: Object model processing took longer than 250ms!"); } startTime = DateTime.Now; // Do another full SPI transfer DataTransfer.PerformFullTransfer(); if (DateTime.Now - startTime > TimeSpan.FromMilliseconds(250)) { Console.WriteLine("WARN: SPI transfer took longer than 250ms!"); } // Wait a moment if (IsIdle) { await Task.Delay(Settings.SpiPollDelay, Program.CancelSource.Token); } } while (!Program.CancelSource.IsCancellationRequested); }
/// <summary> /// Perform communication with the RepRapFirmware controller /// </summary> /// <returns>Asynchronous task</returns> public static async Task Run() { if (Settings.NoSpiTask) { await Task.Delay(-1, Program.CancellationToken); return; } do { using (await _firmwareActionLock.LockAsync(Program.CancellationToken)) { // Check if an emergency stop has been requested if (_firmwareHaltRequest != null && DataTransfer.WriteEmergencyStop()) { _logger.Warn("Emergency stop"); DataTransfer.PerformFullTransfer(); _firmwareHaltRequest.SetResult(null); _firmwareHaltRequest = null; } // Check if a firmware reset has been requested if (_firmwareResetRequest != null && DataTransfer.WriteReset()) { _logger.Warn("Resetting controller"); DataTransfer.PerformFullTransfer(); _firmwareResetRequest.SetResult(null); _firmwareResetRequest = null; if (!Settings.NoTerminateOnReset) { // Wait for the program to terminate and don't perform any extra transfers await Task.Delay(-1, Program.CancellationToken); } } } // Check if a firmware update is supposed to be performed using (await _firmwareUpdateLock.LockAsync(Program.CancellationToken)) { if (_iapStream != null && _firmwareStream != null) { await Invalidate("Firmware update imminent"); try { await PerformFirmwareUpdate(); _firmwareUpdateRequest?.SetResult(null); _firmwareUpdateRequest = null; } catch (Exception e) { _firmwareUpdateRequest?.SetException(e); _firmwareUpdateRequest = null; if (e is OperationCanceledException) { _logger.Debug(e, "Firmware update cancelled"); } else { throw; } } _iapStream = _firmwareStream = null; } } // Invalidate data if a controller reset has been performed if (DataTransfer.HadReset()) { await Invalidate("Controller has been reset"); } // Check for changes of the print status. // The packet providing file info has be sent first because it includes a time_t value that must reside on a 64-bit boundary! if (_printStarted) { using (await Model.Provider.AccessReadOnlyAsync()) { _printStarted = !DataTransfer.WritePrintStarted(Model.Provider.Get.Job.File); } } else { using (await _printStopppedReasonLock.LockAsync(Program.CancellationToken)) { if (_printStoppedReason != null && DataTransfer.WritePrintStopped(_printStoppedReason.Value)) { _printStoppedReason = null; } } } // Deal with heightmap requests using (await _heightmapLock.LockAsync(Program.CancellationToken)) { // Check if the heightmap is supposed to be set if (_setHeightmapRequest != null && DataTransfer.WriteHeightMap(_heightmapToSet)) { _setHeightmapRequest.SetResult(null); _setHeightmapRequest = null; } // Check if the heightmap is requested if (_getHeightmapRequest != null && !_isHeightmapRequested) { _isHeightmapRequested = DataTransfer.WriteGetHeightMap(); } } // Process incoming packets for (int i = 0; i < DataTransfer.PacketsToRead; i++) { PacketHeader?packet; try { packet = DataTransfer.ReadPacket(); if (packet == null) { _logger.Error("Read invalid packet"); break; } await ProcessPacket(packet.Value); } catch (ArgumentOutOfRangeException) { DataTransfer.DumpMalformedPacket(); throw; } } _bytesReserved = 0; // Process pending codes, macro files and requests for resource locks/unlocks as well as flush requests await _channels.Run(); // Request object model updates if (DateTime.Now - _lastQueryTime > TimeSpan.FromMilliseconds(Settings.ModelUpdateInterval)) { if (DataTransfer.ProtocolVersion == 1) { using (await Model.Provider.AccessReadOnlyAsync()) { if (Model.Provider.Get.Boards.Count == 0 && DataTransfer.WriteGetLegacyConfigResponse()) { // We no longer support regular status responses except to obtain the board name for updating the firmware _lastQueryTime = DateTime.Now; } } } else { bool objectModelQueried = false; lock (_pendingModelQueries) { // Query specific object model values on demand if (_pendingModelQueries.TryPeek(out Tuple <string, string> modelQuery) && DataTransfer.WriteGetObjectModel(modelQuery.Item1, modelQuery.Item2)) { objectModelQueried = true; _pendingModelQueries.Dequeue(); } } if (!objectModelQueried && DataTransfer.WriteGetObjectModel(string.Empty, "d99fn")) { // Query live values in regular intervals _lastQueryTime = DateTime.Now; } } } // Ask for expressions to be evaluated lock (_evaluateExpressionRequests) { int numEvaluationsSent = 0; foreach (EvaluateExpressionRequest request in _evaluateExpressionRequests) { if (!request.Written) { if (DataTransfer.WriteEvaluateExpression(request.Channel, request.Expression)) { request.Written = true; numEvaluationsSent++; if (numEvaluationsSent >= Consts.MaxEvaluationRequestsPerTransfer) { break; } } } } } // Send pending messages lock (_messagesToSend) { while (_messagesToSend.TryPeek(out Tuple <MessageTypeFlags, string> message)) { if (DataTransfer.WriteMessage(message.Item1, message.Item2)) { _messagesToSend.Dequeue(); } else { break; } } } // Update filament assignment per extruder drive. This must happen when config.g has finished or M701 is requested if (!Macro.RunningConfig || _assignFilaments) { lock (_extruderFilamentUpdates) { while (_extruderFilamentUpdates.TryPeek(out Tuple <int, string> filamentMapping)) { if (DataTransfer.WriteAssignFilament(filamentMapping.Item1, filamentMapping.Item2)) { _extruderFilamentUpdates.Dequeue(); } else { break; } } } _assignFilaments = false; } // Do another full SPI transfe DataTransfer.PerformFullTransfer(); _channels.ResetBlockedChannels(); // Wait a moment unless instructions are being sent rapidly to RRF bool skipDelay; using (await Model.Provider.AccessReadOnlyAsync()) { skipDelay = Model.Provider.Get.State.Status == MachineStatus.Updating; } if (!skipDelay) { await Task.Delay(Settings.SpiPollDelay, Program.CancellationToken); } }while (true); }
/// <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 } }
/// <summary> /// Initialize physical transfer and perform initial data transfer. /// This is only called once on initialization /// </summary> /// <returns>Asynchronous task</returns> public static Task <bool> Connect() => DataTransfer.PerformFullTransfer(false);