Beispiel #1
0
        /// <summary>
        /// Try to find the filament usage
        /// </summary>
        /// <param name="line">Line</param>
        /// <param name="fileInfo">File information</param>
        /// <returns>Whether filament consumption could be found</returns>
        private static bool FindFilamentUsed(string line, ref ParsedFileInfo fileInfo)
        {
            bool hadMatch = false;

            foreach (Regex item in Settings.FilamentFilters)
            {
                Match match = item.Match(line);
                if (match.Success)
                {
                    foreach (Group grp in match.Groups)
                    {
                        if (grp.Name == "mm")
                        {
                            foreach (Capture c in grp.Captures)
                            {
                                fileInfo.Filament.Add(float.Parse(c.Value));
                            }
                            hadMatch = true;
                        }
                        else if (grp.Name == "m")
                        {
                            foreach (Capture c in grp.Captures)
                            {
                                fileInfo.Filament.Add(float.Parse(c.Value) * 1000F);
                            }
                            hadMatch = true;
                        }
                    }
                }
            }
            return(hadMatch);
        }
Beispiel #2
0
            public void AggregateOtherFileInfo(ParsedFileInfo otherFileInfo)
            {
                LinesCount        += otherFileInfo.LinesCount;
                TokensCount       += otherFileInfo.TokensCount;
                CodeElementsCount += otherFileInfo.CodeElementsCount;

                ParseTimeMs += otherFileInfo.ParseTimeMs;
                for (int i = 0; i < RuleInvocations.Length; i++)
                {
                    RuleInvocations[i] += otherFileInfo.RuleInvocations[i];
                }

                DecisionTimeMs += otherFileInfo.DecisionTimeMs;
                for (int i = 0; i < DecisionInfos.Length; i++)
                {
                    if (DecisionInfos[i] == null)
                    {
                        DecisionInfos[i] = new DecisionInfo(i);
                    }
                    DecisionInfos[i].invocations        += otherFileInfo.DecisionInfos[i].invocations;
                    DecisionInfos[i].LL_ATNTransitions  += otherFileInfo.DecisionInfos[i].LL_ATNTransitions;
                    DecisionInfos[i].LL_DFATransitions  += otherFileInfo.DecisionInfos[i].LL_DFATransitions;
                    DecisionInfos[i].LL_Fallback        += otherFileInfo.DecisionInfos[i].LL_Fallback;
                    DecisionInfos[i].LL_MaxLook         += otherFileInfo.DecisionInfos[i].LL_MaxLook;
                    DecisionInfos[i].LL_MinLook         += otherFileInfo.DecisionInfos[i].LL_MinLook;
                    DecisionInfos[i].LL_TotalLook       += otherFileInfo.DecisionInfos[i].LL_TotalLook;
                    DecisionInfos[i].SLL_ATNTransitions += otherFileInfo.DecisionInfos[i].SLL_ATNTransitions;
                    DecisionInfos[i].SLL_DFATransitions += otherFileInfo.DecisionInfos[i].SLL_DFATransitions;
                    DecisionInfos[i].SLL_MaxLook        += otherFileInfo.DecisionInfos[i].SLL_MaxLook;
                    DecisionInfos[i].SLL_MinLook        += otherFileInfo.DecisionInfos[i].SLL_MinLook;
                    DecisionInfos[i].SLL_TotalLook      += otherFileInfo.DecisionInfos[i].SLL_TotalLook;
                    DecisionInfos[i].timeInPrediction   += otherFileInfo.DecisionInfos[i].timeInPrediction;
                }
            }
Beispiel #3
0
        /// <summary>
        /// Find the simulated time
        /// </summary>
        /// <param name="line">Line</param>
        /// <param name="fileInfo">File information</param>
        /// <returns>Whether the simulated time could be found</returns>
        private static bool FindSimulatedTime(string line, ref ParsedFileInfo fileInfo)
        {
            foreach (Regex item in Settings.SimulatedTimeFilters)
            {
                Match match = item.Match(line);
                if (match.Success)
                {
                    long seconds = 0;
                    foreach (Group grp in match.Groups)
                    {
                        if (!string.IsNullOrEmpty(grp.Value))
                        {
                            switch (grp.Name)
                            {
                            case "h":
                                seconds += long.Parse(grp.Value) * 3600;
                                break;

                            case "m":
                                seconds += long.Parse(grp.Value) * 60;
                                break;

                            case "s":
                                seconds += long.Parse(grp.Value);
                                break;
                            }
                        }
                    }
                    fileInfo.SimulatedTime = seconds;
                    return(true);
                }
            }
            return(false);
        }
 private static bool IsFileInfoComplete(ParsedFileInfo result)
 {
     return((result.Height != 0) &&
            (result.FirstLayerHeight != 0) &&
            (result.LayerHeight != 0) &&
            (result.Filament.Count > 0) &&
            (result.GeneratedBy != ""));
 }
Beispiel #5
0
 /// <summary>
 /// Checks if the given file info is complete
 /// </summary>
 /// <param name="result">File information</param>
 /// <returns>Whether the file info is complete</returns>
 private static bool IsFileInfoComplete(ParsedFileInfo result)
 {
     return((result.Height != 0) &&
            (result.FirstLayerHeight != 0) &&
            (result.LayerHeight != 0) &&
            (result.Filament.Count > 0) &&
            (!string.IsNullOrEmpty(result.GeneratedBy)));
 }
Beispiel #6
0
 /// <summary>
 /// Checks if the given file info is complete
 /// </summary>
 /// <param name="result">File information</param>
 /// <returns>Whether the file info is complete</returns>
 private static bool IsFileInfoComplete(ParsedFileInfo result)
 {
     // Don't check PrintTime and SimulatedTime here because they are usually parsed before the following
     return((result.Height != 0) &&
            (result.FirstLayerHeight != 0) &&
            (result.LayerHeight != 0) &&
            (result.Filament.Count > 0) &&
            (!string.IsNullOrEmpty(result.GeneratedBy)));
 }
