public void ParseG29() { DuetAPI.Commands.Code code = new DuetControlServer.Commands.Code("G29 S1 ; load heightmap"); Assert.AreEqual(CodeType.GCode, code.Type); Assert.AreEqual(29, code.MajorNumber); Assert.AreEqual(null, code.MinorNumber); Assert.AreEqual(1, code.Parameters.Count); Assert.AreEqual('S', code.Parameters[0].Letter); Assert.IsTrue(code.Parameter('S', 0) == 1); }
/// <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); }
/// <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); } }
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; } }
/// <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) { Code code = new Code(); CodeParserBuffer codeParserBuffer = new CodeParserBuffer(Settings.FileBufferSize, true); bool inRelativeMode = false, lastCodeHadInfo = false, gotNewInfo = false; long fileReadLimit = Math.Min(Settings.FileInfoReadLimitHeader + Settings.FileBufferSize, reader.BaseStream.Length); while (codeParserBuffer.GetPosition(reader) < fileReadLimit) { Program.CancellationToken.ThrowIfCancellationRequested(); if (!await DuetAPI.Commands.Code.ParseAsync(reader, code, codeParserBuffer)) { continue; } 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(code.Comment, ref partialFileInfo); gotNewInfo |= FindFilamentUsed(code.Comment, ref partialFileInfo); gotNewInfo |= string.IsNullOrEmpty(partialFileInfo.GeneratedBy) && FindGeneratedBy(code.Comment, ref partialFileInfo); gotNewInfo |= (partialFileInfo.PrintTime == null) && FindPrintTime(code.Comment, ref partialFileInfo); gotNewInfo |= (partialFileInfo.SimulatedTime == null) && FindSimulatedTime(code.Comment, ref partialFileInfo); } // Is the file info complete? if (!gotNewInfo && !lastCodeHadInfo && IsFileInfoComplete(partialFileInfo)) { break; } lastCodeHadInfo = gotNewInfo; code.Reset(); } }