Package: release.debian.org
Severity: normal
Tags: patch
X-Debbugs-CC: Tobias Frost <[email protected]>
User: [email protected]
Usertags: pu

I would like to fix a crash bug in the Fanuc post processor of FreeCAD
in Trixie, reported as important BTS report #1117850.  The issue has
already been addressed upstream and in unstable and testing.

This is the complete patch for my proposed update (also available in the
salsa git repo as branch pere/debian/trixie.  Note the
1100-cam-fanuc-post-fix.patch file is identical to the one already
applied in unstable.  I've tested the change on trixie, and the script
work as it should there.

A stable update to fix this is already approved by Tobias Frost in the
FreeCAD packaging team, see <URL: https://bugs.debian.org/1117850 >.

commit fcf0e49865baecf0cc89b0f2694a1b3d133e328f
Author: Petter Reinholdtsen <[email protected]>
Date:   Sun Mar 8 07:30:15 2026 +0100

    Trixie update to fix fanuc post processor.
    
    Patch fetched from upstream and already included in unstable and
    testing.
    
    Closes: #1117850

diff --git a/debian/changelog b/debian/changelog
index 8ea9084f5..38c2dd519 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+freecad (1.0.0+dfsg-8+deb13u1) trixie; urgency=medium
+
+  * Maintaner approvided upload.
+  * Get fanuc post processor working (Closes: #1117850).
+
+ -- Petter Reinholdtsen <[email protected]>  Sat, 07 Mar 2026 22:02:07 +0100
+
 freecad (1.0.0+dfsg-8) unstable; urgency=medium
 
   * Disable accidential added autopkgtest starttest, which was not ready.
diff --git a/debian/gbp.conf b/debian/gbp.conf
index 9f317df99..4e5f9a2a2 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -1,4 +1,4 @@
 [DEFAULT]
 pristine-tar = True
 sign-tags = true
-debian-branch = debian/unstable
+debian-branch = debian/trixie
diff --git a/debian/patches/1100-cam-fanuc-post-fix.patch 
b/debian/patches/1100-cam-fanuc-post-fix.patch
new file mode 100644
index 000000000..7f9d497a1
--- /dev/null
+++ b/debian/patches/1100-cam-fanuc-post-fix.patch
@@ -0,0 +1,610 @@
+Description: fix fanuc postprocessor
+Author: Petter Reinholdtsen <[email protected]>
+Bug: https://github.com/FreeCAD/FreeCAD/issues/27814
+Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1117850
+Origin: https://github.com/FreeCAD/FreeCAD/pull/27964
+Applied-Upstream: 
https://github.com/FreeCAD/FreeCAD/commit/b0f4ad4a142e35c0e12c2ff241aaa7e3b23c5fa2
+Last-Update: 2026-03-02
+
+commit 13c8babc1a63e1a656fb6559bff90cff58954375
+Author: Petter Reinholdtsen <[email protected]>
+Date:   Mon Mar 2 16:18:03 2026 +0100
+
+    CAM: Correct Fanuc post processor to work properly.
+    
+    Fixes crash problem, milling, drilling, tool changes, thread
+    tapping and get the post processor working as it should.
+    
+    This patch is tested on a Fanuc controller and sent upstream as
+    <URL: https://github.com/FreeCAD/FreeCAD/pull/27960 >
+    
+    Closes: #1117850
+
+diff --git a/src/Mod/CAM/Path/Post/scripts/fanuc_post.py 
b/src/Mod/CAM/Path/Post/scripts/fanuc_post.py
+index 2edc7abaf..15af728a1 100644
+--- a/src/Mod/CAM/Path/Post/scripts/fanuc_post.py
++++ b/src/Mod/CAM/Path/Post/scripts/fanuc_post.py
+@@ -1,3 +1,11 @@
++# SPDX-License-Identifier: LGPL-2.1-or-later
++
++"""
++
++CAM post processor for CNC machines with a Fanuc controller.
++
++"""
++
+ # ***************************************************************************
+ # *   Copyright (c) 2014 sliptonic <[email protected]>               *
+ # *   Copyright (c) 2021 shadowbane1000 <[email protected]>                 *
+@@ -29,8 +37,9 @@ import argparse
+ import datetime
+ import shlex
+ import os.path
++import Path.Base.Util as PathUtil
+ import Path.Post.Utils as PostUtils
+-import PathScripts.PathUtils as PathUtils
++from PathScripts import PathUtils
+ from builtins import open as pyopen
+ 
+ TOOLTIP = """
+@@ -46,6 +55,16 @@ import fanuc_post
+ fanuc_post.export(object,"/path/to/file.ncc","")
+ """
+ 
++# Preamble text will appear at the beginning of the GCODE output file.
++DEFAULT_PREAMBLE = """G17 G54 G40 G49 G80 G90 G94
++"""
++
++# Postamble text will appear following the last operation.
++DEFAULT_POSTAMBLE = """M05
++G17 G54 G90 G80 G40
++M30
++"""
++
+ now = datetime.datetime.now()
+ 
+ parser = argparse.ArgumentParser(prog="fanuc", add_help=False)
+@@ -57,14 +76,19 @@ parser.add_argument(
+     action="store_true",
+     help="don't pop up editor before writing output",
+ )
+-parser.add_argument("--precision", default="3", help="number of digits of 
precision, default=3")
++parser.add_argument("--precision", help="number of digits of precision, 
default=3 (mm) or 4 (in)")
+ parser.add_argument(
+     "--preamble",
+-    help='set commands to be issued before the first command, 
default="G17\nG90"',
++    help='set commands to be issued before the first command, default="'
++    + DEFAULT_PREAMBLE.replace("\n", "\\n")
++    + '"',
+ )
+ parser.add_argument(
+     "--postamble",
+-    help='set commands to be issued after the last command, default="M05\nG17 
G90\nM2"',
++    help="set commands to be issued after the last command, "
++    + 'default="'
++    + DEFAULT_POSTAMBLE.replace("\n", "\\n")
++    + '"',
+ )
+ parser.add_argument(
+     "--inches", action="store_true", help="Convert output for US imperial 
mode (G20)"
+@@ -82,6 +106,11 @@ parser.add_argument(
+     action="store_true",
+     help="suppress tool length offset (G43) following tool changes",
+ )
++parser.add_argument(
++    "--end-spindle-empty",
++    action="store_true",
++    help="place last tool in tool change carousel before postamble",
++)
+ 
+ TOOLTIP_ARGS = parser.format_help()
+ 
+@@ -98,6 +127,8 @@ OUTPUT_DOUBLES = (
+ COMMAND_SPACE = " "
+ LINENR = 100  # line number starting value
+ 
++END_SPINDLE_EMPTY = False
++
+ # These globals will be reflected in the Machine configuration of the project
+ UNITS = "G21"  # G21 for metric, G20 for us standard
+ UNIT_SPEED_FORMAT = "mm/min"
+@@ -112,16 +143,8 @@ PRECISION = 3
+ # rigid tapping.
+ tapSpeed = 0
+ 
+-# Preamble text will appear at the beginning of the GCODE output file.
+-PREAMBLE = """G17 G54 G40 G49 G80 G90
+-"""
+-
+-# Postamble text will appear following the last operation.
+-POSTAMBLE = """M05
+-G17 G54 G90 G80 G40
+-M6 T0
+-M2
+-"""
++PREAMBLE = DEFAULT_PREAMBLE
++POSTAMBLE = DEFAULT_POSTAMBLE
+ 
+ # Pre operation text will be inserted before every operation
+ PRE_OPERATION = """"""
+@@ -130,15 +153,33 @@ PRE_OPERATION = """"""
+ POST_OPERATION = """"""
+ 
+ # Tool Change commands will be inserted before a tool change
+-TOOL_CHANGE = """"""
++# Move to tool change Z position
++TOOL_CHANGE = """G28 G91 Z0
++"""
++
++# List of drill G codes where some parameters are required and their
++# required parameters.
++DRILL_OPERATION = ("G73", "G81", "G82", "G83", "G85")
++DRILL_PARAM_REQ = ("L", "P", "Q", "R", "Z")
++
++# The settings shared between methods
++PREAMBLE = None
++POSTAMBLE = None
+ 
+ 
+ def processArguments(argstring):
++    """
++    Apply default values and command line arguments before
++    processing commands.
++
++    """
+     global OUTPUT_HEADER
+     global OUTPUT_COMMENTS
+     global OUTPUT_LINE_NUMBERS
+     global SHOW_EDITOR
+     global PRECISION
++    global DEFAULT_PREAMBLE
++    global DEFAULT_POSTAMBLE
+     global PREAMBLE
+     global POSTAMBLE
+     global UNITS
+@@ -146,35 +187,66 @@ def processArguments(argstring):
+     global UNIT_FORMAT
+     global MODAL
+     global USE_TLO
++    global END_SPINDLE_EMPTY
+     global OUTPUT_DOUBLES
++    global LINENR
+ 
+     try:
+         args = parser.parse_args(shlex.split(argstring))
+         if args.no_header:
+             OUTPUT_HEADER = False
++        else:
++            OUTPUT_HEADER = True
+         if args.no_comments:
+             OUTPUT_COMMENTS = False
++        else:
++            OUTPUT_COMMENTS = True
+         if args.line_numbers:
+             OUTPUT_LINE_NUMBERS = True
++            LINENR = 100
++        else:
++            OUTPUT_LINE_NUMBERS = False
+         if args.no_show_editor:
+             SHOW_EDITOR = False
+-        print("Show editor = %d" % SHOW_EDITOR)
+-        PRECISION = args.precision
++        else:
++            SHOW_EDITOR = True
++        # print("Show editor = %s" % SHOW_EDITOR)  # Commented to reduce test 
noise
+         if args.preamble is not None:
+-            PREAMBLE = args.preamble
++            PREAMBLE = args.preamble.replace("\\n", "\n")
++        else:
++            PREAMBLE = DEFAULT_PREAMBLE
+         if args.postamble is not None:
+-            POSTAMBLE = args.postamble
++            POSTAMBLE = args.postamble.replace("\\n", "\n")
++        else:
++            POSTAMBLE = DEFAULT_POSTAMBLE
+         if args.inches:
+             UNITS = "G20"
+             UNIT_SPEED_FORMAT = "in/min"
+             UNIT_FORMAT = "in"
+             PRECISION = 4
++        else:
++            UNITS = "G21"
++            UNIT_SPEED_FORMAT = "mm/min"
++            UNIT_FORMAT = "mm"
++            PRECISION = 3
++        if args.precision:
++            PRECISION = int(args.precision)
+         if args.no_modal:
+             MODAL = False
++        else:
++            MODAL = True
+         if args.no_tlo:
+             USE_TLO = False
++        else:
++            USE_TLO = True
+         if args.no_axis_modal:
+             OUTPUT_DOUBLES = True
++        else:
++            OUTPUT_DOUBLES = False
++        if args.end_spindle_empty:
++            END_SPINDLE_EMPTY = True
++        else:
++            END_SPINDLE_EMPTY = False
+ 
+     except Exception:
+         return False
+@@ -198,41 +270,56 @@ def export(objectslist, filename, argstring):
+             )
+             return None
+ 
+-    print("postprocessing...")
++    # print("postprocessing...")  # Commented to reduce test noise
+     gcode = ""
+ 
++    gcode += "%\n"
++
+     # write header
+     if OUTPUT_HEADER:
+-        gcode += "%\n"
+-        gcode += ";\n"
++        # Get current version info
++        major = int(FreeCAD.ConfigGet("BuildVersionMajor"))
++        minor = int(FreeCAD.ConfigGet("BuildVersionMinor"))
++
++        # the filename variable always contain "-", use more relevant
++        # information
++        job = PathUtils.findParentJob(objectslist[0])
++        if job:
++            body, job = job.FullName.split("#")
++        else:
++            # Workaround for the TestFanucPost code, where there is no
++            # job returned by findParentJob
++            body, job = ("FREECAD-FILENAME-GOES-HERE", "JOB-NAME-GOES-HERE")
++        gcode += "(" + body.upper() + ", " + job.upper() + ")\n"
+         gcode += (
+-            os.path.split(filename)[-1]
+-            + " ("
+-            + "FREECAD-FILENAME-GOES-HERE"
+-            + ", "
+-            + "JOB-NAME-GOES-HERE"
+-            + ")\n"
++            linenumber() + "(POST PROCESSOR: FANUC USING FREECAD %d.%d" % 
(major, minor) + ")\n"
+         )
+-        gcode += linenumber() + "(" + filename.upper() + ",EXPORTED BY 
FREECAD!)\n"
+-        gcode += linenumber() + "(POST PROCESSOR: " + __name__.upper() + ")\n"
+         gcode += linenumber() + "(OUTPUT TIME:" + str(now).upper() + ")\n"
+ 
+     # Write the preamble
+     if OUTPUT_COMMENTS:
+         gcode += linenumber() + "(BEGIN PREAMBLE)\n"
+-    for line in PREAMBLE.splitlines(False):
++    for line in PREAMBLE.splitlines():
+         gcode += linenumber() + line + "\n"
+     gcode += linenumber() + UNITS + "\n"
+ 
+     for obj in objectslist:
+ 
++        # to stay compatible with FreeCAD 1.0
++        def activeForOp(obj):
++            # The activeForOp method is available since 2025-05-04 /
++            # commit 1e87d8e6681b755b9757f94b1201e50eb84b28a2
++            if hasattr(PathUtil, "activeForOp"):
++                return PathUtil.activeForOp(obj)
++            if hasattr(obj, "Active"):
++                return obj.Active
++            if hasattr(obj, "Base") and hasattr(obj.Base, "Active"):
++                return obj.Base.Active
++            return True
++
+         # Skip inactive operations
+-        if hasattr(obj, "Active"):
+-            if not obj.Active:
+-                continue
+-        if hasattr(obj, "Base") and hasattr(obj.Base, "Active"):
+-            if not obj.Base.Active:
+-                continue
++        if not activeForOp(obj):
++            continue
+ 
+         # do the pre_op
+         if OUTPUT_COMMENTS:
+@@ -241,13 +328,26 @@ def export(objectslist, filename, argstring):
+         for line in PRE_OPERATION.splitlines(True):
+             gcode += linenumber() + line
+ 
++        # to stay compatible with FreeCAD 1.0
++        def coolantModeForOp(obj):
++            # The coolantModeForOp method is available since
++            # 2025-05-04 / commit
++            # 1e87d8e6681b755b9757f94b1201e50eb84b28a2
++            if hasattr(PathUtil, "coolantModeForOp"):
++                return PathUtil.coolantModeForOp(obj)
++            if (
++                hasattr(obj, "CoolantMode")
++                or hasattr(obj, "Base")
++                and hasattr(obj.Base, "CoolantMode")
++            ):
++                if hasattr(obj, "CoolantMode"):
++                    return obj.CoolantMode
++                else:
++                    return obj.Base.CoolantMode
++            return "None"
++
+         # get coolant mode
+-        coolantMode = "None"
+-        if hasattr(obj, "CoolantMode") or hasattr(obj, "Base") and 
hasattr(obj.Base, "CoolantMode"):
+-            if hasattr(obj, "CoolantMode"):
+-                coolantMode = obj.CoolantMode
+-            else:
+-                coolantMode = obj.Base.CoolantMode
++        coolantMode = coolantModeForOp(obj)
+ 
+         # turn coolant on if required
+         if OUTPUT_COMMENTS:
+@@ -273,12 +373,18 @@ def export(objectslist, filename, argstring):
+                 gcode += linenumber() + "(COOLANT OFF:" + coolantMode.upper() 
+ ")\n"
+             gcode += linenumber() + "M9" + "\n"
+ 
++    if END_SPINDLE_EMPTY:
++        if OUTPUT_COMMENTS:
++            gcode += "(BEGIN MAKING SPINDLE EMPTY)\n"
++        gcode += linenumber() + "M05\n"
++        for line in TOOL_CHANGE.splitlines(True):
++            gcode += linenumber() + line
++        gcode += linenumber() + "M6 T0\n"
+     # do the post_amble
+     if OUTPUT_COMMENTS:
+         gcode += "(BEGIN POSTAMBLE)\n"
+-    for line in POSTAMBLE.splitlines(True):
+-        gcode += linenumber() + line
+-    gcode += "%\n"
++    for line in POSTAMBLE.splitlines():
++        gcode += linenumber() + line + "\n"
+ 
+     if FreeCAD.GuiUp and SHOW_EDITOR:
+         dia = PostUtils.GCodeEditorDialog()
+@@ -291,7 +397,7 @@ def export(objectslist, filename, argstring):
+     else:
+         final = gcode
+ 
+-    print("done postprocessing.")
++    # print("done postprocessing.")  # Commented to reduce test noise
+ 
+     if not filename == "-":
+         gfile = pyopen(filename, "w")
+@@ -311,6 +417,8 @@ def linenumber():
+ 
+ def parse(pathobj):
+     global PRECISION
++    global DRILL_OPERATION
++    global DRILL_PARAM_REQ
+     global MODAL
+     global OUTPUT_DOUBLES
+     global UNIT_FORMAT
+@@ -398,6 +506,7 @@ def parse(pathobj):
+         for index, c in enumerate(commands):
+ 
+             outstring = []
++            outsuffix = []
+             command = c.Name
+             if index + 1 == len(commands):
+                 nextcommand = ""
+@@ -415,83 +524,100 @@ def parse(pathobj):
+                 if command == "G0":
+                     continue
+ 
+-            # if it's a tap, we rigid tap, so don't start the spindle yet...
++            # If tool a tap, we will thread tap, so stop the spindle
++            # for now as there is no point in starting it to stop it
++            # in the G74/G84 operation after S29.  This only trigger
++            # when pathobj is a ToolController.
+             if command == "M03" or command == "M3":
+-                if pathobj.Tool.ToolType == "Tap":
++                if (
++                    hasattr(pathobj, "Tool")
++                    and getattr(pathobj.Tool, "ShapeType", "").lower() == 
"tap"
++                ):
+                     tapSpeed = int(pathobj.SpindleSpeed)
+                     continue
+ 
+-            # convert drill cycles to tap cycles if tool is a tap
+-            if command == "G81" or command == "G83":
+-                if (
+-                    hasattr(pathobj, "ToolController")
+-                    and pathobj.ToolController.Tool.ToolType == "Tap"
+-                ):
+-                    command = "G84"
+-                    out += linenumber() + "G95\n"
+-                    paramstring = ""
+-                    for param in ["X", "Y"]:
+-                        if param in c.Parameters:
+-                            if (
+-                                (not OUTPUT_DOUBLES)
+-                                and (param in currLocation)
+-                                and (currLocation[param] == 
c.Parameters[param])
+-                            ):
+-                                continue
+-                            else:
+-                                pos = Units.Quantity(c.Parameters[param], 
FreeCAD.Units.Length)
+-                                paramstring += (
+-                                    " "
+-                                    + param
+-                                    + format(
+-                                        float(pos.getValueAs(UNIT_FORMAT)),
+-                                        precision_string,
+-                                    )
+-                                )
+-                    if paramstring != "":
+-                        out += linenumber() + "G00" + paramstring + "\n"
+-
+-                    if "S" in c.Parameters:
+-                        tapSpeed = int(c.Parameters["S"])
+-                    out += "M29 S" + str(tapSpeed) + "\n"
+-
+-                    for param in ["Z", "R"]:
+-                        if param in c.Parameters:
+-                            if (
+-                                (not OUTPUT_DOUBLES)
+-                                and (param in currLocation)
+-                                and (currLocation[param] == 
c.Parameters[param])
+-                            ):
+-                                continue
+-                            else:
+-                                pos = Units.Quantity(c.Parameters[param], 
FreeCAD.Units.Length)
+-                                paramstring += (
+-                                    " "
+-                                    + param
+-                                    + format(
+-                                        float(pos.getValueAs(UNIT_FORMAT)),
+-                                        precision_string,
+-                                    )
++            # Handle thread tapping cycles.  Uses rigid tapping.
++            # This only trigger when pathobj is a Operation.
++            if command == "G74" or command == "G84":
++                pitch_mm = float(c.Parameters["F"])
++                # Convert pitch to inches if needed
++                if UNITS == "G20":  # imperial
++                    pitch = pitch_mm / 25.4
++                else:
++                    pitch = pitch_mm
++                paramstring = ""
++                for param in ["X", "Y"]:
++                    if param in c.Parameters:
++                        if (
++                            (not OUTPUT_DOUBLES)
++                            and (param in currLocation)
++                            and (currLocation[param] == c.Parameters[param])
++                        ):
++                            continue
++                        else:
++                            pos = Units.Quantity(c.Parameters[param], 
FreeCAD.Units.Length)
++                            paramstring += (
++                                " "
++                                + param
++                                + format(
++                                    float(pos.getValueAs(UNIT_FORMAT)),
++                                    precision_string,
+                                 )
+-                    # in this mode, F is the distance per revolution of the 
thread (pitch)
+-                    # P is the dwell time in seconds at the bottom of the 
thread
+-                    # Q is the peck depth of the threading operation
+-                    for param in ["F", "P", "Q"]:
+-                        if param in c.Parameters:
+-                            value = Units.Quantity(c.Parameters[param], 
FreeCAD.Units.Length)
++                            )
++                if paramstring != "":
++                    out += linenumber() + "G00" + paramstring + "\n"
++
++                if "S" in c.Parameters:
++                    tapSpeed = int(c.Parameters["S"])
++                out += "M29 S" + str(tapSpeed) + "\n"
++
++                for param in ["Z", "R"]:
++                    if param in c.Parameters:
++                        if (
++                            (not OUTPUT_DOUBLES)
++                            and (param in currLocation)
++                            and (currLocation[param] == c.Parameters[param])
++                        ):
++                            continue
++                        else:
++                            pos = Units.Quantity(c.Parameters[param], 
FreeCAD.Units.Length)
+                             paramstring += (
+                                 " "
+                                 + param
+                                 + format(
+-                                    float(value.getValueAs(UNIT_FORMAT)),
++                                    float(pos.getValueAs(UNIT_FORMAT)),
+                                     precision_string,
+                                 )
+                             )
+ 
+-                    out += linenumber() + "G84" + paramstring + "\n"
+-                    out += linenumber() + "G80\n"
+-                    out += linenumber() + "G94\n"
+-                    continue
++                # Calculate feed rate as distance per minute
++                if tapSpeed is not None:
++                    feed_rate = pitch * tapSpeed
++                    speed = Units.Quantity(feed_rate, UNIT_SPEED_FORMAT)
++                    paramstring += " F" + format(
++                        float(speed.getValueAs(UNIT_SPEED_FORMAT)), 
precision_string
++                    )
++                else:
++                    # No spindle speed found, output pitch as F
++                    paramstring += " F" + format(pitch, precision_string)
++
++                # P is the dwell time in seconds at the bottom of the thread
++                # Q is the peck depth of the threading operation
++                for param in ["P", "Q"]:
++                    if param in c.Parameters:
++                        value = Units.Quantity(c.Parameters[param], 
FreeCAD.Units.Length)
++                        paramstring += (
++                            " "
++                            + param
++                            + format(
++                                float(value.getValueAs(UNIT_FORMAT)),
++                                precision_string,
++                            )
++                        )
++
++                out += linenumber() + command + paramstring + "\n"
++                out += linenumber() + "G80\n"  # End tapping cycle
++                continue
+ 
+             outstring.append(command)
+ 
+@@ -504,7 +630,7 @@ def parse(pathobj):
+             if command == "G80" and lastcommand == nextcommand:
+                 continue
+ 
+-            if c.Name[0] == "(" and not OUTPUT_COMMENTS:  # command is a 
comment
++            if c.Name.startswith("(") and not OUTPUT_COMMENTS:  # command is 
a comment
+                 continue
+ 
+             # Now add the remaining parameters in order
+@@ -540,7 +666,11 @@ def parse(pathobj):
+                         if (
+                             (not OUTPUT_DOUBLES)
+                             and (param in currLocation)
+-                            and (currLocation[param] == c.Parameters[param])
++                            and currLocation[param] == c.Parameters[param]
++                            and (
++                                command not in DRILL_OPERATION
++                                or (command in DRILL_OPERATION and param not 
in DRILL_PARAM_REQ)
++                            )
+                         ):
+                             continue
+                         else:
+@@ -575,14 +705,14 @@ def parse(pathobj):
+             # Check for Tool Change:
+             if command == "M6":
+                 # stop the spindle
+-                out += linenumber() + "M5\n"
++                out += linenumber() + "M05\n"
+                 for line in TOOL_CHANGE.splitlines(True):
+                     out += linenumber() + line
+ 
+                 # add height offset
+                 if USE_TLO:
+-                    tool_height = "\nG43 H" + str(int(c.Parameters["T"]))
+-                    outstring.append(tool_height)
++                    outsuffix.append("G91 G0 G43 G54 Z-[#[2000+#4120]] 
H#4120")
++                    outsuffix.append("G90")
+ 
+             if command == "message":
+                 if OUTPUT_COMMENTS is False:
+@@ -596,9 +726,11 @@ def parse(pathobj):
+                     outstring.insert(0, (linenumber()))
+ 
+                 # append the line to the final output
+-                for w in outstring:
+-                    out += w.upper() + COMMAND_SPACE
++                out += COMMAND_SPACE.join(outstring).upper()
+                 out = out.strip() + "\n"
++            if len(outsuffix) >= 1:
++                for line in outsuffix:
++                    out += linenumber() + line + "\n"
+ 
+         return out
+ 
diff --git a/debian/patches/series b/debian/patches/series
index 52ac756fa..0db094fce 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -11,3 +11,4 @@
 1091-freecad-spelling-others.patch
 1110-GL_MULTISAMPLE.patch
 2080-force-xcb-on-wayland.patch
+1100-cam-fanuc-post-fix.patch

-- 
Happy hacking
Petter Reinholdtsen

Reply via email to