Beispiel #7
0
        public AntlrPerformanceProfiler(Antlr4.Runtime.Parser parser)
        {
            parserRulesCount     = parser.RuleNames.Length;
            parserRuleNames      = parser.RuleNames;
            parserDecisionsCount = parser.Atn.DecisionToDfa.Length;

            ParsedFilesInfos   = new List <ParsedFileInfo>();
            AggregatedPerfInfo = new ParsedFileInfo("TOTAL", parserRulesCount, parserDecisionsCount);
            RuleStacksCount    = new Dictionary <string, int>();
        }
        public async Task TestThumbnails(string fileName, int thumbnailCount)
        {
            string         filePath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "../../../File/GCodes", fileName);
            ParsedFileInfo info     = await DuetControlServer.Files.InfoParser.Parse(filePath);

            TestContext.Out.Write(JsonSerializer.Serialize(info, typeof(ParsedFileInfo), new JsonSerializerOptions {
                WriteIndented = true
            }));
            Assert.AreEqual(info.Thumbnails.Count, thumbnailCount);
        }
        /// <summary>
        /// Try to find the filament usage
        /// </summary>
        /// <param name="line">Line</param>
        /// <param name="fileInfo">File information</param>
        /// <returns>Whether filament consumption could be found</returns>
        private static bool FindFilamentUsed(string line, ref ParsedFileInfo fileInfo)
        {
            foreach (Regex item in Settings.FilamentFilters)
            {
                Match match = item.Match(line);
                if (match.Success)
                {
                    if (match.Groups.TryGetValue("mm", out Group mmGroup))
                    {
                        if (float.TryParse(mmGroup.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out float filamentUsage) &&
                            float.IsFinite(filamentUsage))
                        {
                            if (match.Groups.TryGetValue("index", out Group indexGroup) && int.TryParse(indexGroup.Value, out int index))
                            {
                                for (int i = fileInfo.Filament.Count; i <= index; i++)
                                {
                                    fileInfo.Filament.Add(0F);
                                }
                                fileInfo.Filament[index] = filamentUsage;
                            }
                            else
                            {
                                fileInfo.Filament.Add(filamentUsage);
                            }
                        }
                        return(true);
                    }

                    if (match.Groups.TryGetValue("m", out Group mGroup))
                    {
                        if (float.TryParse(mGroup.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out float filamentUsage) &&
                            float.IsFinite(filamentUsage))
                        {
                            if (match.Groups.TryGetValue("index", out Group indexGroup) && int.TryParse(indexGroup.Value, out int index))
                            {
                                for (int i = fileInfo.Filament.Count; i <= index; i++)
                                {
                                    fileInfo.Filament.Add(0F);
                                }
                                fileInfo.Filament[index] = filamentUsage * 1000F;
                            }
                            else
                            {
                                fileInfo.Filament.Add(filamentUsage * 1000F);
                            }
                        }
                        return(true);
                    }
                }
            }
            return(false);
        }
Beispiel #10
0
 /// <summary>
 /// Find the toolchain that generated the file
 /// </summary>
 /// <param name="line">Line</param>
 /// <param name="fileInfo">File information</param>
 /// <returns>Whether the slicer could be found</returns>
 private static bool FindGeneratedBy(string line, ref ParsedFileInfo fileInfo)
 {
     foreach (Regex item in Settings.GeneratedByFilters)
     {
         Match match = item.Match(line);
         if (match.Success && match.Groups.Count > 1)
         {
             fileInfo.GeneratedBy = match.Groups[1].Value;
             return(true);
         }
     }
     return(false);
 }
Beispiel #11
0
        /// <summary>
        /// Notify the firmware that a print has started
        /// </summary>
        /// <param name="to">Destination</param>
        /// <param name="info">Information about the file being printed</param>
        /// <returns>Number of bytes written</returns>
        /// <exception cref="ArgumentException">One of the supplied values is too big</exception>
        public static int WritePrintStarted(Span <byte> to, ParsedFileInfo info)
        {
            Span <byte> unicodeFilename = Encoding.UTF8.GetBytes(info.FileName);

            if (unicodeFilename.Length > 254)
            {
                throw new ArgumentException("Value is too long", nameof(info.FileName));
            }

            Span <byte> unicodeGeneratedBy = Encoding.UTF8.GetBytes(info.GeneratedBy);

            if (unicodeGeneratedBy.Length > 254)
            {
                throw new ArgumentException("Value is too long", nameof(info.GeneratedBy));
            }

            // Write header
            PrintStarted header = new PrintStarted
            {
                FilenameLength    = (byte)unicodeFilename.Length,
                GeneratedByLength = (byte)unicodeGeneratedBy.Length,
                NumFilaments      = (ushort)info.Filament.Count,
                FileSize          = (uint)info.Size,
                LastModifiedTime  = info.LastModified.HasValue ? (ulong)(info.LastModified.Value - new DateTime(1970, 1, 1)).TotalSeconds : 0,
                FirstLayerHeight  = info.FirstLayerHeight,
                LayerHeight       = info.LayerHeight,
                ObjectHeight      = info.Height,
                PrintTime         = (uint)info.PrintTime,
                SimulatedTime     = (uint)info.SimulatedTime
            };

            MemoryMarshal.Write(to, ref header);
            int bytesWritten = Marshal.SizeOf(header);

            // Write filaments
            foreach (double filament in info.Filament)
            {
                float filamentUsage = (float)filament;
                MemoryMarshal.Write(to.Slice(bytesWritten), ref filamentUsage);
                bytesWritten += Marshal.SizeOf(filamentUsage);
            }

            // Write filename
            unicodeFilename.CopyTo(to.Slice(bytesWritten));
            bytesWritten += unicodeFilename.Length;

            // Write slicer
            unicodeGeneratedBy.CopyTo(to.Slice(bytesWritten));
            bytesWritten += unicodeGeneratedBy.Length;
            return(AddPadding(to, bytesWritten));
        }
