#######################################################################
###                  DNC and CAM Utility Programs                   ###
#######################################################################
These programs are useful for making, sending, and receiving CAM files
to and from a CNC control. Particularly ancient controls without macros,
subroutines, or general math processing. There are also programs for
modifying g-code files, extracting the travel limits from a g-code file,
and removing dis-allowed code from a g-code file.

dnc_renumber.py
        Process a g-code file, renumbering the lines as it goes. Drops
        existing line numbers, and renumbers ALL g-code lines, except
        O-word and "%" lines. Set the line number offset, and the
        roll-over point for those controls with maximum line numbers.

dnc_stats.py
        Compute various statistics of a g-code file. Mostly, find the
        min and max X, Y, Z values for each tool, in order. Reports
        the max and min coordinates for each tool, so an operator can
        work out if tools stick out far enough _before_ running the
        code.

dnc_strip.py
        Strip all comments, line numbers, etc. from a g-code file for
        those controls that can't handle such stuff in a DNC file.
        Specifically, note that Fadal controls won't accept O-words,
        line numbers, or comments in a program being drip-fed to the
        control.

dnc_xform.py
        Offset or scale all the X, Y, and/or Z values in a g-code file.
        Can also swap spindle speed and feed rate commands. The spindle
        and feed replacements are matching the spindle and feed rate,
        not the tool number! Can be very helpful for modifying a g-code
        file from one machine to another (different max spindle, max
        feed, etc.). Can also be used to mirror or offset code.

fadal_post.py
mx3_post.py
        Post-processors for FreeCAD for Fadal and Yasnac MX-3 controls.
        Python scripts, so should be reasonable to modify and update.

pydnc.py
        Python DNC script. Sends a file to a serial port using pyserial
        library for the serial port communications. Set the baud,
        parity, byte size, etc. with command-line settings. Can also pad
        the end of the file for those controls that need it (e.g. MX-3),
        translate the EOL character to/from CR-LF or LF. Also checks for
        XOFF after _every_ character sent, for those controls that use
        XOFF for flow control. Will also add DC2, DC4 codes for those
        controls that want it (e.g. Fadal).
        
plot_gcode.py
        Convert g-code file to positions for plotting with gnuplot.
        Input is a g-code file, output is a long series of x,y,z,mode
        lines for each move in the g-code file. The mode is taken from
        the currently active motion mode (0, 1, 2, 3) for each move. The
        mode number has 1 added to the number for plotting in gnuplot,
        as line color 0 is special.

        Note that coordinate systems, offsets, etc. are ignored
        currently. No conversion of arcs to line segments, so arcs are
        currently displayed as lines from start to end. Tool changes
        introduce blank lines, which break the lines in the plot.

        Plot locations with gnuplot (or other package). Example gnuplot
        transcript-
  gnuplot> set xlabel 'X'
  gnuplot> set ylabel 'Y'
  gnuplot> set zlabel 'Z'
  gnuplot> set title 'G Code Path'
  gnuplot> unset key
  gnuplot> plot 'zap' u 1:2:4 w l lc variable           # 2-d X,Y only
  gnuplot> splot 'zap' u 1:2:3:4 w l lc variable        # 3-d lines
  gnuplot> quit

