public async Task Run_Should_Output_Code_Results_When_Valid() { // arrange var input = "test code"; var output = "test output"; var result = new CodeResult { Output = output, State = OutputState.Valid, Variables = Enumerable.Range(1, 2).Select(i => $"test-var-{i}").ToList(), }; var console = new Mock <IConsole>(); var expectedColPosition = 3; console .Setup(c => c.CursorLeft) .Returns(expectedColPosition); var expectedRowPosition = 6; console .Setup(c => c.CursorTop) .Returns(expectedRowPosition); var keyHandler = new Mock <IConsoleKeyHandler>(); var consoleWriter = new Mock <IConsoleWriter>(); var replEngine = new Mock <IReplEngine>(); var loop = new Mock <ILoop>(); var consoleState = new Mock <IConsoleState>(); keyHandler .Setup(c => c.Process(consoleState.Object)) .Returns(input); replEngine .Setup(r => r.Execute(input)) .ReturnsAsync(result); loop .SetupSequence(l => l.Continue()) .Returns(true) .Returns(false); var interactiveLoop = new InteractiveLoop(console.Object, keyHandler.Object, consoleWriter.Object, replEngine.Object, loop.Object, consoleState.Object); // act await interactiveLoop.Run(); // assert consoleState.VerifySet(c => c.ColPosition = expectedColPosition); consoleState.VerifySet(c => c.RowPosition = expectedRowPosition); consoleWriter.Verify(c => c.WriteOutput(output), Times.Once); consoleWriter.Verify(c => c.WriteError(output), Times.Never); consoleState.Verify(c => c.CompleteInput(result.Variables)); }
private async Task <CodeResult> ExecuteInternally() { CodeResult result = null; // Preprocess this code if (!Flags.HasFlag(CodeFlags.IsPreProcessed)) { result = await Interception.Intercept(this, InterceptionMode.Pre); Flags |= CodeFlags.IsPreProcessed; if (result != null) { InternallyExecuted = true; return(await OnCodeExecuted(result)); } } // Attempt to process the code internally switch (Type) { case CodeType.GCode: result = await GCodes.Process(this); break; case CodeType.MCode: result = await MCodes.Process(this); break; case CodeType.TCode: result = await TCodes.Process(this); break; } if (result != null) { InternallyExecuted = true; return(await OnCodeExecuted(result)); } // If the could not be interpreted, post-process it if (!Flags.HasFlag(CodeFlags.IsPostProcessed)) { result = await Interception.Intercept(this, InterceptionMode.Post); Flags |= CodeFlags.IsPostProcessed; if (result != null) { InternallyExecuted = true; return(await OnCodeExecuted(result)); } } // Code has not been interpreted yet return(null); }
public async Task Execute_Should_Continue_When_Not_Complete() { // arrange var codeLines = new List <string> { "var ", "foo =\"bar\";", "foo", }; var inputCheck = new Mock <IInputCheck>(); var scriptOptionsBuilder = new Mock <IScriptOptionsBuilder>(); var engine = new ReplEngine(inputCheck.Object, scriptOptionsBuilder.Object); var builder = new StringBuilder(); var codeResult = new CodeResult(); // act foreach (var line in codeLines) { builder.AppendLine(line); codeResult = await engine.Execute(builder.ToString()); } // assert Assert.That(codeResult.Output, Is.EqualTo("bar")); Assert.That(codeResult.State, Is.EqualTo(OutputState.Valid)); }
public static Cell Eval(Cell code, CodeResult cr, SchemeEnvironment env) { List <Cell> args = new List <Cell>(); args.Add(code); args.Add(new Cell(env)); Machine machine = new Machine(cr, args); try { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); while (machine.Finished == false) { machine.Step(); } StepsExecuted += machine.Steps; sw.Stop(); Console.WriteLine("!Eval ran in {0}", sw.Elapsed); } catch (Exception e) { Debug.WriteLine("Eval failed: {0}", e.Message); } return(machine.A); }
public CodeResult LogOut() { var jtiClaims = User.Claims.FirstOrDefault(item => item.Type == JwtRegisteredClaimNames.Jti); _cache.Set(jtiClaims.Value, jtiClaims.Value, TimeSpan.FromHours(2)); // 将token唯一标识存入缓存中, 用于判断当前Token已注销,即使token在有效期内 return(CodeResult.Success()); }
/// <summary> /// Log and output a code result /// </summary> /// <param name="result">Code result</param> /// <returns>Asynchronous task</returns> public static async Task LogOutput(CodeResult result) { if (result != null) { foreach (Message msg in result) { await LogOutput(msg); } } }
/// <summary> /// Write messages including timestamp to the log file /// </summary> /// <param name="result">Message list</param> public static async Task Log(CodeResult result) { if (result != null) { foreach (Message msg in result) { LogLevel level = (msg.Type == MessageType.Success) ? LogLevel.Info : LogLevel.Warn; await Log(level, msg); } } }
public static CodeResult GetCodeResult(string filepath, string entry = "main") { filepath = Program.GetFilePath(filepath); if (!codeCache.ContainsKey(filepath)) { string code = System.IO.File.ReadAllText(filepath); CellMachineAssembler assembler = new CellMachineAssembler(code, entry); CodeResult cr = CellMachineAssembler.Assemble(code, entry); codeCache.Add(filepath, cr); } return(codeCache[filepath]); }
/// <summary> /// Print the diagnostics /// </summary> /// <param name="result">Target to write to</param> /// <returns>Asynchronous task</returns> private static async Task Diagnostics(CodeResult result) { StringBuilder builder = new StringBuilder(); builder.AppendLine("=== Duet Control Server ==="); builder.AppendLine($"Duet Control Server v{Assembly.GetExecutingAssembly().GetName().Version}"); await SPI.Interface.Diagnostics(builder); SPI.DataTransfer.Diagnostics(builder); await Print.Diagnostics(builder); result.Add(MessageType.Success, builder.ToString().TrimEnd()); }
public override Cell Eval(Cell Arg, SchemeEnvironment Env) { CodeResult cr = GetCodeResult("Eval.asm"); Machine machine = new Machine(cr, new Cell[] { Arg, new Cell(Env) }); machine.DebugMode = useDebug; while (machine.Finished == false) { machine.Step(); } stepCounter += machine.Steps; return(Result = machine.A); }
/// <summary> /// Print the diagnostics /// </summary> /// <param name="result">Target to write to</param> /// <returns>Asynchronous task</returns> private static async Task Diagnostics(CodeResult result) { StringBuilder builder = new StringBuilder(); builder.AppendLine("=== Duet Control Server ==="); builder.AppendLine($"Duet Control Server v{Program.Version}"); await SPI.Interface.Diagnostics(builder); SPI.DataTransfer.Diagnostics(builder); await FileExecution.Job.Diagnostics(builder); result.Add(MessageType.Success, builder.ToString().TrimEnd()); }
public async Task Run_Should_Output_Error_Message_From_Result_When_Error_State() { // arrange var input = "test invalid code"; var output = "error output"; var result = new CodeResult { Output = output, State = OutputState.Error, Variables = Enumerable.Range(1, 3).Select(i => $"test-var-{i}").ToList(), }; var console = new Mock <IConsole>(); var keyHandler = new Mock <IConsoleKeyHandler>(); var consoleWriter = new Mock <IConsoleWriter>(); var replEngine = new Mock <IReplEngine>(); var loop = new Mock <ILoop>(); var consoleState = new Mock <IConsoleState>(); keyHandler .Setup(c => c.Process(consoleState.Object)) .Returns(input); replEngine .Setup(r => r.Execute(input)) .ReturnsAsync(result); loop .SetupSequence(l => l.Continue()) .Returns(true) .Returns(false); consoleState .Setup(c => c.Text) .Returns(new StringBuilder()); var interactiveLoop = new InteractiveLoop(console.Object, keyHandler.Object, consoleWriter.Object, replEngine.Object, loop.Object, consoleState.Object); // act await interactiveLoop.Run(); // assert consoleState.VerifySet(c => c.TextRowPosition = 1, Times.Never, "should not increment"); consoleWriter.Verify(c => c.WriteOutput(output), Times.Never); consoleWriter.Verify(c => c.WriteError(output), Times.Once); consoleState.Verify(c => c.CompleteInput(result.Variables)); }
private async Task <CodeResult> OnCodeExecuted(CodeResult result) { // Process code result switch (Type) { case CodeType.GCode: result = await GCodes.CodeExecuted(this, result); break; case CodeType.MCode: result = await MCodes.CodeExecuted(this, result); break; case CodeType.TCode: result = await TCodes.CodeExecuted(this, result); break; } // RepRapFirmware generally prefixes error messages with the code itself. // Do this only for error messages that come either from a print or from a macro if (result != null && (Flags.HasFlag(CodeFlags.IsFromMacro) || Channel == CodeChannel.File)) { foreach (Message msg in result) { if (msg.Type == MessageType.Error) { msg.Content = ToShortString() + ": " + msg.Content; } } } // Log warning+error replies if the code could be processed internally if (InternallyExecuted && !result.IsEmpty) { foreach (Message msg in result) { if (msg.Type != MessageType.Success || Channel == CodeChannel.File) { await Utility.Logger.Log(msg); } } } // Finished. Optionally an "Executed" interceptor could be called here, but that would only make sense if the code reply was included return(result); }
private static List <SearchResult> GetQuickFixesFromCodeResult(CodeResult codeResult, string filePath, bool findReferences, string searchFilter, bool exactMatch) { var foundSymbols = new List <SearchResult>(); if (!codeResult.Matches.TryGetValue("content", out IEnumerable <Hit> contentHitsEnum)) { return(foundSymbols); } List <Hit> contentHits = contentHitsEnum.ToList(); int lineOffsetWin = 0; int lineOffsetUnix = 0; int lineNumber = 0; foreach (string line in File.ReadLines(filePath)) { foreach (Hit hit in contentHits.OrderBy(h => h.CharOffset)) { // Hit.CharOffset is calculated based on end-of-lines of the file stored by the service which can be different from local file end-of-lines. // Try guessing what end-of-lines were used by the service and use the first match. if (hit.CharOffset >= lineOffsetUnix && hit.CharOffset < lineOffsetUnix + line.Length) { if (ConsiderMatchCandidate(filePath, findReferences, searchFilter, exactMatch, hit, lineNumber, lineOffsetUnix, line, foundSymbols)) { // Keep only a single match per line per hit - it is already clone enough continue; } } if (hit.CharOffset >= lineOffsetWin && hit.CharOffset < lineOffsetWin + line.Length) { ConsiderMatchCandidate(filePath, findReferences, searchFilter, exactMatch, hit, lineNumber, lineOffsetWin, line, foundSymbols); } } if (foundSymbols.Count >= contentHits.Count) { // Found matching symbols for all hits - can stop searching the file break; } lineOffsetWin += line.Length + 2; lineOffsetUnix += line.Length + 1; lineNumber++; } return(foundSymbols); }
private static unsafe CodeResult VirtualMachine__RunCodeHook(VirtualMachine *vm, OpCode *op, IntPtr a3, uint opLimit, IntPtr a5) { CodeResult result = VirtualMachine__RunCode(vm, op, a3, opLimit, a5); try { VirtualMachine__RunCodeCallback?.Invoke(vm, op, a3, opLimit, a5, result); } catch (Exception ex) { Trace.WriteLine($"Unhandled Exception in {nameof(Script)}.{nameof(VirtualMachine__RunCodeHook)}!"); Trace.WriteLine(ex.ToString()); } return(result); }
/// <summary> /// 获取支付二维码 /// </summary> /// <param name="orderModel"></param> /// <returns></returns> public CodeResult WXPayRequest(OrderInfoEntity orderModel) { CodeResult result = new CodeResult(); string parameterString = @"version=1.0&merid=26100794&mername=北京联友创新科技发展有限公司&merorderid=" + orderModel.OrderCode + "&paymoney=" + orderModel.TotalAmount + "&productname=" + "&productdesc=&userid=" + orderModel.UserId + "&username="******"&email=&phone=&extra=&custom="; string md5 = MD5Hash.GetMD5String(parameterString);//md5校验值 //发送支付请求 try { string url = ""; //微信支付 if (orderModel.PayType == 1) { url = ConfigHelper.GetAppConfigString("WXPayUrl") + @"?version=1.0&merid=26100794&mername=北京联友创新科技发展有限公司&merorderid=" + orderModel.OrderCode + "&paymoney=" + orderModel.TotalAmount + "&productname=" + "&productdesc=&userid=" + orderModel.UserId + "&username="******"&email=&phone=&extra=&custom=&md5=" + md5; } //支付宝支付 if (orderModel.PayType == 2) { url = ConfigHelper.GetAppConfigString("ZFBPayUrl") + @"?version=1.0&merid=26100794&mername=北京联友创新科技发展有限公司&merorderid=" + orderModel.OrderCode + "&paymoney=" + orderModel.TotalAmount + "&productname=" + "&productdesc=&userid=" + orderModel.UserId + "&username="******"&email=&phone=&extra=&custom=&md5=" + md5; } LogHelper.Info("url=" + url); result = HttpClientHelper.GetResponse <CodeResult>(url); } catch (Exception ex) { //LogHelper.WriteLog(typeof(WXPayBLL), "WXPayRequest", Engineer.ggg, orderModel, ex); LogHelper.WriteInfo(typeof(PayBll), ex.Message); } return(result); }
/// <summary> /// Called by the <see cref="Code"/> class to intercept a code. /// This method goes through each connected interception channel and notifies the clients. /// </summary> /// <param name="code">Code to intercept</param> /// <param name="type">Type of the interception</param> /// <returns>null if not intercepted and a CodeResult otherwise</returns> public static async Task <CodeResult> Intercept(Code code, InterceptionMode type) { foreach (var pair in _interceptors) { if (code.SourceConnection != pair.Key.Connection.Id && pair.Value == type) { CodeResult result = await pair.Key.Intercept(code); if (result != null) { return(result); } } } return(null); }
/// <summary> /// Start an arbitrary G/M/T-code and get the task that is resolved when RRF finishes its execution. /// This is an internal alternative to the <see cref="CodeFlags.Asynchronous"/> flag. /// </summary> /// <returns>Asynchronous task</returns> public Task <CodeResult> Enqueue() { CodeResult result = InternallyExecuted ? null : ExecuteInternally().Result; if (result != null) { return(Task.FromResult(result)); } if (Type != CodeType.Comment) { Task <CodeResult> codeTask = Interface.ProcessCode(this); return(codeTask.ContinueWith((task) => OnCodeExecuted(task.Result).Result)); } return(OnCodeExecuted(result)); }
/// <summary> /// Converts simple G/M/T-codes to a regular Code instances, executes them and returns the result as text /// </summary> /// <returns>G-code result as text</returns> public override async Task <string> Execute() { IList <Code> codes; Queue <Task <CodeResult> > codeTasks = new Queue <Task <CodeResult> >(); CodeResult result = new CodeResult(); try { codes = Commands.Code.ParseMultiple(Code); foreach (Code code in codes) { // M122 always goes to the Daemon channel so we (hopefully) get a low-latency response code.Channel = (code.Type == CodeType.MCode && code.MajorNumber == 122) ? DuetAPI.CodeChannel.Daemon : Channel; code.SourceConnection = SourceConnection; codeTasks.Enqueue(code.Enqueue()); } } catch (CodeParserException e) { return($"Error: {e.Message}]\n"); } while (codeTasks.TryDequeue(out Task <CodeResult> task)) { Code code = codes[0]; codes.RemoveAt(0); try { CodeResult codeResult = await task; if (codeResult != null && !codeResult.IsEmpty) { result.AddRange(codeResult); } } catch (AggregateException ae) { // FIXME: Should this terminate the code(s) being executed? Console.WriteLine($"[err] {code} -> {ae.InnerException.Message}"); } } return(result.ToString()); }
private static unsafe CodeResult VirtualMachine__RunCodeHook(VirtualMachine *vm, OpCode *op, IntPtr a3, uint opLimit, IntPtr a5) { //string value = vm->TryGetOpCodeFunctionName(op, out string name) ? name : null; //if (value != null) Trace.WriteLine($"[RunCode] {name} Start"); CodeResult result = VirtualMachine__RunCode(vm, op, a3, opLimit, a5); try { VirtualMachine__RunCodeCallback?.Invoke(vm, op, a3, opLimit, a5, result); //if (value != null) Trace.WriteLine($"[RunCode] {name} End"); } catch (Exception ex) { Trace.WriteLine($"Unhandled Exception in {nameof(Script)}.{nameof(VirtualMachine__RunCodeHook)}!"); Trace.WriteLine(ex.ToString()); } return(result); }
public void OnException(ExceptionContext context) { if (context.Exception is CodeException codeException) { context.Result = new ObjectResult( CodeResult.FromCodeException(codeException)); } else { context.Result = new ObjectResult( CodeResult.FromCode(DefaultExceptionCode, context.Exception.Message, context.Exception.Data)) { StatusCode = DefaultExceptionHttpStatusCode }; context.ExceptionHandled = true; } context.ExceptionHandled = true; }
/// <summary> /// React to an executed M-code before its result is returend /// </summary> /// <param name="code">Code processed by RepRapFirmware</param> /// <param name="result">Result that it generated</param> /// <returns>Result to output</returns> /// <remarks>This method shall be used only to update values that are time-critical. Others are supposed to be updated via the object model</remarks> public static async Task <CodeResult> CodeExecuted(Code code, CodeResult result) { if (!result.IsSuccessful) { return(result); } switch (code.MajorNumber) { // Resume print case 24: if (Print.IsPaused) { // Resume sending file instructions to the firmware Print.Resume(); } break; // Absolute extrusion case 82: using (await Model.Provider.AccessReadWriteAsync()) { Model.Provider.Get.Channels[code.Channel].RelativeExtrusion = false; } break; // Relative extrusion case 83: using (await Model.Provider.AccessReadWriteAsync()) { Model.Provider.Get.Channels[code.Channel].RelativeExtrusion = false; } break; // Diagnostics case 122: if (code.GetUnprecedentedString() != "DSF") { await Diagnostics(result); } break; } return(result); }
/// <summary> /// Converts a simple G/M/T-code to a regular Code instance, executes it and returns its result as text /// </summary> /// <returns>G-code result as text</returns> public override async Task <string> Execute() { Code code = new Code(Code) { Channel = Channel, SourceConnection = SourceConnection }; // Send diagnostics request always over the Daemon channel. // This way, diagnotics can be output even if a code is blocking everything else if (code.Type == CodeType.MCode && code.MajorNumber == 122) { code.Channel = DuetAPI.CodeChannel.Daemon; } CodeResult result = await code.Execute(); return((result != null) ? result.ToString() : ""); }
public void OnResultExecuting(ResultExecutingContext context) { if (context.Result is ObjectResult obj && obj.Value is not CodeResult) { if (IsSuccessCode(obj)) { context.Result = new ObjectResult(CodeResult.FromData(SuccessCode, SuccessMessage, obj.Value)) { StatusCode = obj.StatusCode }; } else { context.Result = new ObjectResult(CodeResult.FromData($"{obj.StatusCode}", obj.Value?.ToString(), obj.Value)) { StatusCode = obj.StatusCode }; } }
/// <summary> /// Run an arbitrary G/M/T-code and wait for it to finish /// </summary> /// <returns>Code result instance</returns> public override async Task <CodeResult> Execute() { // Attempt to process the code internally CodeResult result = InternallyExecuted ? null : await ExecuteInternally(); if (result != null) { return(result); } // Send it to RepRapFirmware unless it is a comment if (Type != CodeType.Comment) { if (Flags.HasFlag(CodeFlags.Asynchronous)) { // Enqueue the code for execution by RRF and return no result Task <CodeResult> codeTask = Interface.ProcessCode(this); _ = Task.Run(async() => { try { CodeResult res = await codeTask; res = await OnCodeExecuted(res); await Model.Provider.Output(res); } catch (AggregateException ae) { Console.WriteLine($"[err] {this} -> {ae.InnerException.Message}"); } }); return(null); } else { // Wait for the code to complete result = await Interface.ProcessCode(this); } } return(await OnCodeExecuted(result)); }
/// <summary> /// Converts simple G/M/T-codes to a regular Code instances, executes them and returns the result as text /// </summary> /// <returns>Code result as text</returns> /// <exception cref="OperationCanceledException">Code has been cancelled</exception> public override async Task <string> Execute() { CodeResult result = new CodeResult(); try { List <Code> codes = Commands.Code.ParseMultiple(Code); foreach (Code code in codes) { // M112, M122, and M999 always go to the Daemon channel so we (hopefully) get a low-latency response if (code.Type == CodeType.MCode && (code.MajorNumber == 112 || code.MajorNumber == 122 || code.MajorNumber == 999)) { code.Channel = DuetAPI.CodeChannel.Daemon; code.Flags |= CodeFlags.IsPrioritized; } else { code.Channel = Channel; } // Execute the code and append the result CodeResult codeResult = await code.Execute(); result.AddRange(codeResult); } } catch (CodeParserException e) { // Report parsing errors as an error message result = new CodeResult(DuetAPI.MessageType.Error, e.Message); } catch (OperationCanceledException) { // Report this code as cancelled result.Add(DuetAPI.MessageType.Error, "Code has been cancelled"); } return(result.ToString()); }
/// <summary> /// React to an executed T-code before its result is returend /// </summary> /// <param name="code">Code processed by RepRapFirmware</param> /// <param name="result">Result that it generated</param> /// <returns>Result to output</returns> public static async Task <CodeResult> CodeExecuted(Code code, CodeResult result) { if (!code.MajorNumber.HasValue || !result.IsSuccessful) { return(result); } // Set new tool number using (await Model.Provider.AccessReadWriteAsync()) { if (Model.Provider.Get.Tools.Any(tool => tool.Number == code.MajorNumber)) { // Make sure the chosen tool actually exists Model.Provider.Get.State.CurrentTool = code.MajorNumber.Value; } else { // Deselect the current tool if it does not exist Model.Provider.Get.State.CurrentTool = -1; } } return(result); }
private static async Task RunPrint() { BaseFile file = _file; // Process the job file Queue <Code> codes = new Queue <Code>(); Queue <Task <CodeResult> > codeTasks = new Queue <Task <CodeResult> >(); do { // Has the file been paused? If so, rewind to the pause position bool paused = false; using (await _lock.LockAsync()) { if (!file.IsFinished && IsPaused) { file.Position = _pausePosition; paused = true; } } // Wait for print to resume if (paused) { codes.Clear(); codeTasks.Clear(); await _resumeEvent.WaitAsync(Program.CancelSource.Token); } // Fill up the code buffer Code code; while (codeTasks.Count == 0 || codeTasks.Count < Settings.BufferedPrintCodes) { code = file.ReadCode(); if (code == null) { break; } // The trick here is that Code.Enqueue runs synchronously and returns a // task instance that completes when a code result is available... codes.Enqueue(code); codeTasks.Enqueue(code.Enqueue()); } // Is there anything to do? if (codes.TryDequeue(out code)) { // Keep track of the next file position so we know where to resume in case the print is paused while a macro is being performed if (codes.TryPeek(out Code nextCode)) { LastFilePosition = nextCode.FilePosition; } else { LastFilePosition = file.Position; } // Process the next code try { CodeResult result = await codeTasks.Dequeue(); await Utility.Logger.LogOutput(result); } catch (Exception e) { Console.WriteLine($"[err] {code} -> {e}"); } } else { // No more codes available - print must have finished break; } } while (!Program.CancelSource.IsCancellationRequested); Console.WriteLine("[info] DCS has finished printing"); // Update the last print filename using (await Model.Provider.AccessReadWriteAsync()) { Model.Provider.Get.Job.LastFileName = await FilePath.ToVirtualAsync(file.FileName); // FIXME: Add support for simulation } // Notify the controller that the print has stopped SPI.Communication.PrintStoppedReason stopReason = !file.IsAborted ? SPI.Communication.PrintStoppedReason.NormalCompletion : (IsPaused ? SPI.Communication.PrintStoppedReason.UserCancelled : SPI.Communication.PrintStoppedReason.Abort); SPI.Interface.SetPrintStopped(stopReason); // Invalidate the file being printed _file = null; LastFilePosition = null; }
/// <summary> /// React to an executed G-code before its result is returend /// </summary> /// <param name="code">Code processed by RepRapFirmware</param> /// <param name="result">Result that it generated</param> /// <returns>Result to output</returns> /// <remarks>This method shall be used only to update values that are time-critical. Others are supposed to be updated via the object model</remarks> public static async Task <CodeResult> CodeExecuted(Code code, CodeResult result) { if (!result.IsSuccessful) { return(result); } switch (code.MajorNumber) { // Rapid/Regular positioning case 0: case 1: CodeParameter feedrate = code.Parameter('F'); if (feedrate != null) { using (await Model.Provider.AccessReadWriteAsync()) { if (Model.Provider.Get.Channels[code.Channel].UsingInches) { Model.Provider.Get.Channels[code.Channel].Feedrate = feedrate / 25.4F; } else { Model.Provider.Get.Channels[code.Channel].Feedrate = feedrate; } } } break; // Use inches case 20: using (await Model.Provider.AccessReadWriteAsync()) { Model.Provider.Get.Channels[code.Channel].UsingInches = true; } break; // Use millimetres case 21: using (await Model.Provider.AccessReadWriteAsync()) { Model.Provider.Get.Channels[code.Channel].UsingInches = false; } break; // Save heightmap case 29: if (code.Parameter('S', 0) == 0) { string file = code.Parameter('P', "heightmap.csv"); try { Heightmap map = await SPI.Interface.GetHeightmap(); await map.Save(await FilePath.ToPhysicalAsync(file, "sys")); result.Add(DuetAPI.MessageType.Success, $"Height map saved to file {file}"); } catch (AggregateException ae) { result.Add(DuetAPI.MessageType.Error, $"Failed to save height map to file {file}: {ae.InnerException.Message}"); } } break; // Absolute positioning case 90: using (await Model.Provider.AccessReadWriteAsync()) { Model.Provider.Get.Channels[code.Channel].RelativePositioning = false; } break; // Relative positioning case 91: using (await Model.Provider.AccessReadWriteAsync()) { Model.Provider.Get.Channels[code.Channel].RelativePositioning = true; } break; } return(result); }
private async Task Process() { // Attempt to process the code internally first if (!InternallyProcessed && await ProcessInternally()) { return; } // Comments are resolved in DCS if (Type == CodeType.Comment) { Result = new CodeResult(); return; } // Send the code to RepRapFirmware if (Flags.HasFlag(CodeFlags.Asynchronous)) { // Enqueue the code for execution by RRF and return no result Task <CodeResult> codeTask = Interface.ProcessCode(this); _ = Task.Run(async() => { try { // Process this code via RRF asynchronously Result = await codeTask; await Model.Provider.Output(Result); } catch (OperationCanceledException) { // Deal with cancelled codes await CodeExecuted(); Console.WriteLine($"[info] Cancelled {this}"); throw; } catch (Exception e) { // Deal with exeptions of asynchronous codes if (e is AggregateException ae) { e = ae.InnerException; } Console.WriteLine($"[err] Failed to execute {this} asynchronously: {e}"); } finally { // Always interpret the result of this code await CodeExecuted(); Console.WriteLine($"[info] Completed {this} asynchronously"); } }); // Start the next code StartNextCode(); } else { // RepRapFirmware buffers a number of codes so a new code can be started before the last one has finished StartNextCode(); // Wait for the code to complete Result = await Interface.ProcessCode(this); } }