Beispiel #12
0
        /// <summary>
        /// Begin a file print
        /// </summary>
        /// <param name="fileName">File to print</param>
        /// <param name="source">Channel that requested the file to be printed</param>
        /// <returns>Code result</returns>
        public static async Task <CodeResult> Start(string fileName, CodeChannel source)
        {
            // Initialize the file
            using (await _lock.LockAsync())
            {
                if (_file != null)
                {
                    return(new CodeResult(MessageType.Error, "A file is already being printed"));
                }

                _file    = new BaseFile(fileName, CodeChannel.File);
                IsPaused = IsAborted = false;
            }

            // Wait for all pending firmware codes on the source channel to finish first
            await SPI.Interface.Flush(source);

            // Reset the resume event
            if (_resumeEvent.IsSet)
            {
                await _resumeEvent.WaitAsync();
            }

            // Analyze it and update the object model
            ParsedFileInfo info = await FileInfoParser.Parse(fileName);

            using (await Model.Provider.AccessReadWriteAsync())
            {
                Model.Provider.Get.Channels[CodeChannel.File].VolumetricExtrusion = false;
                Model.Provider.Get.Job.File.Assign(info);
            }

            // Notify RepRapFirmware and start processing the file in the background
            Console.WriteLine($"[info] Printing file '{fileName}'");
            SPI.Interface.SetPrintStarted();
            _ = Task.Run(RunPrint);

            // Return a result
            using (await Model.Provider.AccessReadOnlyAsync())
            {
                if (Model.Provider.Get.Channels[source].Compatibility == Compatibility.Marlin)
                {
                    return(new CodeResult(MessageType.Success, "File opened\nFile selected"));
                }
                else
                {
                    return(new CodeResult());
                }
            }
        }
Beispiel #13
0
        public async Task TestEmpty()
        {
            string         filePath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "File/GCodes/Circle.gcode");
            ParsedFileInfo info     = await FileInfoParser.Parse(filePath);

            TestContext.Out.Write(JsonConvert.SerializeObject(info, Formatting.Indented));

            Assert.IsNotNull(info.FileName);
            Assert.AreNotEqual(0, info.Size);
            Assert.IsNotNull(info.LastModified);
            Assert.AreEqual(0, info.Height);
            Assert.AreEqual(0.5, info.FirstLayerHeight);
            Assert.AreEqual(0, info.LayerHeight);
            Assert.AreEqual(0, info.Filament.Count);
            Assert.AreEqual("", info.GeneratedBy);
            Assert.AreEqual(0, info.PrintTime);
            Assert.AreEqual(0, info.SimulatedTime);
        }
Beispiel #14
0
 public void BeginParsingFile(TextSourceInfo textSourceInfo, ITokensLinesIterator tokensCountIterator)
 {
     CurrentFileInfo = new ParsedFileInfo(textSourceInfo.Name, parserRulesCount, parserDecisionsCount);
     // Only for CodeElementsParser
     if (tokensCountIterator != null)
     {
         ITokensLine lastLine = null;
         Token       token    = null;
         while ((token = tokensCountIterator.NextToken()) != Token.END_OF_FILE)
         {
             CurrentFileInfo.TokensCount++;
             if (token.TokensLine != lastLine)
             {
                 CurrentFileInfo.LinesCount++;
                 lastLine = token.TokensLine;
             }
         }
     }
 }
Beispiel #15
0
 /// <summary>
 /// Try to find the layer height
 /// </summary>
 /// <param name="line">Line</param>
 /// <param name="fileInfo">File information</param>
 /// <returns>Whether layer height could be found</returns>
 private static bool FindLayerHeight(string line, ref ParsedFileInfo fileInfo)
 {
     foreach (Regex item in Settings.LayerHeightFilters)
     {
         Match match = item.Match(line);
         if (match.Success)
         {
             foreach (Group grp in match.Groups)
             {
                 if (grp.Name == "mm")
                 {
                     fileInfo.LayerHeight = float.Parse(grp.Value);
                     return(true);
                 }
             }
         }
     }
     return(false);
 }
Beispiel #16
0
        public async Task TestEmpty()
        {
            string         filePath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "../../../File/GCodes/Circle.gcode");
            ParsedFileInfo info     = await DuetControlServer.Files.InfoParser.Parse(filePath);

            TestContext.Out.Write(JsonSerializer.Serialize(info, typeof(ParsedFileInfo), new JsonSerializerOptions {
                WriteIndented = true
            }));

            Assert.IsNotNull(info.FileName);
            Assert.AreNotEqual(0, info.Size);
            Assert.AreEqual(0.5, info.Height);
            Assert.AreEqual(0.5, info.FirstLayerHeight);
            Assert.AreEqual(0, info.LayerHeight);
            Assert.AreEqual(0, info.Filament.Count);
            Assert.IsNull(info.GeneratedBy);
            Assert.IsNull(info.PrintTime);
            Assert.IsNull(info.SimulatedTime);
        }
