From 69a8ec5461d84be2ff175df58eb897b56efd1d07 Mon Sep 17 00:00:00 2001 From: Ronoaldo JLP Date: Sun, 7 Apr 2024 16:49:31 -0300 Subject: [PATCH] bugfix: fix temperature with a floating point. The start gcode macros in recent versions of Cura format the print temperature as a floating point. Other temperature commands in the gcode don't have such behavior. On Finder (version 1?) with the more recent firmware, this causes the temperature to be the fixed to start at 185C, which appears to be the "default start temperature" or some rounding error when reading the floating point temperature. This commit fixes that by parsing the 'M104 SXXX' commands, and changing the temperature by converting it to integer. This also allows the temperature to be embedded to the .gx file header. I took the opportunity to move the parsing commands into the gx.py script, as a way to potentially easy the proccess to make this a standalone script that can potentially be used by other slicers/software. Fixes #21 Related to #2 and #16 --- Makefile | 5 +++- plugins/GXWriter/GXWriter.py | 38 ++++------------------------ plugins/GXWriter/gx.py | 43 +++++++++++++++++++++++++++++++ plugins/GXWriter/gx_test.py | 49 ++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 34 deletions(-) create mode 100644 plugins/GXWriter/gx_test.py diff --git a/Makefile b/Makefile index 8d221b0..13e329a 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,10 @@ plugins/FlashforgeFinderIntegration/printer/defs/finder.def.json: git submodule init git submodule update -release: build +test: + find plugins -type f -iname '*_test.py' | xargs -I{} python3 {} + +release: build test if [ x"$(VERSION)" = x"master" ] ; then echo "Unable to release from master. Use make VERSION=X.Y.Z" ; exit 1; fi git tag v$(VERSION) git push --tags diff --git a/plugins/GXWriter/GXWriter.py b/plugins/GXWriter/GXWriter.py index f2bd097..c811a35 100644 --- a/plugins/GXWriter/GXWriter.py +++ b/plugins/GXWriter/GXWriter.py @@ -14,10 +14,9 @@ from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") -import re from io import StringIO, BufferedIOBase from typing import cast, List -from . import gx +from .gx import GX qt_version = 6 try: @@ -26,17 +25,6 @@ qt_version = 5 from PyQt5 import QtGui, QtCore -# Helper function that extracts values from gcode to add to the binary header. -def getValue(line, key, default=None): - if key not in line: - return default - else: - subPart = line[line.find(key) + len(key):] - m = re.search('^-?[0-9]+\\.?[0-9]*', subPart) - try: - return float(m.group(0)) - except: - return default # Implements a MeshWriter that creates the xgcode header before the gcode # content. @@ -77,30 +65,14 @@ def write(self, stream, nodes: List[SceneNode], mode = MeshWriter.OutputMode.Bin def modify(self, gcode): try: # Initialize GX header variables - g = gx.GX() - g.gcode = gcode.encode('latin-1') - # Parse values from original gcode - self._parse_gcode_info(g, gcode) - self._createSnapshot(g) - return g.encode() + gx = GX.from_gcode(gcode) + # Add snapshot image from Cura + self._createSnapshot(gx) + return gx.encode() except Exception: Logger.logException("w", "\n*** Failed to create gx file, defaulting to write regular gcode!!! ***\n") return gcode.encode('latin-1') - def _parse_gcode_info(self, gx, gcode): - for line in gcode.split("\n"): - if line.startswith(';TIME:'): - gx.print_time = int(getValue(line, ';TIME:', 0)) - if line.startswith(';Filament used:'): - f = float(line.split(':')[1].split('m')[0].strip()) - f = f*100 - gx.filament_usage = int(f) - if line.startswith(';Layer height:'): - f = float(getValue(line, ';Layer height:', 0)) - f = f*1000 - gx.layer_height = int(f) - Logger.log("i", "Updated values from struct =>", vars(gx)) - def _createSnapshot(self, g, *args): Logger.log("i", "Creating thumbnail image ...") try: diff --git a/plugins/GXWriter/gx.py b/plugins/GXWriter/gx.py index 30008eb..ce887e2 100755 --- a/plugins/GXWriter/gx.py +++ b/plugins/GXWriter/gx.py @@ -6,6 +6,19 @@ import struct import base64 +import re + +# Helper function that extracts values from gcode to add to the binary header. +def getValue(line, key, default=None): + if key not in line: + return default + else: + subPart = line[line.find(key) + len(key):] + m = re.search('^-?[0-9]+\\.?[0-9]*', subPart) + try: + return float(m.group(0)) + except: + return default class GX(object): """ @@ -103,6 +116,36 @@ def _encode(self): buff+= self.gcode return buff + @staticmethod + def from_gcode(gcode): + gx = GX() + gx.gcode = gcode.encode('latin-1') + for line in gcode.split("\n"): + if line.startswith(';TIME:'): + gx.print_time = int(getValue(line, ';TIME:', 0)) + if line.startswith(';Filament used:'): + f = float(line.split(':')[1].split('m')[0].strip()) + f = f*100 + gx.filament_usage = int(f) + if line.startswith(';Layer height:'): + f = float(getValue(line, ';Layer height:', 0)) + f = f*1000 + gx.layer_height = int(f) + if line.startswith('M104 S'): + # Fixes temperature if expressed in float (195.0 -> 195) + args = [] + for a in line.split(' '): + if a.startswith('S'): + t = float(a.replace('S', '')) + t = int(t) + a = "S{}".format(t) + if gx.print_temperature <= 0.00: + # Stores the first temperature to the xgcode header + gx.print_temperature = t + args.append(a) + gx.gcode = gx.gcode.replace(line.encode(), ' '.join(args).encode()) + return gx + # base64 --wrap=80 testdata/cura.bmp | xclip -sel clip _SAMPLE_BMP = base64.decodebytes(""" Qk12OAAAAAAAADYAAAAoAAAAUAAAADwAAAABABgAAAAAAEA4AADDDgAAww4AAAAAAAAAAAAAnJycnJyc diff --git a/plugins/GXWriter/gx_test.py b/plugins/GXWriter/gx_test.py new file mode 100644 index 0000000..21a1dbc --- /dev/null +++ b/plugins/GXWriter/gx_test.py @@ -0,0 +1,49 @@ +import unittest +from gx import GX + +test_gcode = """;FLAVOR:Marlin +;TIME:1066 +;Filament used: 0.681442m +;Layer height: 0.12 +;MINX:-14 +;MINY:-14 +;MINZ:0.2 +;MAXX:14 +;MAXY:14 +;MAXZ:10.04 +;TARGET_MACHINE.NAME:Flashforge Finder +;Generated with Cura_SteamEngine 5.6.0 +M82 ;absolute extrusion mode +M140 S0 +M104 S195.0 T0 +M104 S0 T1 +M107 +G90 +G28 +M132 X Y Z A B +G1 Z50.00 F400 +G161 X Y F3300 +M6 T0 +M907 X100 Y100 Z40 A80 B20 +M108 T0 +G1 Z.20 F400 +G92 E0 +G92 E0 +G1 F1800 E-1.3 +;LAYER_COUNT:83 +;LAYER:0 +M106 S255 +G0 F3000 X14 Y9.314 Z0.2""" + +class TestGX(unittest.TestCase): + + def test_from_gcode(self): + gx = GX.from_gcode(test_gcode) + result = gx.encode().decode('latin1') + print("Resulting gcode: ", result) + self.assertFalse(' S195.0 ' in result) + self.assertTrue(' S195 ' in result) + self.assertTrue('xgcode' in result) + +if __name__ == '__main__': + unittest.main()