cam_macros.py
        Python pre-processor to make a DNC-ready g-code-only file from a
        source file with g-code, macros, and setup comments. The macros
        allow a higher level of cam programming than straight
        hand-coding the coordinates. With a CAD program that can provide
        a consistent set of x, y, z coordinates for corners, the macros
        can be used as a CAM programming language for 2.5-D cutting.

        Create the source file with embedded setup comments
        starting with "#" - these comments must be the whole line!
        Embedded g-code does not have any particular marker - just enter
        g-code as it should be used. Macros start a line, and are the
        only item on a line - do not try to mix g-code or macros on the
        same line. Macro tokens take a list of parameters or other
        specific format; see below for the format for each token.

        No recursion is supported in this script- macros inside macros
        are not allowed, although they could be supported by embedding
        macro calls in a subroutine macro, and then rerunning the script
        on the output of the first run. Possibly embed the cam_macro.py
        call in a while loop in a shell script that runs the macro
        expansion to idempotence....

        This script takes input from stdin, and outputs to stdout and
        stderr. G-code output is on stdout, and notifications and setup
        comments (those lines starting with "#") are on stderr. Typical
        use:
        [gungnir.local] cam_macros.py < source_file > dnc_gcode 2> setup_notes

  Current tokens recognized as macros-
  NIBBLE_X
        NIBBLE_X Xxs,xe Yys,ye Sdelta
        NIBBLE_X X-8.0,-3.942 Y-0.2765,+0.2765 S0.100
                Nibble along X axis, from xs to xe in steps of at most
                delta. Each nibble runs from ys to ye. Use careful
                choice of start and end to implement climb or
                conventional milling.
  NIBBLE_Y
        NIBBLE_Y Xxs,xe Yys,ye Sdelta
        NIBBLE_Y X-12.410,-11.660 Y+0.2765,+0.5290 S0.100
                Nibble along Y axis, from ys to ye in steps of at most
                delta. Each nibble runs from xs to xe. Use careful
                choice of start and end to implement climb or
                conventional milling.
  PERIMETER
        PERIMETER Ddiameter L
        xxxx,yyyy[,zzzz]
        nan for coordinate means skip....
        END
                Run around a perimeter, in order. Code with individual
                points on each line (1 per line), ending with "END" on a
                line. Profile is only closed if start point added at end
                of list. Any coordinate entered as "nan" will be treated
                as the same as the last used coordinate. Z values
                optional on all lines, but only added if entered. X and
                Y coordinates needed for each line, even if Y is nan.

                If present, the D token specifies a tool diameter, and the
                perimeter coordinates are offset by the tool radius
                (diameter/2). The "L" token flips the side of compensation
                to the left, as viewed moving along the coordinates.
                Without the "L" token, compensation moves the tool to the
                right. Compensation should be correct for any angles and
                radius, although small areas which do not fit the tool may
                cause unexpected results. A perimeter which cannot fit the
                tool could cause incorrect or unusable tool paths!
  SUB
        SUB Zzs,ze Sdelta
        g-code
        g-code
        .
        .
        .
        END
                Repeat a chunk of g-code once for each z level between
                zs and ze, tepping down by no more than delta. The
                entire chunk of code until END is repeated at each Z
                level. This is very similar to calling a
                subroutine in most controls, but can be used in those
                crippled controls without subroutines or macros. No
                provision for expanding macros inside the subroutine;
                perhaps run cam_macros.py multiple times.
                
                If set ramp, then the first move of the subroutine will
                have a Z move added. If noramp is set, then a G1 Z move
                will be added before the first move of the subroutine.
                By setting "ramp" and carefully choosing the first
                subroutine move, a nice ramp down may be obtained.

                Also, can replace Z on the SUB line with any combination
                of X, Y, and Z to iterate over those axes. Each axis
                gets a start and end value, and the iteration will move
                over all axes each step. Number of steps is rounded up
                from the maximum step axis. All axes use the same max
                delta step, and all axes iterate in the same number of
                steps from start to end.

                Note that each line of the subroutine is checked for
                fields "{x}", "{y}", and "{z}". All such fields are
                replaced with the current x, y, and z computed position
                for the current iteration of the subroutine. If the
                subroutine is not iterating over an axis, the current
                value will always be 0.0.
  DEF
        DEF label
        g-code
        g-code
        .
        .
        .
        END
                Create a subroutine with name "label" for future use
                with CALL. Does not insert the code at the definition,
                and definition must precede the CALL!
  CALL
        CALL label
                Insert a copy of the named subroutine at this location.
                The routine is inserted with no changes, exactly once
                per CALL.
  HELIX
        HELIX Xx.xxxx Yy.yyyy Zz_start,z_end Sdelta Ddiameter Rradius N
        HELIX X-7.9000 Y0. Z0.00,-0.500 d0.0625 r0.1
                Radius is OUTER radius of helix, diameter is for tool offset
                (to inside).
                Delta is max step in Z per revolution. Adds extra
                revolution at end at final depth. If flag N is set, do
                NOT move to the center at the end. Default is to move to
                the center at the end of the helix, like a hole has been
                cut.
  SLOT
        SLOT Xxs,xe Yys,ye Zzs,ze Rradius Sz_step C
                C is a flag for climb milling, CCW around slot and arcs.
                Cut a slot from xs,ys to xe,ye at Z levels zs to ze in
                steps no larger than z_step. Slot cut with radius; if
                radius is 0 the slot will only move back and forth at
                constant Z.
  RAMP
        RAMP Xxs,xe Yys,ye Zzs,ze Rradius Sz_step C
                C is a flag for climb milling, CCW around slot
                Cut a slot from xs,ys to xe,ye at Z levels zs to ze in
                steps no larger than z_step. Slot cut with radius; if
                radius is 0 the slot will only move back and forth. This
                is different from SLOT in that the Z move is done over first
                straight leg of the slot, then around arc, back leg,
                second arc at constant Z. Thus, ramps down into material
                then cuts around rest of perimeter of slot. If used
                with radius 0, ramps down to xe,ye and then cuts back to
                xs,ys at constant z, then ramps down again.
  TOOL
        TOOL number
                Tool change to tool "number". If g43 set, adds move to
                ztool with G43 H after tool change for setting tool
                offset. If g53 set, adds G0 G53 Z0. before M6 to move
        existing N### blocks from the output.
        SET COMMENT - turn on _all_ comments; leave g-code comments, and
          add macro expansion comments
        SET ARC2LINE - convert G2, G3 moves into G1 with line segments
        SET ARCP - set precision for converting arcs to lines
        SET ARCS - stop converting arcs to line segments
        SET RAMP - add Z to first line of subroutine, so ramp down
        SET NORAMP - move in Z before the first line of a repeated
          subroutine