Beispiel #17
0
 /// <summary>
 /// Try to find the layer height
 /// </summary>
 /// <param name="line">Line</param>
 /// <param name="fileInfo">File information</param>
 /// <returns>Whether layer height could be found</returns>
 private static bool FindLayerHeight(string line, ref ParsedFileInfo fileInfo)
 {
     foreach (Regex item in Settings.LayerHeightFilters)
     {
         Match match = item.Match(line);
         if (match.Success)
         {
             foreach (Group grp in match.Groups)
             {
                 if (grp.Name == "mm" && float.TryParse(grp.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out float layerHeight) &&
                     float.IsFinite(layerHeight) && layerHeight < Settings.MaxLayerHeight)
                 {
                     fileInfo.LayerHeight = layerHeight;
                     return(true);
                 }
             }
         }
     }
     return(false);
 }
        /// <summary>
        /// Parse the file for thumbnails
        /// </summary>
        /// <param name="reader">Stream reader</param>
        /// <param name="parsedFileInfo">G-code file information</param>
        /// <returns>Asynchronous task</returns>
        /// <remarks>
        /// This functionality should be moved to ParseHeader in the long term
        /// </remarks>
        private static async Task ParseThumbnails(StreamReader reader, ParsedFileInfo parsedFileInfo)
        {
            Code             code             = new();
            CodeParserBuffer codeParserBuffer = new(Settings.FileBufferSize, true);

            reader.BaseStream.Seek(0, SeekOrigin.Begin);
            while (codeParserBuffer.GetPosition(reader) < reader.BaseStream.Length)
            {
                Program.CancellationToken.ThrowIfCancellationRequested();
                if (!await DuetAPI.Commands.Code.ParseAsync(reader, code, codeParserBuffer))
                {
                    continue;
                }

                if (code.Type != CodeType.None && code.Type != CodeType.Comment)
                {
                    return;
                }

                if (string.IsNullOrEmpty(code.Comment))
                {
                    code.Reset();
                    continue;
                }

                //This is the start of a PrusaSlicer Image.
                if (code.Comment.Contains("thumbnail begin", StringComparison.InvariantCultureIgnoreCase))
                {
                    _logger.Debug("Found Prusa Slicer Image");
                    await PrusaSlicerImageParser.ProcessAsync(reader, codeParserBuffer, parsedFileInfo, code);
                }
                //Icon Image
                else if (code.Comment.Contains("Icon:"))
                {
                    _logger.Debug("Found Icon Image");
                    await IconImageParser.ProcessAsync(reader, codeParserBuffer, parsedFileInfo, code);
                }
                code.Reset();
            }
        }
Beispiel #19
0
        /// <summary>
        /// Try to find the filament usage
        /// </summary>
        /// <param name="line">Line</param>
        /// <param name="fileInfo">File information</param>
        /// <returns>Whether filament consumption could be found</returns>
        private static bool FindFilamentUsed(string line, ref ParsedFileInfo fileInfo)
        {
            bool hadMatch = false;

            foreach (Regex item in Settings.FilamentFilters)
            {
                Match match = item.Match(line);
                if (match.Success)
                {
                    foreach (Group grp in match.Groups)
                    {
                        if (grp.Name == "mm")
                        {
                            foreach (Capture c in grp.Captures)
                            {
                                if (float.TryParse(c.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out float filamentUsage) &&
                                    float.IsFinite(filamentUsage))
                                {
                                    fileInfo.Filament.Add(filamentUsage);
                                }
                            }
                            hadMatch = true;
                        }
                        else if (grp.Name == "m")
                        {
                            foreach (Capture c in grp.Captures)
                            {
                                if (float.TryParse(c.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out float filamentUsage) &&
                                    float.IsFinite(filamentUsage))
                                {
                                    fileInfo.Filament.Add(filamentUsage * 1000F);
                                }
                            }
                            hadMatch = true;
                        }
                    }
                }
            }
            return(hadMatch);
        }
        /// <summary>
        /// Parse a G-code file
        /// </summary>
        /// <param name="fileName">File to analyze</param>
        /// <returns>Information about the file</returns>
        public static async Task <ParsedFileInfo> Parse(string fileName)
        {
            FileStream           fileStream = new FileStream(fileName, FileMode.Open);
            SeekableStreamReader reader     = new SeekableStreamReader(fileStream);

            try
            {
                ParsedFileInfo result = new ParsedFileInfo
                {
                    FileName     = await FilePath.ToVirtualAsync(fileName),
                    Size         = fileStream.Length,
                    LastModified = File.GetLastWriteTime(fileName)
                };

                if (fileStream.Length > 0)
                {
                    List <float> filamentConsumption = new List <float>();
                    await ParseHeader(reader, filamentConsumption, result);
                    await ParseFooter(reader, fileStream.Length, filamentConsumption, result);

                    result.Filament = filamentConsumption;

                    if (result.FirstLayerHeight + result.LayerHeight > 0F && result.Height > 0F)
                    {
                        result.NumLayers = (int?)(Math.Round((result.Height - result.FirstLayerHeight) / result.LayerHeight) + 1);
                    }
                }

                reader.Close();
                fileStream.Close();
                return(result);
            }
            catch
            {
                reader.Close();
                fileStream.Close();
                throw;
            }
        }
        /// <summary>
        /// Find the total print time
        /// </summary>
        /// <param name="line">Line</param>
        /// <param name="fileInfo">File information</param>
        /// <returns>Whether the print time could be found</returns>
        private static bool FindPrintTime(string line, ref ParsedFileInfo fileInfo)
        {
            foreach (Regex item in Settings.PrintTimeFilters)
            {
                Match match = item.Match(line);
                if (match.Success)
                {
                    long seconds = 0;
                    foreach (Group grp in match.Groups)
                    {
                        if (float.TryParse(grp.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out float printTime) &&
                            float.IsFinite(printTime))
                        {
                            switch (grp.Name)
                            {
                            case "h":
                                seconds += (long)Math.Round(printTime) * 3600L;
                                break;

                            case "m":
                                seconds += (long)Math.Round(printTime) * 60L;
                                break;

                            case "s":
                                seconds += (long)Math.Round(printTime);
                                break;
                            }
                        }
                    }
                    if (seconds > 0)
                    {
                        fileInfo.PrintTime = seconds;
                    }
                    return(true);
                }
            }
            return(false);
        }
