/// <summary> /// Attempt to start a file macro /// </summary> /// <param name="filename">Name of the macro file</param> /// <param name="reportMissing">Report an error if the file could not be found</param> /// <param name="fromCode">Request comes from a real G/M/T-code</param> /// <returns>Asynchronous task</returns> public async Task HandleMacroRequest(string filename, bool reportMissing, bool fromCode) { // Get the code starting the macro file QueuedCode startingCode = null; if (fromCode) { if (NestedMacros.TryPeek(out MacroFile macroFile) && macroFile.StartCode != null && !macroFile.StartCode.DoingNestedMacro) { // In case a G/M/T-code invokes more than one macro file... startingCode = macroFile.StartCode; // Check if the other macro file has been finished if (macroFile.IsFinished) { NestedMacros.Pop().Dispose(); _logger.Info("Finished intermediate macro file {0}", Path.GetFileName(macroFile.FileName)); } } else if (BufferedCodes.Count > 0) { // The top buffered code is the one that requested the macro file startingCode = BufferedCodes[0]; } if (startingCode != null) { startingCode.DoingNestedMacro = true; // FIXME This work-around will not be needed any more when the SBC interface has got its own task in RRF if ((filename == "stop.g" || filename == "sleep.g") && startingCode.Code.CancellingPrint) { string cancelFile = await FilePath.ToPhysicalAsync("cancel.g", FileDirectory.System); if (File.Exists(cancelFile)) { // Execute cancel.g instead of stop.g if it exists filename = "cancel.g"; } } } }
/// <summary> /// Handle a G-code reply /// </summary> /// <param name="flags">Message flags</param> /// <param name="reply">Code reply</param> /// <returns>Whether the reply could be processed</returns> public bool HandleReply(MessageTypeFlags flags, string reply) { if (flags.HasFlag(MessageTypeFlags.LogMessage)) { _partialLogMessage += reply; if (!flags.HasFlag(MessageTypeFlags.PushFlag)) { if (!string.IsNullOrWhiteSpace(_partialLogMessage)) { MessageType type = flags.HasFlag(MessageTypeFlags.ErrorMessageFlag) ? MessageType.Error : flags.HasFlag(MessageTypeFlags.WarningMessageFlag) ? MessageType.Warning : MessageType.Success; Utility.Logger.Log(type, _partialLogMessage); } _partialLogMessage = null; } } if (SystemMacroHadError) { SystemMacroHadError = false; return(true); } if (NestedMacros.TryPeek(out MacroFile macroFile)) { if ((macroFile.StartCode != null && !macroFile.StartCode.DoingNestedMacro) || (macroFile.StartCode == null && SystemMacroHasFinished)) { if (macroFile.StartCode != null) { macroFile.StartCode.HandleReply(flags, reply); if (macroFile.IsFinished) { NestedMacros.Pop().Dispose(); _logger.Info("Finished macro file {0}", Path.GetFileName(macroFile.FileName)); if (macroFile.StartCode != null) { _logger.Debug("==> Starting code: {0}", macroFile.StartCode); } } } else if (!flags.HasFlag(MessageTypeFlags.PushFlag)) { NestedMacros.Pop().Dispose(); SystemMacroHasFinished = false; _logger.Info("Finished system macro file {0}", Path.GetFileName(macroFile.FileName)); } return(true); } if (macroFile.StartCode != null) { macroFile.StartCode.HandleReply(flags, reply); } } if (BufferedCodes.Count > 0) { BufferedCodes[0].HandleReply(flags, reply); if (BufferedCodes[0].IsFinished) { BytesBuffered -= BufferedCodes[0].BinarySize; BufferedCodes.RemoveAt(0); } return(true); } // Replies from the code queue or a final empty response from the file are expected if (Channel != CodeChannel.CodeQueue && Channel != CodeChannel.File) { _logger.Warn("Out-of-order reply: '{0}'", reply); } return(false); }