#### GNUPLOT as a toolpath viz tool
############
So, process the g-code file to a set of positions and line color specs.
Then, can plot the lines with gnuplot with output terminals of X windows
DEC sixel graphics, acsii terminal, VT100, etc., etc.

Current processing of the g-code file as a starting example- plot_gcode.py
Used as-
  gettings@laptop:~/projects/Thompson/CNC$ ~/devel/cam/plot_gcode.py < Thompson.Op1.dnc > zap

gnuplot> plot 'zap' u 1:2:4 w l lc variable
gnuplot> splot 'zap' u 1:2:3:4 w l lc variable
gnuplot> set xlabel 'X'
gnuplot> set ylabel 'Y'
gnuplot> set zlabel 'Z'
gnuplot> set title 'G Code Path'
gnuplot> replot
gnuplot> unset key
gnuplot> replot
gnuplot> quit

So, now can add option to cncterm.py to process through the loaded
g-code file, open a pipe to a gnuplot process, and plot the positions
with line types for each style of move.

Still need to develop code to process G2, G3 arcs to line segments,
which could be useful for macro processing system, since can offset the
line segments with current perimeter option.

So, xterm -ti 340 will let you use sixel graphics in xterm, so can play
with sixel output for an inline graphics plot over ssh lines, etc. No X
required on server side. Nice.

Not sure how to verify how many pixels can be used in a sixel image;
default is 640x480, and that should match the actual display size of our
serial console emulators. Can set size of the canvas for gnuplot, etc.
when running in a pipe. Perhaps run some tests of general gnuplot on the
serial terminal connected to the kneemill beaglebone.

Example using leyentry to set key with line types
splot 'zap' u 1:2:3:4 w l lc variable notitle,
  keyentry w l lc 1 title 'G0',
  keyentry w l lc 2 t 'G1',
  keyentry w l lc 3 t 'G2',
  keyentry w l lc 4 t 'G3'