Beispiel #22
0
        /// <summary>
        /// Parse a G-code file
        /// </summary>
        /// <param name="fileName">File to analyze</param>
        /// <returns>Information about the file</returns>
        public static async Task <ParsedFileInfo> Parse(string fileName)
        {
            using FileStream fileStream = new FileStream(fileName, FileMode.Open);
            using StreamReader reader   = new StreamReader(fileStream, null, true, Settings.FileInfoReadBufferSize);
            ParsedFileInfo result = new ParsedFileInfo
            {
                FileName     = await FilePath.ToVirtualAsync(fileName),
                Size         = fileStream.Length,
                LastModified = File.GetLastWriteTime(fileName)
            };

            if (fileStream.Length > 0)
            {
                await ParseHeader(reader, result);
                await ParseFooter(reader, result);

                if (result.FirstLayerHeight + result.LayerHeight > 0F && result.Height > 0F)
                {
                    result.NumLayers = (int?)(Math.Round((result.Height - result.FirstLayerHeight) / result.LayerHeight) + 1);
                }
            }
            return(result);
        }
Beispiel #23
0
        /// <summary>
        /// Find the simulated time
        /// </summary>
        /// <param name="line">Line</param>
        /// <param name="fileInfo">File information</param>
        /// <returns>Whether the simulated time could be found</returns>
        private static bool FindSimulatedTime(string line, ref ParsedFileInfo fileInfo)
        {
            foreach (Regex item in Settings.SimulatedTimeFilters)
            {
                Match match = item.Match(line);
                if (match.Success)
                {
                    long seconds = 0;
                    foreach (Group grp in match.Groups)
                    {
                        if (long.TryParse(grp.Value, out long simulatedTime))
                        {
                            switch (grp.Name)
                            {
                            case "h":
                                seconds += simulatedTime * 3600;
                                break;

                            case "m":
                                seconds += simulatedTime * 60;
                                break;

                            case "s":
                                seconds += simulatedTime;
                                break;
                            }
                        }
                    }
                    if (seconds > 0)
                    {
                        fileInfo.SimulatedTime = seconds;
                    }
                    return(true);
                }
            }
            return(false);
        }
Beispiel #24
0
        /// <summary>
        /// Parse the footer of a G-code file
        /// </summary>
        /// <param name="reader">Stream reader</param>
        /// <param name="partialFileInfo">G-code file information</param>
        /// <returns>Asynchronous task</returns>
        private static async Task ParseFooter(StreamReader reader, ParsedFileInfo partialFileInfo)
        {
            CancellationToken token = Program.CancelSource.Token;

            reader.BaseStream.Seek(0, SeekOrigin.End);

            Code code = new Code();
            bool inRelativeMode = false, lastLineHadInfo = false, hadFilament = partialFileInfo.Filament.Count > 0, enforcingAbsolutePosition = false;

            char[] buffer        = new char[Settings.FileInfoReadBufferSize];
            int    bufferPointer = 0;

            do
            {
                token.ThrowIfCancellationRequested();

                // Read another line
                ReadLineFromEndResult readResult = await ReadLineFromEndAsync(reader, buffer, bufferPointer);

                if (readResult == null)
                {
                    break;
                }
                bufferPointer = readResult.BufferPointer;

                // See what codes to deal with
                bool gotNewInfo = false;
                using (StringReader stringReader = new StringReader(readResult.Line))
                {
                    while (Code.Parse(stringReader, code, ref enforcingAbsolutePosition))
                    {
                        if (code.Type == CodeType.GCode && partialFileInfo.Height == 0)
                        {
                            if (code.MajorNumber == 90)
                            {
                                // G90 code (absolute positioning) implies we were in relative mode
                                inRelativeMode = true;
                                gotNewInfo     = true;
                            }
                            else if (inRelativeMode)
                            {
                                // G91 code (relative positioning) implies we were in absolute mode
                                inRelativeMode = (code.MajorNumber != 91);
                                gotNewInfo     = true;
                            }
                            else if (code.MajorNumber == 0 || code.MajorNumber == 1)
                            {
                                // G0/G1 is an absolute move, see if there is a Z parameter present
                                CodeParameter zParam = code.Parameter('Z');
                                if (zParam != null && (code.Comment == null || !code.Comment.TrimStart().StartsWith("E")))
                                {
                                    gotNewInfo             = true;
                                    partialFileInfo.Height = zParam;
                                }
                            }
                        }
                        else if (!string.IsNullOrWhiteSpace(code.Comment))
                        {
                            gotNewInfo |= partialFileInfo.LayerHeight == 0 && FindLayerHeight(readResult.Line, ref partialFileInfo);
                            gotNewInfo |= !hadFilament && FindFilamentUsed(readResult.Line, ref partialFileInfo);
                            gotNewInfo |= string.IsNullOrEmpty(partialFileInfo.GeneratedBy) && FindGeneratedBy(readResult.Line, ref partialFileInfo);
                            gotNewInfo |= partialFileInfo.PrintTime == 0 && FindPrintTime(readResult.Line, ref partialFileInfo);
                            gotNewInfo |= partialFileInfo.SimulatedTime == 0 && FindSimulatedTime(readResult.Line, ref partialFileInfo);
                        }
                        code.Reset();
                    }
                }

                // Is the file info complete?
                if (!gotNewInfo && !lastLineHadInfo && IsFileInfoComplete(partialFileInfo))
                {
                    break;
                }
                lastLineHadInfo = gotNewInfo;
            }while (reader.BaseStream.Length - reader.BaseStream.Position < Settings.FileInfoReadLimitFooter + buffer.Length);
        }
        private static async Task ParseHeader(SeekableStreamReader reader, ParsedFileInfo partialFileInfo)
        {
            // Every time CTS.Token is accessed a copy is generated. Hence we cache one until this method completes
            CancellationToken token = Program.CancelSource.Token;

            List <float> filamentConsumption = new List <float>();
            bool         inRelativeMode = false, lastLineHadInfo = false;

            do
            {
                token.ThrowIfCancellationRequested();

                string line = await reader.ReadLineAsync();

                if (line == null)
                {
                    break;
                }
                bool gotNewInfo = false;

                // See what code to deal with
                Code code = new Code(line);
                if (code.Type == CodeType.GCode && partialFileInfo.FirstLayerHeight == 0)
                {
                    if (code.MajorNumber == 91)
                    {
                        // G91 code (relative positioning)
                        inRelativeMode = true;
                        gotNewInfo     = true;
                    }
                    else if (inRelativeMode)
                    {
                        // G90 (absolute positioning)
                        inRelativeMode = (code.MajorNumber != 90);
                        gotNewInfo     = true;
                    }
                    else if (code.MajorNumber == 0 || code.MajorNumber == 1)
                    {
                        // G0/G1 is a move, see if there is a Z parameter present
                        CodeParameter zParam = code.Parameter('Z');
                        if (zParam != null)
                        {
                            float z = zParam;
                            if (z <= Settings.MaxLayerHeight)
                            {
                                partialFileInfo.FirstLayerHeight = z;
                                gotNewInfo = true;
                            }
                        }
                    }
                }
                else if (code.Type == CodeType.Comment)
                {
                    gotNewInfo |= partialFileInfo.LayerHeight == 0 && FindLayerHeight(line, ref partialFileInfo);
                    gotNewInfo |= FindFilamentUsed(line, ref filamentConsumption);
                    gotNewInfo |= partialFileInfo.GeneratedBy == "" && FindGeneratedBy(line, ref partialFileInfo);
                    gotNewInfo |= partialFileInfo.PrintTime == 0 && FindPrintTime(line, ref partialFileInfo);
                    gotNewInfo |= partialFileInfo.SimulatedTime == 0 && FindSimulatedTime(line, ref partialFileInfo);
                }

                if (!gotNewInfo && !lastLineHadInfo && IsFileInfoComplete(partialFileInfo))
                {
                    break;
                }
                lastLineHadInfo = gotNewInfo;
            }while (reader.Position < Settings.FileInfoReadLimit);

            foreach (float filament in filamentConsumption)
            {
                partialFileInfo.Filament.Add(filament);
            }
        }
        public void PrintStarted()
        {
            Span <byte> span = new byte[128];

            span.Fill(0xFF);

            ParsedFileInfo info = new ParsedFileInfo
            {
                Size             = 452432,
                FileName         = "0:/gcodes/test.g",
                FirstLayerHeight = 0.3F,
                GeneratedBy      = "Slic3r",
                Height           = 53.4F,
                LastModified     = new DateTime(2014, 11, 23),
                NumLayers        = 343,
                Filament         = new List <float> {
                    123.45F, 678.9F
                },
                LayerHeight   = 0.2F,
                PrintTime     = 12355,
                SimulatedTime = 10323
            };

            int bytesWritten = Writer.WritePrintStarted(span, info);

            Assert.AreEqual(72, bytesWritten);

            // Header
            ushort filenameLength = MemoryMarshal.Read <ushort>(span.Slice(0, 2));

            Assert.AreEqual(info.FileName.Length, filenameLength);
            ushort generatedByLength = MemoryMarshal.Read <ushort>(span.Slice(2, 2));

            Assert.AreEqual(6, generatedByLength);
            uint numFilaments = MemoryMarshal.Read <uint>(span.Slice(4, 4));

            Assert.AreEqual(2, numFilaments);
            ulong expectedModifiedDate = (ulong)(info.LastModified.Value - new DateTime(1970, 1, 1)).TotalSeconds;
            ulong modifiedDate         = MemoryMarshal.Read <ulong>(span.Slice(8, 8));

            Assert.AreEqual(expectedModifiedDate, modifiedDate);
            uint fileSize = MemoryMarshal.Read <uint>(span.Slice(16, 4));

            Assert.AreEqual(452432, fileSize);
            float firstLayerHeight = MemoryMarshal.Read <float>(span.Slice(20, 4));

            Assert.AreEqual(0.3, firstLayerHeight, 0.00001);
            float layerHeight = MemoryMarshal.Read <float>(span.Slice(24, 4));

            Assert.AreEqual(0.2, layerHeight, 0.00001);
            float objectHeight = MemoryMarshal.Read <float>(span.Slice(28, 4));

            Assert.AreEqual(53.4, objectHeight, 0.00001);
            uint printTime = MemoryMarshal.Read <uint>(span.Slice(32, 4));

            Assert.AreEqual(12355, printTime);
            uint simulatedTime = MemoryMarshal.Read <uint>(span.Slice(36, 4));

            Assert.AreEqual(10323, simulatedTime);

            // Filament consumption
            float filamentUsageA = MemoryMarshal.Read <float>(span.Slice(40, 4));

            Assert.AreEqual(123.45, filamentUsageA, 0.0001);
            float filamentUsageB = MemoryMarshal.Read <float>(span.Slice(44, 4));

            Assert.AreEqual(678.9, filamentUsageB, 0.0001);

            // File name
            string fileName = Encoding.UTF8.GetString(span.Slice(48, info.FileName.Length));

            Assert.AreEqual(info.FileName, fileName);

            // Generated by
            string generatedBy = Encoding.UTF8.GetString(span.Slice(48 + info.FileName.Length, info.GeneratedBy.Length));

            Assert.AreEqual(info.GeneratedBy, generatedBy);
        }
Beispiel #27
0
        /// <summary>
        /// Parse the header of a G-code file
        /// </summary>
        /// <param name="reader">Stream reader</param>
        /// <param name="partialFileInfo">G-code file information</param>
        /// <returns>Asynchronous task</returns>
        private static async Task ParseHeader(StreamReader reader, ParsedFileInfo partialFileInfo)
        {
            // Every time CTS.Token is accessed a copy is generated. Hence we cache one until this method completes
            CancellationToken token = Program.CancelSource.Token;

            Code code = new Code();
            bool inRelativeMode = false, lastLineHadInfo = false, enforcingAbsolutePosition = false;

            do
            {
                token.ThrowIfCancellationRequested();

                // Read another line
                string line = await reader.ReadLineAsync();

                if (line == null)
                {
                    break;
                }

                // See what codes to deal with
                bool gotNewInfo = false;
                using (StringReader stringReader = new StringReader(line))
                {
                    while (Code.Parse(stringReader, code, ref enforcingAbsolutePosition))
                    {
                        if (code.Type == CodeType.GCode && partialFileInfo.FirstLayerHeight == 0)
                        {
                            if (code.MajorNumber == 91)
                            {
                                // G91 code (relative positioning)
                                inRelativeMode = true;
                                gotNewInfo     = true;
                            }
                            else if (inRelativeMode)
                            {
                                // G90 (absolute positioning)
                                inRelativeMode = (code.MajorNumber != 90);
                                gotNewInfo     = true;
                            }
                            else if (code.MajorNumber == 0 || code.MajorNumber == 1)
                            {
                                // G0/G1 is a move, see if there is a Z parameter present
                                CodeParameter zParam = code.Parameter('Z');
                                if (zParam != null)
                                {
                                    float z = zParam;
                                    if (z <= Settings.MaxLayerHeight)
                                    {
                                        partialFileInfo.FirstLayerHeight = z;
                                        gotNewInfo = true;
                                    }
                                }
                            }
                        }
                        else if (!string.IsNullOrWhiteSpace(code.Comment))
                        {
                            gotNewInfo |= partialFileInfo.LayerHeight == 0 && FindLayerHeight(line, ref partialFileInfo);
                            gotNewInfo |= FindFilamentUsed(line, ref partialFileInfo);
                            gotNewInfo |= string.IsNullOrEmpty(partialFileInfo.GeneratedBy) && FindGeneratedBy(line, ref partialFileInfo);
                            gotNewInfo |= partialFileInfo.PrintTime == 0 && FindPrintTime(line, ref partialFileInfo);
                            gotNewInfo |= partialFileInfo.SimulatedTime == 0 && FindSimulatedTime(line, ref partialFileInfo);
                        }
                        code.Reset();
                    }
                }

                // Is the file info complete?
                if (!gotNewInfo && !lastLineHadInfo && IsFileInfoComplete(partialFileInfo))
                {
                    break;
                }
                lastLineHadInfo = gotNewInfo;
            }while (reader.BaseStream.Position < Settings.FileInfoReadLimitHeader + Settings.FileInfoReadBufferSize);
        }
Beispiel #28
0
        /// <summary>
        /// Extract thumbnails generated by Prusa Slicer from a file
        /// </summary>
        /// <param name="reader">Stream reader to read from</param>
        /// <param name="codeParserBuffer">Parser buffer</param>
        /// <param name="parsedFileInfo">File information</param>
        /// <param name="code">Code to reuse while parsing</param>
        /// <returns>Asynchronous task</returns>
        public static async Task ProcessAsync(StreamReader reader, CodeParserBuffer codeParserBuffer, ParsedFileInfo parsedFileInfo, Code code)
        {
            StringBuilder encodedImage = new();

            //Read the image header info that is currently in the code
            string[] thumbnailTokens = code.Comment.Trim().Split(' ');

            //Stop processing since the thumbnail may be corrupt.
            if (thumbnailTokens.Length != 4)
            {
                throw new ImageProcessingException();
            }
            string[] dimensions = thumbnailTokens[2].Split('x');
            if (dimensions.Length != 2)
            {
                throw new ImageProcessingException();
            }

            ParsedThumbnail thumbnail = new()
            {
                Width  = int.Parse(dimensions[0]),
                Height = int.Parse(dimensions[1])
            };

            int encodedLength = int.Parse(thumbnailTokens[3]);

            encodedImage.Clear();
            code.Reset();


            //Keep reading the data from the file
            while (codeParserBuffer.GetPosition(reader) < reader.BaseStream.Length)
            {
                Program.CancellationToken.ThrowIfCancellationRequested();
                if (!await Code.ParseAsync(reader, code, codeParserBuffer))
                {
                    continue;
                }



                if (code.Type != CodeType.Comment)
                {
                    return;
                }

                if (string.IsNullOrEmpty(code.Comment))
                {
                    code.Reset();
                    continue;
                }

                if (code.Comment.Contains("thumbnail begin", StringComparison.InvariantCultureIgnoreCase))
                {
                    //Exit if we find another start tag before ending the previous image
                    throw new ImageProcessingException();
                }
                else if (code.Comment.Contains("thumbnail end", StringComparison.InvariantCultureIgnoreCase))
                {
                    if (encodedImage.Length == encodedLength)
                    {
                        thumbnail.EncodedImage = "data:image/png;base64," + encodedImage.ToString();
                        parsedFileInfo.Thumbnails.Add(thumbnail);
                        return;
                    }
                }
                else
                {
                    encodedImage.Append(code.Comment.Trim());
                }
                code.Reset();
            }
        }
    }
        public void PrintStarted2()
        {
            Span <byte> span = new byte[128];

            span.Fill(0xFF);

            ParsedFileInfo info = new ParsedFileInfo
            {
                Size             = 4180,
                FileName         = "0:/gcodes/circle.g",
                FirstLayerHeight = 0.5F,
                GeneratedBy      = string.Empty,
                Height           = 0,
                LastModified     = new DateTime(2019, 4, 23),
                NumLayers        = null,
                LayerHeight      = 0,
                PrintTime        = 0,
                SimulatedTime    = 0,
            };

            int bytesWritten = Writer.WritePrintStarted(span, info);

            Assert.AreEqual(60, bytesWritten);

            // Header
            ushort filenameLength = MemoryMarshal.Read <ushort>(span.Slice(0, 2));

            Assert.AreEqual(info.FileName.Length, filenameLength);
            ushort generatedByLength = MemoryMarshal.Read <ushort>(span.Slice(2, 2));

            Assert.AreEqual(info.GeneratedBy.Length, generatedByLength);
            uint numFilaments = MemoryMarshal.Read <uint>(span.Slice(4, 4));

            Assert.AreEqual(0, numFilaments);
            ulong expectedModifiedDate = (ulong)(info.LastModified.Value - new DateTime(1970, 1, 1)).TotalSeconds;
            ulong modifiedDate         = MemoryMarshal.Read <ulong>(span.Slice(8, 8));

            Assert.AreEqual(expectedModifiedDate, modifiedDate);
            uint fileSize = MemoryMarshal.Read <uint>(span.Slice(16, 4));

            Assert.AreEqual(4180, fileSize);
            float firstLayerHeight = MemoryMarshal.Read <float>(span.Slice(20, 4));

            Assert.AreEqual(0.5, firstLayerHeight, 0.00001);
            float layerHeight = MemoryMarshal.Read <float>(span.Slice(24, 4));

            Assert.AreEqual(0, layerHeight, 0.00001);
            float objectHeight = MemoryMarshal.Read <float>(span.Slice(28, 4));

            Assert.AreEqual(0, objectHeight, 0.00001);
            uint printTime = MemoryMarshal.Read <uint>(span.Slice(32, 4));

            Assert.AreEqual(0, printTime);
            uint simulatedTime = MemoryMarshal.Read <uint>(span.Slice(36, 4));

            Assert.AreEqual(0, simulatedTime);

            // File name
            string fileName = Encoding.UTF8.GetString(span.Slice(40, info.FileName.Length));

            Assert.AreEqual(info.FileName, fileName);

            // Generated by
            string generatedBy = Encoding.UTF8.GetString(span.Slice(40 + info.FileName.Length, generatedByLength));

            Assert.AreEqual(info.GeneratedBy, generatedBy);
        }
        private static async Task ParseFooter(SeekableStreamReader reader, long length, ParsedFileInfo partialFileInfo)
        {
            CancellationToken token = Program.CancelSource.Token;

            reader.Seek(0, SeekOrigin.End);

            bool         inRelativeMode = false, lastLineHadInfo = false;
            float?       lastZ               = null;
            List <float> filamentConsumption = new List <float>(partialFileInfo.Filament);

            do
            {
                token.ThrowIfCancellationRequested();

                // Read another line
                string line = await ReadLineFromEndAsync(reader);

                if (line == null)
                {
                    break;
                }
                bool gotNewInfo = false;

                // See what code to deal with
                Code code = new Code(line);
                if (code.Type == CodeType.GCode && partialFileInfo.Height == 0)
                {
                    if (code.MajorNumber == 90)
                    {
                        // G90 code (absolute positioning) implies we were in relative mode
                        inRelativeMode = true;
                        gotNewInfo     = true;
                    }
                    else if (inRelativeMode)
                    {
                        // G91 code (relative positioning) implies we were in absolute mode
                        inRelativeMode = (code.MajorNumber != 91);
                        gotNewInfo     = true;
                    }
                    else if (code.MajorNumber == 0 || code.MajorNumber == 1)
                    {
                        // G0/G1 is a move, see if there is a Z parameter present
                        // Users tend to place their own lift Z code at the end, so attempt to read two G0/G1 Z
                        // codes and check the height differene between them
                        CodeParameter zParam = code.Parameter('Z');
                        if (zParam != null && (code.Comment == null || !code.Comment.TrimStart().StartsWith("E")))
                        {
                            gotNewInfo = true;
                            if (lastZ == null)
                            {
                                lastZ = zParam;
                            }
                            else
                            {
                                float z = zParam;
                                if (lastZ - z > Settings.MaxLayerHeight)
                                {
                                    partialFileInfo.Height = z;
                                }
                                else
                                {
                                    partialFileInfo.Height = lastZ.Value;
                                }
                                break;
                            }
                        }
                    }
                }
                else if (code.Type == CodeType.Comment)
                {
                    gotNewInfo |= partialFileInfo.LayerHeight == 0 && FindLayerHeight(line, ref partialFileInfo);
                    gotNewInfo |= FindFilamentUsed(line, ref filamentConsumption);
                    // gotNewInfo |= partialFileInfo.GeneratedBy == "") && FindGeneratedBy(line, ref partialFileInfo);
                    gotNewInfo |= partialFileInfo.PrintTime == 0 && FindPrintTime(line, ref partialFileInfo);
                    gotNewInfo |= partialFileInfo.SimulatedTime == 0 && FindSimulatedTime(line, ref partialFileInfo);
                }

                if (!gotNewInfo && !lastLineHadInfo && IsFileInfoComplete(partialFileInfo))
                {
                    break;
                }
                lastLineHadInfo = gotNewInfo;
            }while (length - reader.Position < Settings.FileInfoReadLimit);

            partialFileInfo.Filament.Clear();
            foreach (float filament in filamentConsumption)
            {
                partialFileInfo.Filament.Add(filament);
            }

            if (lastZ != null && partialFileInfo.Height == 0)
            {
                partialFileInfo.Height = lastZ.Value;
            }
        }