########################### Virtual NC Controller ############################
#                                                                            #
# Copyright (c) 1999/2000/2001/2002/2003/2004/2005/2006, UGS PLM Solutions.  #
#                                                                            #
##############################################################################
#                       V N C _ C O M M O N _ V 3 5 2 . T C L
##############################################################################
#
# DESCRIPTION
#
#   This file contains handlers for incremental VNC conversion.
#
##############################################################################


# Do not override existing function during conversion!
#
if { [llength [info commands PB_CMD_vnc__preprocess_nc_block]] == 0 } {
#
#=============================================================
proc PB_CMD_vnc__preprocess_nc_block { } {
#=============================================================
# This command (executed automatically) enables you to
# process a non-message NC block before being subject to
# the regular parsing for simulation.
#
#
#  Actions can be performed per sub-string pattern found in the
#  block buffer.
#
#  Simple search can be done using "string match ..." command,
#  whereas more rigorous search can be done using
#
#  "VNC_parse_nc_block BUFFER word cb_cmd"
#  ---------------------------------------
#    Arguments -
#           BUFFER  : Reference (pointer) to the block buffer
#                     (Normally you pass in "mom_sim_o_buffer" without "$" sign.)
#                     ** At this point, the block sequence number
#                        has been removed from "mom_sim_o_buffer".
#           word    : token (string pattern) to be identified
#           cb_cmd  : Optional callback command string to be executed
#                     when a match has been found.
#
#    Return -
#           0 : no match is found
#           1 : an exact match is found (no numerals traling the token)
#           2 : an extended match is found (with trailing numerals)
#
#  When a block buffer containing "X1.234" is searched for the token "X",
#  an extended match (2) will be found.
#
#  mom_sim_nc_code
#  ***************
#    "1.234" will be stored in global varaible "mom_sim_nc_code".
#
#    Entire matched sub-string (X1.234) will be removed from the buffer
#    passed into "VNC_parse_nc_block".
#
#
#  Another useful utility can be used to extract the trailing value (if any)
#  of an Address in the block.
#
#  "VNC_extract_address_val BUFFER addr"
#  -------------------------------------
#    Arguments -
#           BUFFER  : Reference (pointer) to the block buffer
#           addr    : Address name
#           flag    : [optional] 1 - Preserve buffer
#                                0 - Remove matched sub-string (default)
#
#    Return -
#           value or ""
#
#
#  o_buff
#  ******
#    Normally, the local variable "o_buff" is set to the block buffer before
#    "mom_sim_o_buffer" is subject to the process to preserve its original
#    state. When a desired match is found the "o_buff" can be set to the
#    resultant "$mom_sim_o_buffer" and then returned to the calling command
#    for subsequent process.
#
#    If no further process is needed for the block after a token is found,
#    "o_buff" is set to a NULL string ("") then returned.
#
#

  global mom_sim_o_buffer
  global mom_sim_nc_code
  global mom_sim_nc_address
  global mom_sim_nc_register
  global mom_sim_nc_func
  global mom_sim_address

  global mom_sim_pos mom_sim_prev_pos
  global mom_sim_result mom_sim_result1


   set o_buff $mom_sim_o_buffer


  # Trim off anything after an @ sign (comment)
  #
   if [string match "*@*" $mom_sim_o_buffer] {
      set i_at [string first "@" $mom_sim_o_buffer]
      if { $i_at > -1 } {
         set o_buff [string trimright [string range $mom_sim_o_buffer 0 [expr $i_at - 1]]]
      }
   }


  # Trim off trailing in-line comment
  #
   global mom_sim_control_out
   if [string match "*$mom_sim_control_out*" $mom_sim_o_buffer] {
      set i_at [string first "$mom_sim_control_out" $mom_sim_o_buffer]
      if { $i_at > -1 } {
         set o_buff [string trimright [string range $mom_sim_o_buffer 0 [expr $i_at - 1]]]
      }
   }


   set mom_sim_o_buffer $o_buff


  # Suppress delay block
  #
   global mom_sim_nc_func
   if [VNC_parse_nc_word o_buff "$mom_sim_nc_func(DELAY_SEC)" 1] {
      set mom_sim_o_buffer ""
      set o_buff ""
   }
   if [VNC_parse_nc_word o_buff "$mom_sim_nc_func(DELAY_REV)" 1] {
      set mom_sim_o_buffer ""
      set o_buff ""
   }


  # Extract T code
  #
  # Depending on controller, a tool change may be performed when
  # a T code is encountered, or triggered by a M06 later on.
  # -- T code is NOT removed from the buffer at this point.
  #
   set token $mom_sim_address(T,leader)
   if [VNC_parse_nc_word mom_sim_o_buffer $token 2] {

     # Here we assume the T address only contains tool number with leading zero.
     # -- More rigorous code will be needed when T code also contains
     #    tool length adjust register or other data.
     #
      set code [string trimleft $mom_sim_nc_code 0]
      if { [string length $code] == 0 } {
         set code 0
      }

     # Save tool number to register
      set mom_sim_nc_register($token) $code

     # Perform tool change, if necessary, or restore block buffer
     #
      set change_tool 0

      if $change_tool {
         PB_SIM_call VNC_tool_change
      } else {
         set mom_sim_o_buffer $o_buff
      }
   }


  # Extract D code
  #
   set token $mom_sim_address(D,leader)
   if [VNC_parse_nc_word mom_sim_o_buffer $token 2] {
      set code [string trimleft $mom_sim_nc_code 0]
      if { [string length $code] == 0 } {
         set code 0
      }
      set mom_sim_nc_register($token) $code
   }


  # Identify H code in G43 block to avoid being confused as incremental C axis move.
  #
   PB_SIM_call PB_CMD_vnc__G_adjust_code

   if { [string match "PLUS" $mom_sim_nc_register(TL_ADJUST)] ||\
        [string match "MINUS" $mom_sim_nc_register(TL_ADJUST)] } {

      set token $mom_sim_address(H,leader)
      if [VNC_parse_nc_word mom_sim_o_buffer $token 2] {
        # Prune leading "0"
         set code [string trimleft $mom_sim_nc_code 0]
         if { [string length $code] == 0 } {
            set code 0
         }
         set mom_sim_nc_register($token) $code
      }
   }


  #----------------------------
  # Handle Polar mode settings
  #
   global mom_sim_polar_mode


  # Allow 2 ways of polar mode handling
  #
   if [string match "*G112*" $mom_sim_o_buffer] {


     #***************************************************************
     # 1 : SIM_set_machining_mode MILL_CX & SIM_set_linearization ON
     # 2 : SIM_set_linearization ON only
     #
      set mom_sim_polar_mode 1


      PB_SIM_call SIM_set_linearization ON

      if { $mom_sim_polar_mode == 2 } {

        # Suppress circular output during linearization.
         global mom_kin_arc_output_mode

        # Preserve current arc output mode
         global mom_sim_prev_kin_arc_output_mode
         set mom_sim_prev_kin_arc_output_mode $mom_kin_arc_output_mode

         set mom_kin_arc_output_mode "LINEAR"
         PB_SIM_call MOM_reload_kinematics
      }


     # Invert X-axis if coords are mirrored.
      global mom_sim_csys_matrix mom_sim_prev_csys_matrix
      array set mom_sim_prev_csys_matrix [array get mom_sim_csys_matrix]

      global mom_sim_x_factor

      if { $mom_sim_x_factor == -1 } {

         MTX3_xform_csys 0 0 180 0 0 0 mom_sim_csys_matrix
         PB_SIM_call PB_CMD_vnc__set_kinematics

         if { ![catch {set ref_pt [PB_SIM_call SIM_ask_last_position_zcs]} ] } {
            set mom_sim_pos(0) [lindex $ref_pt 0]
            set mom_sim_pos(1) [lindex $ref_pt 1]
            set mom_sim_pos(2) [lindex $ref_pt 2]
         }
      }

     # Retain current C angle
      global mom_sim_init_polar_c_angle
      if { $mom_sim_num_machine_axes > 3 } {
         SIM_ask_axis_position $mom_sim_mt_axis($mom_sim_num_machine_axes)
         set mom_sim_init_polar_c_angle $mom_sim_result
      }
   }

   if [string match "*G113*" $mom_sim_o_buffer] {

      if ![info exists mom_sim_polar_mode] {
         set mom_sim_polar_mode 0
      }

      PB_SIM_call SIM_set_linearization OFF

      if { $mom_sim_polar_mode == 2 } {

        # Restore current arc output mode
         global mom_kin_arc_output_mode
         global mom_sim_prev_kin_arc_output_mode

         if [info exists mom_sim_prev_kin_arc_output_mode] {
            set mom_kin_arc_output_mode $mom_sim_prev_kin_arc_output_mode
            PB_SIM_call MOM_reload_kinematics
         }
      }

      if { $mom_sim_polar_mode != 0 } {
        # Restore CSYS
         global mom_sim_csys_matrix mom_sim_prev_csys_matrix
         if [info exists mom_sim_prev_csys_matrix] {
            array set mom_sim_csys_matrix [array get mom_sim_prev_csys_matrix]
            VNC_unset_vars  mom_sim_prev_csys_matrix
            PB_SIM_call PB_CMD_vnc__set_kinematics
         }

        # Prevent unnecessary unwind for all modes
         global mom_sim_5th_axis_has_limits
         global mom_sim_4th_axis_has_limits

        # Prevent unnecessary unwind
         if [info exists mom_sim_mt_axis(5)] {
            if !$mom_sim_5th_axis_has_limits {
               PB_SIM_call SIM_normalize_rotary_axis $mom_sim_mt_axis(5) NORM_180

              # Fetch current angle from machine
               SIM_ask_axis_position $mom_sim_mt_axis(5)
               if [EQ_is_zero $mom_sim_result] {
                  PB_SIM_call SIM_move_rotary_axis 5 $mom_sim_mt_axis(5) 0.0
               }
               set mom_sim_pos(4) 0.0
            }
         } elseif [info exists mom_sim_mt_axis(4)] {
            if !$mom_sim_4th_axis_has_limits {
               PB_SIM_call SIM_normalize_rotary_axis $mom_sim_mt_axis(4) NORM_180

              # Fetch current angle from machine
               SIM_ask_axis_position $mom_sim_mt_axis(4)
               if [EQ_is_zero $mom_sim_result] {
                  PB_SIM_call SIM_move_rotary_axis 5 $mom_sim_mt_axis(4) 0.0
               }
               set mom_sim_pos(3) 0.0
            }
         }

        # Nullify Y-coord of the ref pos to re-establish this pt.
        # -- Needed to zero out linearization error.
         global mom_sim_pos_mtcs
         VNC_unset_vars  mom_sim_pos_mtcs(1)

        # Fall back to initial C angle
         global mom_sim_init_polar_c_angle
         if [info exists mom_sim_init_polar_c_angle] {
            set mom_sim_pos([expr $mom_sim_num_machine_axes - 1]) $mom_sim_init_polar_c_angle
            PB_SIM_call SIM_move_rotary_axis 5 $mom_sim_mt_axis($mom_sim_num_machine_axes) \
                                               $mom_sim_pos([expr $mom_sim_num_machine_axes - 1])
         }
      }

      set mom_sim_polar_mode 0
   }


  #----------------------------------------------------------------------------
  # If a tilt CSYS object is used and its info is available from a CAM program,
  # the tilt local csys transformation can be handled here, otherwise it should
  # be handled as a case of "other device" per definition in NC instructions.
  #

  # Disable this section to define csys using NC instructions
  if 0 {

  # Enable tilt local csys
  #
   if [VNC_parse_nc_word o_buff "G68.1" 1] {

      set mom_sim_nc_register(CSYS_ROTATION) 1

      global mom_sim_prev_csys_matrix
      array set mom_sim_prev_csys_matrix [array get mom_sim_csys_matrix]


     # A local csys definition is available during an in-process isv.
     #
      global mom_sim_csys_matrix
      global mom_sim_local_csys_matrix

      if [info exists mom_sim_local_csys_matrix] {
         for { set i 0 } { $i < 12 } { incr i } {
            set mom_sim_csys_matrix($i)  $mom_sim_local_csys_matrix($i)
         }
      }

     # Since the output is localized, zero all offsets.
      set mom_sim_nc_register(WORK_OFFSET) [list]
      lappend mom_sim_nc_register(WORK_OFFSET) 0.0 0.0 0.0 0.0 0.0
 
     # Reference main zcs base component
      global mom_sim_zcs_base
      global mom_sim_zcs_base_MCS

      set mom_sim_zcs_base $mom_sim_zcs_base_MCS
      PB_SIM_call PB_CMD_vnc__set_kinematics

     # Suppress circular output. ISV doesn't know how to move
     # circle on a non-principal plane.
      global mom_kin_arc_output_mode

     # Preserve current arc output mode
      global mom_sim_prev_kin_arc_output_mode
      set mom_sim_prev_kin_arc_output_mode $mom_kin_arc_output_mode

      set mom_kin_arc_output_mode "LINEAR"
      PB_SIM_call MOM_reload_kinematics

     # Disable further simulation
      set o_buff ""
   }


  # Disable tilt local CSYS
   if [VNC_parse_nc_word o_buff "G69.1" 1] {

      if [info exists mom_sim_nc_register(CSYS_ROTATION)] {
         VNC_unset_vars  mom_sim_nc_register(CSYS_ROTATION)

        # Restore reference to the main CSYS
         global mom_sim_csys_matrix
         global mom_sim_main_csys_matrix
         if [info exists mom_sim_main_csys_matrix] {
            for { set i 0 } { $i < 12 } { incr i } {
               set mom_sim_csys_matrix($i)  $mom_sim_main_csys_matrix($i)
            }
         }

         global mom_sim_zcs_base
         global mom_sim_zcs_base_MCS

         if { [info exists mom_sim_zcs_base_MCS] && ![string match "" [string trim $mom_sim_zcs_base_MCS]] }  {
            set mom_sim_zcs_base $mom_sim_zcs_base_MCS
            PB_SIM_call PB_CMD_vnc__set_kinematics
         }
      }

     # Restore current arc output mode
      global mom_kin_arc_output_mode
      global mom_sim_prev_kin_arc_output_mode
      if [info exists mom_sim_prev_kin_arc_output_mode] {
         set mom_kin_arc_output_mode $mom_sim_prev_kin_arc_output_mode
         PB_SIM_call MOM_reload_kinematics
      }

     # Disable further simulation
      set o_buff ""
   }

  } ;# if 0
  #----------------------------------------------------------------------------


  # Return an empty buffer to prevent further simulation of this block
  #
  # set o_buff ""


return $o_buff
}

} ;# if


#=============================================================
proc PB_CMD_vnc__reset_coordinate { } {
#=============================================================
# Called when a G92 is encountered.
#
  global mom_sim_nc_register
  global mom_sim_motion_begun
  global mom_sim_prev_pos

 # Absolute coordinates specified with the block.
  global mom_sim_offset_pt


   PB_SIM_call VNC_reset_controller


  #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  # Comment out "return" to process work coordinate reset for lathe post
  #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   if [string match "TURN" $mom_sim_nc_register(MACHINE_MODE)] {
return
   }


   for {set i 0} {$i < 5} {incr i} {

     # Only change the components that exist in the block.
     #
      if [info exists mom_sim_offset_pt($i)] {
        #---------------------------------------------------
        # Do not change offset when the motion hasn't begun,
        # since mom_sim_prev_pos may not be reliable.
        #---------------------------------------------------
         if $mom_sim_motion_begun {
            set offset [expr $mom_sim_offset_pt($i) - $mom_sim_prev_pos($i)]
            set mom_sim_nc_register(MAIN_OFFSET)  [lreplace $mom_sim_nc_register(MAIN_OFFSET) $i $i $offset]
         }
      }
   }
}


#=============================================================
proc PB_CMD_vnc__compute_tool_holder_angle_delta { } {
#=============================================================
# <By JM>
# Function computes the angle delta for the B axis rotation
# for lathes or mill/turn machines with B axis.
# The computation is based on the globals mom_tool_holder_orient_angle
# and mom_tool_holder_angle_for_cutting (see below)
#

    # Angle of the tool holder in default working orientation
    # This angle is specified in the holder tap page of the tool dialog for turning tools
    # It refers to the X axis of the tool workspace
  
     global mom_tool_holder_orient_angle

         
    # Angle of the tool holder to be used in a specific operation.
    # This value overrides the default one in the tool dialog
    # This angle is specified in the Tool Holder Angle field 
    # of the Machine control subdialog in the operation.
    # It refers to the spindle rotational axis of the current MCS

     global mom_tool_holder_angle_for_cutting


    # The 'Reorient Tool Holder' check box flag if the
    # above angle shall be used or not 

     global mom_use_b_axis 

     global mom_tool_workspace
     global mom_msys_matrix
     global mom_spindle_definition_type  ;# Z/X  or X/Y workplane 
  

    # No action if no angle is specified in the operation 

     if { ![info exists mom_use_b_axis] || $mom_use_b_axis != 1 } { return 0 }

       # First determine the vector that corresponds to the angle ( call it cutting holder vector ) 
       # This vector is with respect to the current MCS

        set co1 [expr cos($mom_tool_holder_angle_for_cutting)]  ;# first coordinate
        set co2 [expr sin($mom_tool_holder_angle_for_cutting)]  ;# second coordinate
   
       # Define cutting_holder_vector (ch_vec) depending on lathe workplane
        if { $mom_spindle_definition_type == 0 }  {

          # X/Y workplane -> cutter holder angle refers to X axis 

           set ch_vec(0) $co1
           set ch_vec(1) $co2
           set ch_vec(2) 0

        }  else  {

          # Z/X workplane  -> cutter holder angle refers to Z axis

           set ch_vec(0) $co2
           set ch_vec(1) 0
           set ch_vec(2) $co1
        }

       # Transforrm the vector to absolute csys
        set ch_vec_abs(0) [expr $ch_vec(0) * $mom_msys_matrix(0) +\
                                $ch_vec(1) * $mom_msys_matrix(3) +\
                                $ch_vec(2) * $mom_msys_matrix(6)] 

        set ch_vec_abs(1) [expr $ch_vec(0) * $mom_msys_matrix(1) +\
                                $ch_vec(1) * $mom_msys_matrix(4) +\
                                $ch_vec(2) * $mom_msys_matrix(7)] 

        set ch_vec_abs(2) [expr $ch_vec(0) * $mom_msys_matrix(2) +\
                                $ch_vec(1) * $mom_msys_matrix(5) +\
                                $ch_vec(2) * $mom_msys_matrix(8)] 

       # Transform the absolute vector to tool workspace (tws)
        set ch_vec_tws(0) [expr $ch_vec_abs(0) * $mom_tool_workspace(0) +\
                                $ch_vec_abs(1) * $mom_tool_workspace(1) +\
                                $ch_vec_abs(2) * $mom_tool_workspace(2)] 

        set ch_vec_tws(1) [expr $ch_vec_abs(0) * $mom_tool_workspace(3) +\
                                $ch_vec_abs(1) * $mom_tool_workspace(4) +\
                                $ch_vec_abs(2) * $mom_tool_workspace(5)] 

        set ch_vec_tws(2) [expr $ch_vec_abs(0) * $mom_tool_workspace(6) +\
                                $ch_vec_abs(1) * $mom_tool_workspace(7) +\
                                $ch_vec_abs(2) * $mom_tool_workspace(8)] 


       # Calculate the angle of the vector
        set ch_vec_angle [expr atan2($ch_vec_tws(1), $ch_vec_tws(0))]
 
       # Angle delta in degree
        set PIII [expr 2 * acos(0)]
        set deg_fac [expr 180 / $PIII]
        set cutter_holder_angle_delta [expr ($ch_vec_angle - $mom_tool_holder_orient_angle) * $deg_fac]


return $cutter_holder_angle_delta
}


#=============================================================
proc PB_CMD_vnc__tool_change { } {
#=============================================================
  global sim_prev_tool_name
  global mom_sim_result mom_sim_result1
  global mom_sim_ug_tool_name
  global mom_sim_tool_loaded
  global mom_sim_spindle_comp mom_sim_spindle_jct
  global mom_sim_lg_axis
  global mom_sim_nc_register
  global mom_sim_machine_type
  global mom_sim_tool_offset_used mom_sim_tool_offset mom_sim_tool_mount
  global mom_sim_output_reference_method
  global mom_sim_tool_junction mom_sim_current_junction
  global mom_sim_pivot_distance
  global mom_sim_tool_change

  global mom_sim_pos mom_sim_prev_pos


  # Fetch UG tool name per tool number
   global mom_sim_address
   global mom_sim_tool_data
   global mom_sim_tool_number

   set tool_number ""
   if [info exists mom_sim_tool_number] {
      set tool_number $mom_sim_tool_number
   } elseif [info exists mom_sim_nc_register($mom_sim_address(T,leader))] {
      set tool_number $mom_sim_nc_register($mom_sim_address(T,leader))
   }

   if { $tool_number != ""  &&  [info exists mom_sim_tool_data($tool_number,name)] } {
      set mom_sim_ug_tool_name $mom_sim_tool_data($tool_number,name)
   } else {
      set mom_sim_tool_change 0
return
   }


   if [string match "$sim_prev_tool_name" $mom_sim_ug_tool_name] {
      set mom_sim_tool_change 0
return
   }


  # Allow users to use specified tool change position.
   if [llength [info commands "PB_CMD_vnc____go_to_tool_change_position"]] {

      PB_SIM_call PB_CMD_vnc____go_to_tool_change_position

   } elseif [llength [info commands "PB_CMD_vnc__go_to_tool_change_position"]] {
     # Legacy
      PB_SIM_call PB_CMD_vnc__go_to_tool_change_position

   } else {

     # By default, turret does not return to ref pt for tool change
      global mom_sim_tool_carrier_id
      global mom_sim_turret_carriers
      global mom_sim_tool_pocket_id

      set done_position 0

      if { [info exists mom_sim_tool_carrier_id] &&\
           [info exists mom_sim_tool_pocket_id] &&\
           [info exists mom_sim_turret_carriers] } {

        # Not sure this is always true!
         if { [lsearch $mom_sim_turret_carriers $mom_sim_tool_carrier_id] >= 0 } {

            set mom_sim_nc_register(REF_INT_PT_X) -939
            set mom_sim_nc_register(REF_INT_PT_Y) -939
            VNC_unset_vars  mom_sim_nc_register(REF_INT_PT_Z)

           # Position spindle to reference point.
            PB_SIM_call PB_CMD_vnc__send_dogs_home

           # Unset temporary intermediate reference point
            VNC_unset_vars  mom_sim_nc_register(REF_INT_PT_X) mom_sim_nc_register(REF_INT_PT_Y)

            set done_position 1
         }
      }

      if { $done_position == 0 } {
        # Fake a temporary intermediate reference point to send all dogs home
         set mom_sim_nc_register(REF_INT_PT_X) -939
         set mom_sim_nc_register(REF_INT_PT_Y) -939
         set mom_sim_nc_register(REF_INT_PT_Z) -939

        # Position spindle to reference point.
         PB_SIM_call PB_CMD_vnc__send_dogs_home

        # Unset temporary intermediate reference point
         VNC_unset_vars  mom_sim_nc_register(REF_INT_PT_X)\
                        mom_sim_nc_register(REF_INT_PT_Y)\
                        mom_sim_nc_register(REF_INT_PT_Z)
      }
   }


   set sim_tool_name ""


#>>>>>
#  This is where you add detailed movements such as rotating tool changer,
#  unmounting old tool and mounting new tool and/or getting next tool in ready position.
#<<<<<

  # User provided tool change sequence
   if [llength [info commands "PB_CMD_vnc__user_tool_change"]] {

      set sim_tool_name [PB_SIM_call PB_CMD_vnc__user_tool_change]

   } elseif [llength [info commands "PB_CMD_vnc____tool_change"]] {

      set sim_tool_name [PB_SIM_call PB_CMD_vnc____tool_change]

   } else {

      global mom_sim_tool_carrier_id
      global mom_sim_turret_carriers
      global mom_sim_turret_axis
      global mom_sim_tool_pocket_id


      set done_tool_change 0

      set tool_change_time 5


      set mom_sim_result ""

     # Rotate turret to index lathe tool
      if { [info exists mom_sim_tool_carrier_id] &&\
           [info exists mom_sim_tool_pocket_id] &&\
           [info exists mom_sim_turret_carriers] } {

         if { [lsearch $mom_sim_turret_carriers $mom_sim_tool_carrier_id] >= 0 } {

           # Handle mixed use of tools on a turret and stationary tools.
            if ![catch { PB_SIM_call SIM_ask_kim_comp_name_by_id "TOOL" $mom_sim_ug_tool_name }] {
               set done_tool_change 1
            }

            if $done_tool_change {

               global mom_sim_pocket_angle

              # Handle holder angle with operation
               set cutter_holder_angle_delta 0.0
               set cutter_holder_angle_delta [PB_SIM_call PB_CMD_vnc__compute_tool_holder_angle_delta]

              # Actual turret rotation angle = rot angle based on pocket ID + tool holder delta 
               set turret_rotation_angle [expr $cutter_holder_angle_delta +\
                           $mom_sim_pocket_angle($mom_sim_tool_carrier_id,$mom_sim_tool_pocket_id)]
 
              # Set rotation direction
               PB_SIM_call SIM_set_axis_rotary_dir_mode\
                           $mom_sim_turret_axis($mom_sim_tool_carrier_id) "ALWAYS_SHORTEST"

               PB_SIM_call SIM_move_rotary_axis $tool_change_time\
                           $mom_sim_turret_axis($mom_sim_tool_carrier_id)\
                           $turret_rotation_angle
            }
         }
      }


     # Initialize previous spindle component when needed.
      global mom_sim_prev_spindle_comp
      if ![info exists mom_sim_prev_spindle_comp] {
         set mom_sim_prev_spindle_comp $mom_sim_spindle_comp
      }


     # Change tool for mills
      if { $done_tool_change == 0 } {

        # Prevent unmounting stationary lathe tool
         if [string match "$mom_sim_prev_spindle_comp" $mom_sim_spindle_comp] {

            PB_SIM_call VNC_unmount_tool $sim_prev_tool_name
         }
         PB_SIM_call VNC_set_ref_jct {""}
         PB_SIM_call SIM_mount_tool $tool_change_time "UG_NAME" "$mom_sim_ug_tool_name"\
                                    "$mom_sim_spindle_comp" "$mom_sim_spindle_jct"
      }

     # Retain spindle component
      set mom_sim_prev_spindle_comp $mom_sim_spindle_comp

     # Fetch tool comp ID
      set sim_tool_name $mom_sim_result 
   }


   PB_SIM_call SIM_update 


   if {$sim_tool_name != ""} {
      PB_SIM_call SIM_activate_tool $sim_tool_name
   } else {
return
   }

   PB_SIM_call SIM_update 


   set sim_prev_tool_name $mom_sim_ug_tool_name
   set mom_sim_tool_loaded $sim_tool_name


  # Flag that a tool change is done.
   set mom_sim_tool_change 0


   PB_SIM_call VNC_set_ref_jct $sim_tool_name

   set mom_sim_tool_junction "$mom_sim_current_junction"


  #++++++++++++++++++++++++++++++++++++++++++++++++++++++
  # Create a junction per tool offsets to track N/C data.
  #++++++++++++++++++++++++++++++++++++++++++++++++++++++
   set use_tool_tip_jct 1

   if { $mom_sim_tool_data($tool_number,offset_used) || [expr $mom_sim_pivot_distance != 0.0] } {

      if { ![string match "*_wedm" $mom_sim_machine_type] } {
         if [string match "*axis*" $mom_sim_machine_type] {
            set use_tool_tip_jct 0
            set x_offset [expr -1.0 * ($mom_sim_tool_data($tool_number,z_off) + $mom_sim_pivot_distance)]
            set y_offset 0.0
            set z_offset 0.0

         } elseif [string match "*lathe*" $mom_sim_machine_type] {
            if [string match "TURRET_REF" $mom_sim_output_reference_method] {
               set use_tool_tip_jct 0
               set x_offset $mom_sim_tool_data($tool_number,x_off)
               set y_offset $mom_sim_tool_data($tool_number,y_off)
               set z_offset 0.0
            }
         }
      }
   }


   if { !$use_tool_tip_jct } {
      global mom_sim_tool_x_offset mom_sim_tool_y_offset mom_sim_tool_z_offset

      set mom_sim_tool_x_offset $x_offset
      set mom_sim_tool_y_offset $y_offset
      set mom_sim_tool_z_offset $z_offset

      PB_SIM_call PB_CMD_vnc__offset_tool_jct
   }


   if [string match "TURN" $mom_sim_nc_register(MACHINE_MODE)] {
      set mom_sim_pos(1) 0
   }

  # Reset mom_sim_prev_pos to disable unnecessary move
   for {set i 0} {$i < 5} {incr i} {
      set mom_sim_prev_pos($i) $mom_sim_pos($i)
   }
}


#=============================================================
proc PB_CMD_vnc__calculate_duration_time { } {
#=============================================================
  global mom_sim_motion_linear_or_angular
  global mom_sim_travel_delta mom_sim_duration_time
  global mom_sim_feedrate_mode
  global mom_sim_nc_register
  global mom_sim_rapid_feed_rate
  global mom_sim_max_dpm


   if [llength [info commands "PB_CMD_vnc__user_calculate_duration_time"]] {
      PB_SIM_call PB_CMD_vnc__user_calculate_duration_time
return
   }


  # Prescreen condition
   if ![EQ_is_gt [expr abs($mom_sim_travel_delta)] 0.0] {
      set mom_sim_duration_time 0.0
return
   }


   set linear_or_angular $mom_sim_motion_linear_or_angular
   set delta [expr abs($mom_sim_travel_delta)]

  # Determine feed rate & mode
   if { [string match "RAPID" $mom_sim_nc_register(MOTION)] || [expr $mom_sim_nc_register(F) <= 0] } {

      set feed $mom_sim_rapid_feed_rate

      if { $mom_sim_nc_register(UNIT) == "MM" } {
         set mode MM_PER_MIN
      } else {
         set mode INCH_PER_MIN
      }
   } else {
      set feed $mom_sim_nc_register(F)
      set mode $mom_sim_nc_register(FEED_MODE)
   }


   set feed [expr abs($feed)]


  # Initialize time
   set mom_sim_duration_time 1

   if { $linear_or_angular == "ANGULAR" } {

     # Find correct feed rate mode for a pure ratary move
      global mom_sim_feed_param
      global mom_sim_rapid_feed_mode
      global mom_sim_contour_feed_mode

      if { $mom_sim_nc_register(MOTION) == "RAPID" } {
         if { [info exists mom_sim_max_dpm] && [EQ_is_gt $mom_sim_max_dpm 0.0] } {
            set mom_sim_duration_time [expr ($delta / $mom_sim_max_dpm) * 60.0]
         }
      } else {

        # Calculate time for pure rotary move with DPM, if defined.
         global mom_sim_feedrate_dpm
         if { [info exists mom_sim_feedrate_dpm] && [EQ_is_gt $mom_sim_feedrate_dpm 0.0] } {
            set mom_sim_duration_time [expr ($delta / $mom_sim_feedrate_dpm) * 60.0]
         } elseif ![EQ_is_zero $feed] {

           # We actually need to know the direction of rotation to convert FPM to DPM.
           # +++ Use kluge for now

            set mom_sim_duration_time [expr ($delta / $feed)]
         }
      }

   } else { ;# LINEAR

      if ![EQ_is_zero $feed] {

         switch $mode {
            INCH_PER_MIN -
            MM_PER_MIN   {

               set mom_sim_duration_time [expr ($delta / $feed) * 60.0]
            }

            INCH_PER_REV -
            MM_PER_REV   {

               global mom_sim_spindle_mode mom_sim_spindle_speed
               global mom_sim_PI mom_sim_prev_pos mom_sim_pos

               switch $mom_sim_spindle_mode {
                  "REV_PER_MIN" {
                     set feed [expr $feed * $mom_sim_spindle_speed]
                  }
                  "SFM" -
                  "FEET_PER_MIN" {
                    # The spindle direction may not always be along Z-axis.
                    # We need more sophisticated formula here!
                    #
                     if ![EQ_is_zero [expr $mom_sim_prev_pos(0) + $mom_sim_pos(0)] ] {
                        set feed [expr $feed * $mom_sim_spindle_speed * 12 /\
                                       abs($mom_sim_PI * ($mom_sim_prev_pos(0) + $mom_sim_pos(0)))]
                     } else {
                        set feed $mom_sim_rapid_feed_rate
                     }
                  }
                  "SMM" -
                  "M_PER_MIN" {
                     if ![EQ_is_zero [expr $mom_sim_prev_pos(0) + $mom_sim_pos(0)] ] {
                        set feed [expr $feed * $mom_sim_spindle_speed * 1000 /\
                                       abs($mom_sim_PI * ($mom_sim_prev_pos(0) + $mom_sim_pos(0)))]
                     } else {
                        set feed $mom_sim_rapid_feed_rate
                     }
                  }
               }

               if ![EQ_is_zero $feed] {
                  set mom_sim_duration_time [expr ($delta / $feed) * 60.0]
               }
            }

            MM_PER_100REV {
              # FRN mode
               set mom_sim_duration_time [expr 60 / $feed]
            }
         }
      }
   }

 if 0 { ;# debug
   global __sim_total_time
   if ![info exists __sim_total_time] {
      set __sim_total_time 0.0
   }
   set __sim_total_time [expr $__sim_total_time + $mom_sim_duration_time]
 }

}


#=============================================================
proc PB_CMD_vnc__define_wcs { } {
#=============================================================
  global mom_sim_result mom_sim_result1
  global mom_sim_csys_matrix
  global mom_sim_machine_zero_offsets
  global mom_sim_csys_data
  global mom_sim_wcs_offsets
  global mom_sim_csys_set
  global mom_sim_nc_register
  global mom_sim_machine_zero_csys_matrix
  global mom_sim_main_csys_matrix
  global mom_sim_local_csys_matrix


  # Define Machine Zero coordinate system offset from MTCS Junction
  #
   PB_SIM_call SIM_ask_mtcs_junction
   PB_SIM_call SIM_ask_init_junction_xform $mom_sim_result

   set i 0
   foreach v $mom_sim_result {
      set mom_sim_csys_matrix($i) $v
      incr i
   }
   foreach v $mom_sim_result1 {
      set mom_sim_csys_matrix($i) $v
      incr i
   }


  # MTCS must be oriented the same as NC axes, the desired Machine Zero CSYS
  # may only require, if any, translational offsets.
  # - All other work coordinate systems (fixture offsets G53 - G59 & etc.)
  #   will be defined w.r.t. the Machine Zero CSYS.
  #
    set x [lindex $mom_sim_machine_zero_offsets 0]
    set y [lindex $mom_sim_machine_zero_offsets 1]
    set z [lindex $mom_sim_machine_zero_offsets 2]

   MTX3_xform_csys 0.0 0.0 0.0 $x $y $z mom_sim_csys_matrix

   array set mom_sim_machine_zero_csys_matrix  [array get mom_sim_csys_matrix]


  # Initialize WCS matrices w.r.t. Machine Zero.
  # - They may get overwritten by MCS object during an in-process ISV.
  #
  # array set main_csys_matrix [array get csys_matrix]

   array set main_csys_matrix [array get mom_sim_machine_zero_csys_matrix]

   set n_wcs [array size mom_sim_wcs_offsets]

   for { set i 0 } { $i < $n_wcs } { incr i } {

      if [info exists mom_sim_wcs_offsets($i)] {

         array set csys_matrix [array get main_csys_matrix]

          set x [lindex $mom_sim_wcs_offsets($i) 0]
          set y [lindex $mom_sim_wcs_offsets($i) 1]
          set z [lindex $mom_sim_wcs_offsets($i) 2]
          set a [lindex $mom_sim_wcs_offsets($i) 3]
          set b [lindex $mom_sim_wcs_offsets($i) 4]
          set c [lindex $mom_sim_wcs_offsets($i) 5]

         MTX3_xform_csys $a $b $c $x $y $z csys_matrix

         for { set j 0 } { $j < 12 } { incr j } {
            set mom_sim_csys_data($i,$j) $csys_matrix($j)
         }
      }
   }


  # Zero work offsets
   set mom_sim_nc_register(WORK_OFFSET) [list 0.0 0.0 0.0 0.0 0.0]


  # Initialize reference to 0th WCS
   for { set j 0 } { $j < 12 } { incr j } {
      set csys_matrix($j) $mom_sim_csys_data(0,$j)
   }
   array set mom_sim_csys_matrix  [array get csys_matrix]
   PB_SIM_call PB_CMD_vnc__set_kinematics
   set mom_sim_csys_set 1

   array set mom_sim_main_csys_matrix  [array get mom_sim_csys_matrix]
   array set mom_sim_local_csys_matrix [array get mom_sim_csys_matrix]
}


#=============================================================
proc PB_CMD_vnc__define_misc_procs { } {
#=============================================================
 uplevel #0 {

  #-----------------------------------------------------------
  proc VNC_unset_procs { args } {
  #-----------------------------------------------------------

     if { [llength $args] == 0 } {
  return
     }

     foreach p $args {
        if [llength [info commands [string trim $p] ] ] {
           rename $p ""
        }
     }
  }

  #-----------------------------------------------------------
  proc VNC_unset_vars { args } {
  #-----------------------------------------------------------

     if { [llength $args] == 0 } {
  return
     }

     foreach VAR $args {
        upvar $VAR var

        global tcl_version

        if [array exists var] {
           if [expr $tcl_version < 8.4] {
              foreach a [array names var] {
                 if [info exists var($a)] {
                    unset var($a)
                 }
              }
              unset var
           } else {
              array unset var
           }
        }

        if [info exists var] {
           unset var
        }
     }
  }

  #-----------------------------------------------------------
  proc VNC_info { args } {
  #-----------------------------------------------------------
     if { [llength $args] > 0 } {
        set msg [string trim [lindex $args 0]]
     } else {
        set msg ""
     }
     MOM_output_to_listing_device $msg
  }

  #-----------------------------------------------------------
  proc VNC_parse_nc_word { O_BUFF word flag args } {
  #-----------------------------------------------------------
  # - Reduce buffer & execute callback only
  #   when the requested type of match is found.
  #
  #   Arguments -
  #
  #     BUFFER  : Reference (pointer) to the block buffer
  #               (Normally you pass in "mom_sim_o_buffer" without "$" sign.)
  #               ** At this point, the block sequence number
  #                  has been removed from "mom_sim_o_buffer".
  #
  #     word    : token (string pattern) to be identified
  #
  #     flag    : 0 = Any match, do not remove token
  #               1 = Exact match
  #               2 = Extended match
  #               3 = Any match
  #
  #     args    : Optional callback command string to be executed
  #               when a match has been found.
  #
  #   Return -
  #               0 = No match
  #               1 = Match found
  #              -1 = Match found but callback not found
  #
    upvar $O_BUFF o_buff

     set tmp_buff $o_buff

     set status [VNC_parse_nc_block tmp_buff $word]

     if { $status > 0 } {
        if { $flag == 0  ||  $flag == 3  ||  $status == $flag } {
          # Trim buffer
           if { $flag != 0 } {
              set o_buff $tmp_buff
           }

          # Execute callback
           if { [llength $args] > 0 } {
              set exec_cb [string trim [lindex $args 0]]
           } else {
              set exec_cb ""
           }

           if { ![string match "" $exec_cb] } {
              if [llength [info commands "$exec_cb"]] {
                 eval "$exec_cb"
              } else {
  return -1
              }
           }

  return 1
        }
     }

  return 0
  }

  #-----------------------------------------------------------
  proc  MTX3_xform_csys { a b c x y z CSYS } {
  #-----------------------------------------------------------
     upvar $CSYS csys
  #
  #                     Rotation about
  #         X                  Y                  Z
  # ----------------   ----------------   ----------------
  #   1     0     0     cosB   0   sinB    cosC -sinC    0
  #   0   cosA -sinA     0     1     0     sinC  cosC    0
  #   0   sinA  cosA   -sinB   0   cosB      0     0     1


    # Validate input data
     if { [EQ_is_zero $a] && [EQ_is_zero $b] && [EQ_is_zero $c] &&\
          [EQ_is_zero $x] && [EQ_is_zero $y] && [EQ_is_zero $z] } {
  return
     }


    #----------
    # Ratation
    #----------
     set xa [expr +1*$a]
     set yb [expr +1*$b]
     set zc [expr +1*$c]

     array set mm [array get csys]

     if { ![EQ_is_zero $a] || ![EQ_is_zero $b] || ![EQ_is_zero $c] } {

       # Rotate about X
       #
        set mx(0) 1;            set mx(1) 0;            set mx(2) 0
        set mx(3) 0;            set mx(4) [cosD $xa];   set mx(5) [-sinD $xa]
        set mx(6) 0;            set mx(7) [sinD $xa];   set mx(8) [cosD $xa]

       # Rotate about Y
       #
        set my(0) [cosD $yb];   set my(1) 0;            set my(2) [sinD $yb]
        set my(3) 0;            set my(4) 1;            set my(5) 0
        set my(6) [-sinD $yb];  set my(7) 0;            set my(8) [cosD $yb]

       # Rotate about Z
       #
        set mz(0) [cosD $zc];   set mz(1) [-sinD $zc];  set mz(2) 0
        set mz(3) [sinD $zc];   set mz(4) [cosD $zc];   set mz(5) 0
        set mz(6) 0;            set mz(7) 0;            set mz(8) 1

        MTX3_multiply  my mx mt
        MTX3_multiply  mz mt ma
        MTX3_transpose ma mt
        MTX3_multiply  mm mt csys
     }

    #-------------
    # Translation
    #-------------
     set u(0) $x;  set u(1) $y;  set u(2) $z
     MTX3_transpose mm ma
     MTX3_vec_multiply u ma v

     set csys(9)  [expr $csys(9)  + $v(0)]
     set csys(10) [expr $csys(10) + $v(1)]
     set csys(11) [expr $csys(11) + $v(2)]

     for { set i 0 } { $i < 12 } { incr i } {
        if [EQ_is_zero $csys($i)] {
           set csys($i) 0.0
        }
     }
  }

  #-----------------------------------------------------------
  proc VNC_map_from_machine_offsets { offsets } {
  #-----------------------------------------------------------
  # This function converts a 5-element offsets to a 6-element offsets.
  #

   if { [llength $offsets] == 6 } {
      return $offsets
   }

   global mom_sim_machine_type
   global mom_sim_4th_axis_plane
   global mom_sim_5th_axis_plane

   set xyzabc [list [lindex $offsets 0] [lindex $offsets 1] [lindex $offsets 2] 0.0 0.0 0.0]

   set 4th_index 0
   set 5th_index 0
   set ang4 [lindex $offsets 3]
   set ang5 [lindex $offsets 4]

   if { [string match "4*" $mom_sim_machine_type] } {
      switch $mom_sim_4th_axis_plane {
         "YZ" {
            set 4th_index 3
         }
         "ZX" {
            set 4th_index 4
         }
         "XY" {
            set 4th_index 5
         }
      }
      if { $4th_index > 0 } {
         set xyzabc [lreplace $xyzabc $4th_index $4th_index $ang4]
      }
   }

   if { [string match "5*" $mom_sim_machine_type] } {
      switch $mom_sim_4th_axis_plane {
         "XY" {
            set 4th_index 5
            switch $mom_sim_5th_axis_plane {
               "YZ" {
                  set 5th_index 3
               }
               "ZX" {
                  set 5th_index 4
               }
            }
         }
         "YZ" {
            set 4th_index 3
            switch $mom_sim_5th_axis_plane {
               "XY" {
                  set 5th_index 5
               }
               "ZX" {
                  set 5th_index 4
               }
            }
         }
         "ZX" {
            set 4th_index 4
            switch $mom_sim_5th_axis_plane {
               "XY" {
                  set 5th_index 5
               }
               "YZ" {
                  set 5th_index 3
               }
            }
         }
      }
      if { $4th_index > 0 } {
         set xyzabc [lreplace $xyzabc $4th_index $4th_index $ang4]
      }
      if { $5th_index > 0 } {
         set xyzabc [lreplace $xyzabc $5th_index $5th_index $ang5]
      }
   }

  return $xyzabc
  }

  #-----------------------------------------------------------
  proc VNC_map_to_machine_offsets { offsets } {
  #-----------------------------------------------------------
  # This function converts a 6-element offsets to a 5-element
  # offsets for an orthogonal machine.
  #

   if { [llength $offsets] == 5 } {
      return $offsets
   }

   global mom_sim_machine_type
   global mom_sim_4th_axis_plane
   global mom_sim_5th_axis_plane

   set xyzab [list [lindex $offsets 0] [lindex $offsets 1] [lindex $offsets 2] 0.0 0.0]

   set 4th_index 0
   set 5th_index 0

   if { [string match "4*" $mom_sim_machine_type] } {
      switch $mom_sim_4th_axis_plane {
         "YZ" {
            set 4th_index 3
         }
         "ZX" {
            set 4th_index 4
         }
         "XY" {
            set 4th_index 5
         }
      }
      if { $4th_index > 0 } {
         set ang4 [lindex $offsets $4th_index]
         set xyzab [lreplace $xyzab 3 3 $ang4]
      }
   }

   if { [string match "5*" $mom_sim_machine_type] } {
      switch $mom_sim_4th_axis_plane {
         "XY" {
            set 4th_index 5
            switch $mom_sim_5th_axis_plane {
               "YZ" {
                  set 5th_index 3
               }
               "ZX" {
                  set 5th_index 4
               }
            }
         }
         "YZ" {
            set 4th_index 3
            switch $mom_sim_5th_axis_plane {
               "XY" {
                  set 5th_index 5
               }
               "ZX" {
                  set 5th_index 4
               }
            }
         }
         "ZX" {
            set 4th_index 4
            switch $mom_sim_5th_axis_plane {
               "XY" {
                  set 5th_index 5
               }
               "YZ" {
                  set 5th_index 3
               }
            }
         }
      }
      if { $4th_index > 0 } {
         set ang4 [lindex $offsets $4th_index]
         set xyzab [lreplace $xyzab 3 3 $ang4]
      }
      if { $5th_index > 0 } {
         set ang5 [lindex $offsets $5th_index]
         set xyzab [lreplace $xyzab 4 4 $ang5]
      }
   }

  return $xyzab
  }

 } ;# uplevel
}


#=============================================================
proc PB_CMD_vnc__display_version { } {
#=============================================================
  global mom_sim_vnc_handler mom_sim_post_builder_version

   VNC_send_message "> Virtual NC Controller in [file dir $mom_sim_vnc_handler]"
   VNC_send_message "> [file tail $mom_sim_vnc_handler]\
                       created with Post Builder v$mom_sim_post_builder_version."
}


#=============================================================
proc PB_CMD_vnc__init_sim_vars { } {
#=============================================================
  global mom_sim_word_separator mom_sim_word_separator_len
  global mom_sim_end_of_block mom_sim_end_of_block_len
  global mom_sim_pos
  global mom_sim_tool_loaded
  global mom_sim_tool_junction
  global mom_sim_curr_jct_matrix mom_sim_curr_jct_origin
  global mom_sim_nc_register
  global mom_sim_wcs_offsets
  global mom_sim_ug_tool_name
  global mom_sim_result mom_sim_result1


  # Define some misc commands.
   PB_SIM_call PB_CMD_vnc__define_misc_procs


  # Transfer static data from the Post.
  #
   PB_SIM_call VNC_load_post_definitions


  # Inspect NC functions
  #
   PB_SIM_call PB_CMD_vnc__inspect_nc_func


  # When a VNC is used to output VNC messages only w/o simulation.
  #
   global mom_sim_vnc_msg_only
   if { [info exists mom_sim_vnc_msg_only] && $mom_sim_vnc_msg_only } {
return
   }


  # Display this VNC name in ISV.
  #
   PB_SIM_call PB_CMD_vnc__display_version


  # Initialize controller's input unit to post's output unit
  #
   global mom_sim_output_unit
   if { ![info exists mom_sim_nc_register(UNIT)] } {
      set mom_sim_nc_register(UNIT) $mom_sim_output_unit
   }


  # Undefine machine tool kinematics assignment
  # to clear up residual variables.
  #
   global mom_sim_zcs_base mom_sim_zcs_base_MCS mom_sim_zcs_base_LCS
   global mom_sim_spindle_comp mom_sim_spindle_jct mom_sim_pivot_jct
   global mom_sim_advanced_kinematic_jct
   global mom_sim_mt_axis

   VNC_unset_vars  mom_sim_zcs_base_MCS\
                   mom_sim_zcs_base_LCS\
                   mom_sim_zcs_base\
                   mom_sim_spindle_comp\
                   mom_sim_spindle_jct\
                   mom_sim_pivot_jct\
                   mom_sim_advanced_kinematic_jct\
                   mom_sim_mt_axis


  # Interrogate actual number of NC axes from model
  # This enables use of a higher dof driver on a lower dof machine.
   global mom_sim_num_machine_axes

   PB_SIM_call SIM_ask_nc_axes_of_mtool
   if { $mom_sim_result < $mom_sim_num_machine_axes } {
      set mom_sim_num_machine_axes $mom_sim_result
   }


  #------------------------------
  # Map machine tool assignments
  #------------------------------
   if { [PB_SIM_call PB_CMD_vnc__ask_number_of_active_channels] > 1 } {

      if [catch { PB_SIM_call PB_CMD_vnc____map_machine_tool_axes }] {

        # Fetch machine kinematics from model
         if [string match "TRUE" [PB_SIM_call MOM_validate_machine_model]] {
            PB_SIM_call PB_CMD_vnc__reload_machine_tool_axes
         } else {
           # Force an error raise
            PB_SIM_call PB_CMD_vnc__validate_machine_tool
         }
      }

   } else {

     # PB341 implementation
      if [string match "TRUE" [PB_SIM_call MOM_validate_machine_model]] {
        # Fetch machine kinematics from model
         PB_SIM_call PB_CMD_vnc__reload_machine_tool_axes
      } else {
        # Hard code axes assignmaents
         PB_SIM_call PB_CMD_vnc____map_machine_tool_axes
      }
   }


  # Initialize a null list for other NC codes to be simulated.
  # Actual code list will be defined in PB_CMD_vnc____set_nc_definitions.
  #
   global mom_sim_other_nc_codes
   global mom_sim_other_nc_codes_ex

   set mom_sim_other_nc_codes [list]
   set mom_sim_other_nc_codes_ex [list]


  # Add user's NC data definition.
  #
   if [llength [info commands "PB_CMD_vnc__set_nc_definitions"]] {
      PB_SIM_call PB_CMD_vnc__set_nc_definitions
   } else {
      PB_SIM_call PB_CMD_vnc____set_nc_definitions
   }


  # Add more user's NC data definition required for conversion.
  # (Legacy only)
   PB_SIM_call PB_CMD_vnc__fix_nc_definitions


  # Unset Y axis for a lathe, if necessary.
  #
   PB_SIM_call PB_CMD_vnc__unset_Y_axis


  # Validity check for machine tool parameters.
  #
   PB_SIM_call PB_CMD_vnc__validate_machine_tool


  # Nullify ref pos of MTCS
   global mom_sim_pos_mtcs
   VNC_unset_vars  mom_sim_pos_mtcs


  # Logical axes assignments (not from the post?)
  # It works to equate logical names to the physical names.
  #
   global mom_sim_lg_axis mom_sim_nc_axes mom_sim_address

  # Linear axes are commanded by logical names, whereas
  # rotary axes are commanded by physical names.
  #
   set mom_sim_lg_axis(X) X
   set mom_sim_lg_axis(Y) Y
   set mom_sim_lg_axis(Z) Z
   set mom_sim_lg_axis(I) I
   set mom_sim_lg_axis(J) J
   set mom_sim_lg_axis(K) K

   set mom_sim_nc_axes [concat $mom_sim_lg_axis(X) $mom_sim_lg_axis(Y) $mom_sim_lg_axis(Z)]

   switch $mom_sim_num_machine_axes {
      4 {
         set mom_sim_lg_axis(4) $mom_sim_mt_axis(4)
         lappend mom_sim_nc_axes $mom_sim_lg_axis(4)
      }
      5 {
         set mom_sim_lg_axis(4) $mom_sim_mt_axis(4)
         set mom_sim_lg_axis(5) $mom_sim_mt_axis(5)
         lappend mom_sim_nc_axes $mom_sim_lg_axis(4) $mom_sim_lg_axis(5)
      }
   }


  # Initialize data for simulation.
  #
   if { ![info exists mom_sim_ug_tool_name] } {
      set mom_sim_ug_tool_name ""
   }

   if { ![info exists mom_sim_tool_loaded] } {
      set mom_sim_tool_loaded ""
   }

   if { ![info exists mom_sim_tool_junction] } {
      set mom_sim_tool_junction "$mom_sim_spindle_jct"
   }

   if { ![info exists mom_sim_curr_jct_matrix] } {
      lappend mom_sim_curr_jct_matrix 1.0 0.0 0.0  0.0 1.0 0.0  0.0 0.0 1.0
   }

   if { ![info exists mom_sim_curr_jct_origin] } {
      lappend mom_sim_curr_jct_origin 0.0 0.0 0.0
   }

   for {set i 0} {$i < 8} {incr i} {
      if { ![info exists mom_sim_pos($i)] } {
         set mom_sim_pos($i) 0
      }
   }


  # Initialize controller's states, in case, not set in a VNC by
  # PB_CMD_vnc____set_nc_definitions
  #
   global mom_sim_vnc_msg_prefix
   if ![info exists mom_sim_vnc_msg_prefix] {
      set mom_sim_vnc_msg_prefix  "VNC_MSG::"
   }

   global mom_sim_spindle_max_rpm mom_sim_spindle_speed
   if ![info exists mom_sim_spindle_max_rpm] {
      set mom_sim_spindle_max_rpm 0
   }
   if ![info exists mom_sim_spindle_speed] {
      set mom_sim_spindle_speed 0
   }

   global mom_sim_cycle_spindle_axis
   if ![info exists mom_sim_cycle_spindle_axis] {
      set mom_sim_cycle_spindle_axis 2
   }

   if ![info exists mom_sim_nc_register(POWER_ON_WCS)] {
      set mom_sim_nc_register(POWER_ON_WCS) 0
   }

   if ![info exists mom_sim_nc_register(WCS)] {
      set mom_sim_nc_register(WCS) $mom_sim_nc_register(POWER_ON_WCS)
   }

   if { ![info exists mom_sim_nc_register(MOTION)] } {
      set mom_sim_nc_register(MOTION) RAPID
   }
   if { ![info exists mom_sim_nc_register(INPUT)] } {
      set mom_sim_nc_register(INPUT) ABS
   }
   if { ![info exists mom_sim_nc_register(STROKE_LIMIT)] } {
      set mom_sim_nc_register(STROKE_LIMIT) ON
   }
   if { ![info exists mom_sim_nc_register(CUTCOM)] } {
      set mom_sim_nc_register(CUTCOM) OFF
   }
   if { ![info exists mom_sim_nc_register(TL_ADJUST)] } {
      set mom_sim_nc_register(TL_ADJUST) OFF
   }
   if { ![info exists mom_sim_nc_register(SCALE)] } {
      set mom_sim_nc_register(SCALE) OFF
   }
   if { ![info exists mom_sim_nc_register(MACRO_MODAL)] } {
      set mom_sim_nc_register(MACRO_MODAL) OFF
   }
   if { ![info exists mom_sim_nc_register(WCS_ROTATE)] } {
      set mom_sim_nc_register(WCS_ROTATE) OFF
   }
   if { ![info exists mom_sim_nc_register(CYCLE)] } {
      set mom_sim_nc_register(CYCLE) OFF
   }
   if { ![info exists mom_sim_nc_register(CYCLE_RETURN)] } {
      set mom_sim_nc_register(CYCLE_RETURN) INIT_LEVEL
   }
   if { ![info exists mom_sim_nc_register(RETURN_HOME)] } {
      set mom_sim_nc_register(RETURN_HOME) 0
   }
   if { ![info exists mom_sim_nc_register(FROM_HOME)] } {
      set mom_sim_nc_register(FROM_HOME) 0
   }
   if { ![info exists mom_sim_nc_register(MAIN_OFFSET)] } {
      set mom_sim_nc_register(MAIN_OFFSET) [list 0.0 0.0 0.0 0.0 0.0]
   }
   if { ![info exists mom_sim_nc_register(LOCAL_OFFSET)] } {
      set mom_sim_nc_register(LOCAL_OFFSET) [list 0.0 0.0 0.0 0.0 0.0]
   }
   if { ![info exists mom_sim_nc_register(WORK_OFFSET)] } {
      set mom_sim_nc_register(WORK_OFFSET) [PB_SIM_call VNC_map_to_machine_offsets\
                                                        $mom_sim_wcs_offsets($mom_sim_nc_register(WCS))]
   }

   if { ![info exists mom_sim_nc_register(SPINDLE_DIRECTION)] } {
      set mom_sim_nc_register(SPINDLE_DIRECTION) OFF
   }
   if { ![info exists mom_sim_nc_register(SPINDLE_MODE)] } {
      set mom_sim_nc_register(SPINDLE_MODE) REV_PER_MIN
   }
   if { ![info exists mom_sim_nc_register(S)] } {
      set mom_sim_nc_register(S) 0
   }
   if { ![info exists mom_sim_nc_register(FEED_MODE)] } {
      switch $mom_sim_nc_register(UNIT) {
         MM {
            set mom_sim_nc_register(FEED_MODE) MM_PER_MIN
         }
         default {
            set mom_sim_nc_register(FEED_MODE) INCH_PER_MIN
         }
      }
   }
   if { ![info exists mom_sim_nc_register(F)] } {
      set mom_sim_nc_register(F) 0
   }

   global mom_sim_rapid_dogleg
   if ![info exists mom_sim_rapid_dogleg] {
      set mom_sim_rapid_dogleg  0
   }


#>>>>>
  # Initialize subspindle activation state
  #
   if { ![info exists mom_sim_nc_register(CROSS_MACHINING)] } {
      set mom_sim_nc_register(CROSS_MACHINING) 0
   }

  # Initialize machine mode
  #
   global mom_sim_machine_type
   if [string match "*wedm*" $mom_sim_machine_type] {
      set mom_sim_nc_register(MACHINE_MODE) WEDM
   } elseif [string match "*lathe*" $mom_sim_machine_type] {
      set mom_sim_nc_register(MACHINE_MODE) TURN
   } else {
      set mom_sim_nc_register(MACHINE_MODE) MILL
   }

  # Initialize plane code
  #
   if [string match "TURN" $mom_sim_nc_register(MACHINE_MODE)] {
      set mom_sim_nc_register(PLANE) ZX
   } else {
      set mom_sim_nc_register(PLANE) XY
   }

  # Initialize CSYS state
  #
   global mom_sim_csys_set
   if ![info exists mom_sim_csys_set] {
      set mom_sim_csys_set  0
   }

  # Initialize tool offsets
  #
   global mom_sim_tool_offset_used mom_sim_tool_offset
   if { ![info exists mom_sim_tool_offset_used] } {
      set mom_sim_tool_offset_used 0
   }

   if { ![info exists mom_sim_tool_offset] } {
      set mom_sim_tool_offset(0) 0.0
      set mom_sim_tool_offset(1) 0.0
      set mom_sim_tool_offset(2) 0.0
   }

   global mom_sim_pivot_distance
   if { ![info exists mom_sim_pivot_distance] } {
      set mom_sim_pivot_distance 0.0
   }

  # Set default N/C output unit.  This value will be used
  # when no output unit function is specified in the N/C code.
  # It's also used as the intial mode when controller is reset.
  #
   set mom_sim_nc_register(DEF_UNIT)       $mom_sim_nc_register(UNIT)

  #-----------------------------------
  # Set the machine tool driver units.
  #-----------------------------------
   if [string match "MM" $mom_sim_nc_register(UNIT)] {
      PB_SIM_call SIM_set_mtd_units "MM" 
   } else {
      PB_SIM_call SIM_set_mtd_units "INCH" 
   }

  #--------------------------------
  # Set rotary axis direction mode.
  #--------------------------------
   global mom_sim_4th_axis_direction mom_sim_5th_axis_direction
   global mom_sim_4th_axis_max_limit mom_sim_5th_axis_max_limit
   global mom_sim_4th_axis_min_limit mom_sim_5th_axis_min_limit

   if [info exists mom_sim_lg_axis(4)] {
      if { ![string match " " $mom_sim_4th_axis_direction] } {
         if [string match "MAGNITUDE_DETERMINES_DIRECTION" $mom_sim_4th_axis_direction] {
            if { [EQ_is_zero $mom_sim_4th_axis_min_limit] && [EQ_is_equal $mom_sim_4th_axis_max_limit 360.0] } {
               set mom_sim_4th_axis_direction "ALWAYS_SHORTEST"
            }
         }
         PB_SIM_call SIM_set_axis_rotary_dir_mode $mom_sim_lg_axis(4) $mom_sim_4th_axis_direction
      }
   }
   if [info exists mom_sim_lg_axis(5)] {
      if { ![string match " " $mom_sim_5th_axis_direction] } {
         if [string match "MAGNITUDE_DETERMINES_DIRECTION" $mom_sim_5th_axis_direction] {
            if { [EQ_is_zero $mom_sim_5th_axis_min_limit] && [EQ_is_equal $mom_sim_5th_axis_max_limit 360.0] } {
               set mom_sim_5th_axis_direction "ALWAYS_SHORTEST"
            }
         }
         PB_SIM_call SIM_set_axis_rotary_dir_mode $mom_sim_lg_axis(5) $mom_sim_5th_axis_direction
      }
   }


  #--------------------------------------------------------
  # Define max feed rate for each axis, if not yet defined.
  #--------------------------------------------------------
   global mom_sim_rapid_feed_rate
   global mom_sim_rapid_feed mom_sim_rapid_unit
   global mom_sim_spindle_max_rpm


   if ![info exists mom_sim_rapid_feed(X)] {
      set mom_sim_rapid_feed(X) $mom_sim_rapid_feed_rate
   }
   if ![info exists mom_sim_rapid_feed(Y)] {
      set mom_sim_rapid_feed(Y) $mom_sim_rapid_feed_rate
   }
   if ![info exists mom_sim_rapid_feed(Z)] {
      set mom_sim_rapid_feed(Z) $mom_sim_rapid_feed_rate
   }
   if ![info exists mom_sim_rapid_feed(4)] {
      set mom_sim_rapid_feed(4) $mom_sim_rapid_feed_rate
   }
   if ![info exists mom_sim_rapid_feed(5)] {
      set mom_sim_rapid_feed(5) $mom_sim_rapid_feed_rate
   }

   if ![info exists mom_sim_rapid_unit(X)] {
      set mom_sim_rapid_unit(X) $mom_sim_nc_register(FEED_MODE)
   }
   if ![info exists mom_sim_rapid_unit(Y)] {
      set mom_sim_rapid_unit(Y) $mom_sim_nc_register(FEED_MODE)
   }
   if ![info exists mom_sim_rapid_unit(Z)] {
      set mom_sim_rapid_unit(Z) $mom_sim_nc_register(FEED_MODE)
   }
   if ![info exists mom_sim_rapid_unit(4)] {
      set mom_sim_rapid_unit(4) REV_PER_MIN
   }
   if ![info exists mom_sim_rapid_unit(5)] {
      set mom_sim_rapid_unit(5) REV_PER_MIN
   }


  # Default max rpm
   global mom_sim_default_spindle_max_rpm
   if { ![info exists mom_sim_default_spindle_max_rpm] } {
      set mom_sim_default_spindle_max_rpm 10000
   }

   if { ![info exists mom_sim_spindle_max_rpm] || ![EQ_is_gt $mom_sim_spindle_max_rpm 0.0] } {
      set mom_sim_spindle_max_rpm $mom_sim_default_spindle_max_rpm
   }


  #------------------------------------------------
  # Initialize parameters required by Sync Manager
  # for the components involved in this driver.
  #
   global mom_multi_channel_mode

   if [info exists mom_multi_channel_mode] {


      global mom_sim_delay_one_block
      set mom_sim_delay_one_block 0


     # In case sync manager is not yet initialized...
      global mom_sim_sync_manager_initialized
      if ![info exists mom_sim_sync_manager_initialized] {
         PB_SIM_call PB_CMD_vnc__start_of_program
      }


      global mom_sim_result mom_sim_result1
      PB_SIM_call SIM_ask_nc_axes_of_mtool

      set axes_list {X Y Z 4 5}
      foreach axis $axes_list {
         if [info exists mom_sim_mt_axis($axis)] {
            if { [lsearch $mom_sim_result1 $mom_sim_mt_axis($axis)] >= 0 } {
               PB_SIM_call SIM_mach_max_axis_rapid_velocity $mom_sim_mt_axis($axis) $mom_sim_rapid_feed($axis) $mom_sim_rapid_unit($axis)
            }
         }
      }
   }


  #-------------------------------------------------------------------------------
  # Initialize reference CSYS w.r.t the MTCS junction with the machine model.
  # - This also establishes the machine datum csys.
  # - This matrix is also used to define the 1st version of the main & local csys.
  #
   if { $mom_sim_csys_set == 0 } {

     # Fix legacy offsets (5 elements -> 6 elements)
      set n_wcs [array size mom_sim_wcs_offsets]

      for { set i 0 } { $i < $n_wcs } { incr i } {
         if { [llength $mom_sim_wcs_offsets($i)] == 5 } {
            set mom_sim_wcs_offsets($i) [PB_SIM_call VNC_map_from_machine_offsets $mom_sim_wcs_offsets($i)]
         }
      }


     # Offsets between MTCS and the main WCS
      global mom_sim_machine_zero_offsets
      if ![info exists mom_sim_machine_zero_offsets] {
         set mom_sim_machine_zero_offsets  [list 0.0 0.0 0.0]
      }


     # Define all Work Coordinate Systems
     #
      PB_SIM_call PB_CMD_vnc__define_wcs
   }


  # Initialize cut data type
   global mom_sim_cut_data_type
   if ![info exists mom_sim_cut_data_type] {
      set mom_sim_cut_data_type "CENTERLINE"
   }
}


#=============================================================
proc PB_CMD_vnc__send_dogs_home { } {
#=============================================================
  global mom_sim_mt_axis
  global mom_sim_num_machine_axes
  global mom_sim_nc_register
  global mom_sim_result mom_sim_result1


  # Make sure the polar mode is OFF.
   PB_SIM_call SIM_set_linearization OFF


  # Determine the axes that need to move per intermediate pt specified.
   set move_X 0
   set move_Y 0
   set move_Z 0
   set move_4 0
   set move_5 0

   PB_SIM_call SIM_ask_nc_axes_of_mtool


   if [info exists mom_sim_nc_register(REF_INT_PT_X)] {
      if { [info exists mom_sim_mt_axis(X)] } {
         if { [lsearch $mom_sim_result1 "$mom_sim_mt_axis(X)"] >= 0 } {
            set move_X 1
         }
      }
   }
   if [info exists mom_sim_nc_register(REF_INT_PT_Y)] {
      if { [info exists mom_sim_mt_axis(Y)] } {
         if { [lsearch $mom_sim_result1 "$mom_sim_mt_axis(Y)"] >= 0 } {
            set move_Y 1
         }
      }
   }
   if [info exists mom_sim_nc_register(REF_INT_PT_Z)] {
      if { [info exists mom_sim_mt_axis(Z)] } {
         if { [lsearch $mom_sim_result1 "$mom_sim_mt_axis(Z)"] >= 0 } {
            set move_Z 1
         }
      }
   }

   if { $mom_sim_num_machine_axes > 3 } {
      if [info exists mom_sim_nc_register(REF_INT_PT_4)] {
         set move_4 1
      }
   }

   if { $mom_sim_num_machine_axes > 4 } {
      if [info exists mom_sim_nc_register(REF_INT_PT_5)] {
         set move_5 1
      }
   }


  # Establish machine home position in MTCS for the 1st time.
   global mom_sim_pos_mtcs
   global mom_sim_lg_axis
   global mom_sim_spindle_jct mom_sim_current_junction
   global mom_sim_pivot_jct

  # Make use of pivot junction
   if [info exists mom_sim_pivot_jct] {
      PB_SIM_call SIM_set_current_ref_junction $mom_sim_pivot_jct
      set mom_sim_current_junction "$mom_sim_pivot_jct"
   } else {
      PB_SIM_call SIM_set_current_ref_junction $mom_sim_spindle_jct
      set mom_sim_current_junction "$mom_sim_spindle_jct"
   }

  # Set RAPID mode
   PB_SIM_call VNC_set_feedrate_mode RAPID

   set time 1


  # Establish ref pt
   if { ![info exists mom_sim_pos_mtcs(0)] } {
      if $move_X {
         PB_SIM_call SIM_move_linear_axis 1 $mom_sim_mt_axis(X) [lindex $mom_sim_nc_register(REF_PT) 0]
         set ref_pt [PB_SIM_call SIM_ask_last_position_mtcs]
         set mom_sim_pos_mtcs(0) [lindex $ref_pt 0]
      }
   }
   if { ![info exists mom_sim_pos_mtcs(1)] } {
      if $move_Y {
         if [info exists mom_sim_mt_axis(Y)] {
            PB_SIM_call SIM_move_linear_axis 1 $mom_sim_mt_axis(Y) [lindex $mom_sim_nc_register(REF_PT) 1]
            set ref_pt [PB_SIM_call SIM_ask_last_position_mtcs]
            set mom_sim_pos_mtcs(1) [lindex $ref_pt 1]
         }
      }
   }
   if { ![info exists mom_sim_pos_mtcs(2)] } {
      if $move_Z {
         PB_SIM_call SIM_move_linear_axis 1 $mom_sim_mt_axis(Z) [lindex $mom_sim_nc_register(REF_PT) 2]
         set ref_pt [PB_SIM_call SIM_ask_last_position_mtcs]
         set mom_sim_pos_mtcs(2) [lindex $ref_pt 2]
      }
   }

  # Always zero rotary axes ???
   if { $mom_sim_num_machine_axes > 3 } {
     # set move_4 1
   }

   if { $mom_sim_num_machine_axes > 4 } {
     # set move_5 1
   }


   set coord_list [list]
   if $move_X {
      lappend coord_list $mom_sim_lg_axis(X)  $mom_sim_pos_mtcs(0)
   }
   if $move_Y {
      lappend coord_list $mom_sim_lg_axis(Y)  $mom_sim_pos_mtcs(1)
   }
   if $move_Z {
      lappend coord_list $mom_sim_lg_axis(Z)  $mom_sim_pos_mtcs(2)
   }


   if { [llength $coord_list] > 0 } {
      eval PB_SIM_call SIM_move_linear_mtcs $coord_list
   }


global mom_sim_message
set mom_sim_message "REF PT >$mom_sim_nc_register(REF_PT)<"
PB_CMD_vnc__send_message


  # If a rotary axis is limitless, only unwind it to the modulu of 360!
  #
   global mom_sim_num_machine_axes mom_sim_mt_axis
   global mom_sim_4th_axis_has_limits mom_sim_5th_axis_has_limits
   global mom_sim_4th_axis_direction mom_sim_5th_axis_direction

   global mom_sim_pos

   global mom_sim_4th_axis_max_limit mom_sim_4th_axis_min_limit
   global mom_sim_5th_axis_max_limit mom_sim_5th_axis_min_limit

   if [expr $mom_sim_num_machine_axes > 4] {

      if $move_5 {

         if $mom_sim_5th_axis_has_limits {

            set mom_sim_pos(4) 0

         } else {

            PB_SIM_call SIM_ask_axis_position $mom_sim_mt_axis(5)

            if { ![EQ_is_equal $mom_sim_result $mom_sim_pos(4)] } {

               PB_SIM_call SIM_normalize_rotary_axis $mom_sim_mt_axis(5) NORM_180
               set mom_sim_pos(4) 0.0

            } else {

               if [expr $mom_sim_pos(4) < 0.0] {
                  set sign -1
               } else {
                  set sign 1
               }
               set rem [expr fmod($mom_sim_pos(4),360)]
               if [expr abs($rem) > 180] {
                  set mom_sim_pos(4) [expr $mom_sim_pos(4) + $sign*360 - $rem]
               } else {
                  set mom_sim_pos(4) [expr $mom_sim_pos(4) - $rem]
               }

               if [EQ_is_zero $mom_sim_pos(4)] {
                  set mom_sim_pos(4) 0.0
               }
            }
         }

         PB_SIM_call SIM_set_interpolation OFF

         if { [EQ_is_lt $mom_sim_pos(4) $mom_sim_5th_axis_min_limit] ||\
              [EQ_is_gt $mom_sim_pos(4) $mom_sim_5th_axis_max_limit] } {

            PB_SIM_call SIM_normalize_rotary_axis $mom_sim_mt_axis(5) NORM_180
            PB_SIM_call SIM_ask_axis_position $mom_sim_mt_axis(5)
            set mom_sim_pos(4) $mom_sim_result
         }
         PB_SIM_call SIM_move_rotary_axis 5 $mom_sim_mt_axis(5) $mom_sim_pos(4)
         PB_SIM_call SIM_set_interpolation ON

      }
   }

   if [expr $mom_sim_num_machine_axes > 3] {

      if $move_4 {

         if $mom_sim_4th_axis_has_limits {

            set mom_sim_pos(3) 0

         } else {

            PB_SIM_call SIM_ask_axis_position $mom_sim_mt_axis(4)

            if { ![EQ_is_equal $mom_sim_result $mom_sim_pos(3)] } {

               PB_SIM_call SIM_normalize_rotary_axis $mom_sim_mt_axis(4) NORM_180
               set mom_sim_pos(3) 0.0

            } else {

               if [expr $mom_sim_pos(3) < 0.0] {
                  set sign -1
               } else {
                  set sign 1
               }
               set rem [expr fmod($mom_sim_pos(3),360)]
               if [expr abs($rem) > 180] {
                  set mom_sim_pos(3) [expr $mom_sim_pos(3) + $sign*360 - $rem]
               } else {
                  set mom_sim_pos(3) [expr $mom_sim_pos(3) - $rem]
               }

               if [EQ_is_zero $mom_sim_pos(3)] {
                  set mom_sim_pos(3) 0.0
               }
            }
         }

         PB_SIM_call SIM_set_interpolation OFF

         if { [EQ_is_lt $mom_sim_pos(3) $mom_sim_4th_axis_min_limit] ||\
              [EQ_is_gt $mom_sim_pos(3) $mom_sim_4th_axis_max_limit] } {

            PB_SIM_call SIM_normalize_rotary_axis $mom_sim_mt_axis(4) NORM_180
            PB_SIM_call SIM_ask_axis_position $mom_sim_mt_axis(4)
            set mom_sim_pos(3) $mom_sim_result
         }
         PB_SIM_call SIM_move_rotary_axis 5 $mom_sim_mt_axis(4) $mom_sim_pos(3)
         PB_SIM_call SIM_set_interpolation ON
      }
   }


   PB_SIM_call SIM_update


   PB_SIM_call SIM_set_current_ref_junction $mom_sim_current_junction


  # Keep track of current position
   if { ![catch {set ref_pt [PB_SIM_call SIM_ask_last_position_zcs]} ] } {
      set mom_sim_pos(0) [lindex $ref_pt 0]
      set mom_sim_pos(1) [lindex $ref_pt 1]
      set mom_sim_pos(2) [lindex $ref_pt 2]
   }


  # Zero Y for lathe mode
   if [string match "TURN" $mom_sim_nc_register(MACHINE_MODE)] {
      set mom_sim_pos(1) 0
   }


  # Zero all other axes
   set mom_sim_pos(5) 0
   set mom_sim_pos(6) 0
   set mom_sim_pos(7) 0
}


#=============================================================
proc PB_CMD_vnc__set_param_per_msg { } {
#=============================================================
# This function may not be executed in a standalone NC file
# simulation. Parameters defined here will need to be set
# some place else.
#
  global mom_sim_msg_key mom_sim_msg_word


VNC_output_debug_msg "VNC_MSG - key:$mom_sim_msg_key  word:$mom_sim_msg_word"


  #-------------------------
  # Execute user's function
  #-------------------------
   PB_SIM_call PB_CMD_vnc____set_param_per_msg


   global mom_sim_tool_number mom_sim_tool_data

   switch $mom_sim_msg_key {

      "CUT_DATA_TYPE" {
         global mom_sim_cut_data_type
         set mom_sim_cut_data_type $mom_sim_msg_word
      }

      "CONTACT_TRACKING_TYPE" {
         global mom_sim_contact_tracking_type
         set mom_sim_contact_tracking_type $mom_sim_msg_word
      }

      "CONTACT_TRACKING_DIAMETER" {
         global mom_sim_tool_cutcom_offset
         set mom_sim_tool_cutcom_offset [expr $mom_sim_msg_word / 2]
      }

      "CONTACT_TRACKING_DISTANCE" {
         global mom_sim_tool_adjust_offset
         set mom_sim_tool_adjust_offset $mom_sim_msg_word
      }

      "HELIX_PITCH" {
         global mom_sim_PI
         global mom_sim_helix_pitch
         set mom_sim_helix_pitch "[expr $mom_sim_msg_word / (2 * $mom_sim_PI)]"
      }

      "HELIX_PITCH_TYPE" {
         global mom_sim_helix_pitch_type
         set mom_sim_helix_pitch_type "$mom_sim_msg_word"
      }

      "HELIX_OUTPUT_MODE" {
         global mom_sim_helix_output_mode
         set mom_sim_helix_output_mode "$mom_sim_msg_word"
      }

      "SPINDLE_DIRECTION" {
         global mom_sim_spindle_direction
         set mom_sim_spindle_direction "$mom_sim_msg_word"
      }

      "SPINDLE_MODE" {
         global mom_sim_spindle_mode
         global mom_sim_nc_register

         switch $mom_sim_msg_word {
            RPM { set mom_sim_msg_word REV_PER_MIN }
         }
         set mom_sim_spindle_mode $mom_sim_msg_word
         set mom_sim_nc_register(SPINDLE_MODE) $mom_sim_spindle_mode
      }

      "SPINDLE_MAX_RPM" {
         global mom_sim_spindle_max_rpm

        # Set maximum spindle speed to controller's default.
         global mom_sim_default_spindle_max_rpm
         if { [EQ_is_gt $mom_sim_msg_word 0.0] } {
            set mom_sim_spindle_max_rpm "$mom_sim_msg_word"
         } else {
            set mom_sim_spindle_max_rpm $mom_sim_default_spindle_max_rpm
         }
      }

      "SPINDLE_SPEED" {
         global mom_sim_spindle_speed mom_sim_spindle_mode
         set mom_sim_spindle_speed "$mom_sim_msg_word"

         PB_SIM_call PB_CMD_vnc__set_speed
      }

      "TOOL_NUMBER" {
         set mom_sim_tool_number "$mom_sim_msg_word"

         global mom_sim_tool_change
         set mom_sim_tool_change 1

         global mom_sim_tool_carrier_id
         if [info exists mom_sim_tool_carrier_id] {
            set mom_sim_tool_data($mom_sim_tool_number,carrier_id) "\"$mom_sim_tool_carrier_id\""
         }
      }

      "TOOL_NAME" {
         global mom_sim_ug_tool_name
         set mom_sim_ug_tool_name "$mom_sim_msg_word"

        # Capture tool data in an array.
         set mom_sim_tool_data($mom_sim_tool_number,name) $mom_sim_ug_tool_name
      }

      "TOOL_TYPE" {
         global mom_sim_tool_type
         set mom_sim_tool_type "$mom_sim_msg_word"

        # Capture tool type
         if [string match "MILL*" [string toupper $mom_sim_tool_type]] {
            set type MILL
         } elseif [string match "DRILL*" [string toupper $mom_sim_tool_type]] {
            set type DRILL
         } else {
            set type TURN
         }
         set mom_sim_tool_data($mom_sim_tool_number,type) $type
      }

      "TOOL_OFFSET" {
         global mom_sim_tool_offset_used
         set mom_sim_tool_offset_used "$mom_sim_msg_word"

         set mom_sim_tool_data($mom_sim_tool_number,offset_used) $mom_sim_tool_offset_used
      }

      "TOOL_X_OFF" {
         global mom_sim_tool_offset
         set mom_sim_tool_offset(0) "$mom_sim_msg_word"

         set mom_sim_tool_data($mom_sim_tool_number,x_off) $mom_sim_tool_offset(0)
      }

      "TOOL_Y_OFF" {
         global mom_sim_tool_offset
         set mom_sim_tool_offset(1) "$mom_sim_msg_word"

         set mom_sim_tool_data($mom_sim_tool_number,y_off) $mom_sim_tool_offset(1)
      }

      "TOOL_Z_OFF" {
         global mom_sim_tool_offset
         set mom_sim_tool_offset(2) "$mom_sim_msg_word"

         set mom_sim_tool_data($mom_sim_tool_number,z_off) $mom_sim_tool_offset(2)
      }

      "TOOL_CARRIER_ID" {
         global mom_sim_tool_carrier_id
         set mom_sim_tool_carrier_id "$mom_sim_msg_word"

         if [info exists mom_sim_tool_number] {
            set mom_sim_tool_data($mom_sim_tool_number,carrier_id) "\"$mom_sim_tool_carrier_id\""
         }
      }

      "SPINDLE_GROUP" {
         global mom_sim_spindle_group
         set mom_sim_spindle_group "$mom_sim_msg_word"
      }

      "TOOL_POCKET_ID" {
         global mom_sim_tool_pocket_id
         set mom_sim_tool_pocket_id "$mom_sim_msg_word"

         set mom_sim_tool_data($mom_sim_tool_number,pocket_id) "\"$mom_sim_tool_pocket_id\""
      }

      "TOOL_DIAMETER" {
         global mom_sim_tool_diameter
         set mom_sim_tool_diameter "$mom_sim_msg_word"

         global mom_sim_cut_data_type
         if { [info exists mom_sim_cut_data_type] &&\
              [string match "CONTACT_CONTOUR" $mom_sim_cut_data_type] } {
            global mom_sim_contact_tracking_type
            if [string match "BOTTOM" $mom_sim_contact_tracking_type] {
               global mom_sim_tool_cutcom_offset
               set mom_sim_tool_cutcom_offset [expr $mom_sim_tool_diameter / 2]
            }
         }

         set mom_sim_tool_data($mom_sim_tool_number,diameter) $mom_sim_tool_diameter
      }

      "TOOL_CUTCOM_REG" {
         global mom_sim_tool_cutcom_register
         set mom_sim_tool_cutcom_register "$mom_sim_msg_word"

        # Register cutcom offset
         global mom_sim_tool_cutcom_offset

         if ![info exists mom_sim_tool_cutcom_offset] {
            set mom_sim_tool_cutcom_offset 0.0
         }

         global mom_sim_tool_cutcom_data

         set mom_sim_tool_cutcom_data($mom_sim_tool_cutcom_register) $mom_sim_tool_cutcom_offset

         set mom_sim_tool_data($mom_sim_tool_number,cutcom_register) $mom_sim_tool_cutcom_register
      }

      "TOOL_ADJUST_REG" {
         global mom_sim_tool_adjust_register
         set mom_sim_tool_adjust_register "$mom_sim_msg_word"

        # Register length offset
         global mom_sim_tool_adjust_offset

         if ![info exists mom_sim_tool_adjust_offset] {
            set mom_sim_tool_adjust_offset 0.0
         }

         global mom_sim_tool_adjust_data

         set mom_sim_tool_adjust_data($mom_sim_tool_adjust_register) $mom_sim_tool_adjust_offset

         set mom_sim_tool_data($mom_sim_tool_number,adjust_register) $mom_sim_tool_adjust_register
      }

      "HEAD_NAME" {
         global mom_sim_machine_head
         set mom_sim_machine_head "$mom_sim_msg_word"
      }

      "POST_NAME" {
         global mom_sim_post_name
         global mom_sim_vnc_handler_loaded

         set mom_sim_post_name "$mom_sim_msg_word"

         set new_vnc_file [string trim ${mom_sim_post_name}_vnc.tcl]
         set new_vnc_file [join [split $new_vnc_file \\] /]

         if { [string compare [string trim $mom_sim_vnc_handler_loaded] $new_vnc_file] } {
            uplevel #0 {
               source ${mom_sim_post_name}_vnc.tcl
            }

            PB_SIM_call PB_CMD_vnc__init_sim_vars
         }
      }

      "CYCLE_SPINDLE_AXIS" {
         global mom_sim_cycle_spindle_axis
         set mom_sim_cycle_spindle_axis "$mom_sim_msg_word"
      }

      "CSYS_FIXTURE_OFFSET" {
         global mom_sim_fixture_offset
         set mom_sim_fixture_offset "$mom_sim_msg_word"
      }

      default {
      }
   }


  # Grab CSYS_MTX_'s
  #
   global mom_sim_csys_matrix mom_sim_csys_set
   global mom_sim_csys_data

   global mom_sim_fixture_offset
   if ![info exists mom_sim_fixture_offset] {
      set mom_sim_fixture_offset 0
   }


   if [string match "CSYS_MTX_*" $mom_sim_msg_key] {
      set tokens [split $mom_sim_msg_key _]
      set idx [lindex $tokens 2]

      set mom_sim_csys_matrix($idx) "$mom_sim_msg_word"

     # Store CSYS matrix
      set mom_sim_csys_data($mom_sim_fixture_offset,$idx) "$mom_sim_msg_word"


     # When csys is completely defined, map and set ZCS junction for simulation.
      if { $idx == 11 } {

        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        # -- We don't want to override G68.1 CSYS configuration
        #    that has been defined per NC code instead of MCS object.
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
         if ![info exists mom_sim_nc_register(CSYS_ROTATION)] {

            PB_SIM_call PB_CMD_vnc__set_kinematics
            set mom_sim_csys_set 1

           # Signal a new CSYS is set (See M304 for sub-spindle)
            global mom_sim_csys_origin_initial
            set mom_sim_csys_origin_initial 1
         }
      }
   }


  # Grab NURBS data
  #
   global mom_sim_nurbs_start
   global mom_sim_nurbs_order
   global mom_sim_nurbs_knot_count
   global mom_sim_nurbs_knots
   global mom_sim_nurbs_point_count
   global mom_sim_nurbs_points
   global mom_sim_nurbs_point_end_index

   if [string match "NURBS_START" $mom_sim_msg_key] {
      set mom_sim_nurbs_start 0
   }

   if [string match "NURBS_ORDER" $mom_sim_msg_key] {
      set mom_sim_nurbs_order $mom_sim_msg_word
   }

   if [string match "NURBS_KNOT_COUNT" $mom_sim_msg_key] {
      set mom_sim_nurbs_knot_count $mom_sim_msg_word
      set mom_sim_nurbs_knots [list]
   }

   if [string match "NURBS_POINT_COUNT" $mom_sim_msg_key] {
      set mom_sim_nurbs_point_count $mom_sim_msg_word
      set mom_sim_nurbs_points [list]
      set mom_sim_nurbs_point_end_index [expr $mom_sim_nurbs_point_count - 1]
   }

   if [string match "NURBS_KNOTS*" $mom_sim_msg_key] {
      lappend mom_sim_nurbs_knots $mom_sim_msg_word
   }

  # Info of control points is the last set of parameters passed from a NURBS event.
  # (See PB_CMD_vnc__pass_nurbs_data)
  #
   if [string match "NURBS_POINTS*" $mom_sim_msg_key] {
      lappend mom_sim_nurbs_points $mom_sim_msg_word

     # When the control points list is completed, set off simulation.
      if [string match "*($mom_sim_nurbs_point_end_index,Z)*" $mom_sim_msg_key] {
         global mom_sim_nc_register
         set mom_sim_nc_register(MOTION) NURBS

         set mom_sim_nurbs_start 1
         PB_SIM_call PB_CMD_vnc__sim_motion

         VNC_unset_vars  mom_sim_nurbs_start
      }
   }


  # Nullify msg key
   set mom_sim_msg_key ""
   set mom_sim_msg_word ""
}


#=============================================================
proc PB_CMD_vnc__sim_motion { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nurbs_start


  # Disable simulation when a NURBS definition starts.
   if { [info exists mom_sim_nurbs_start] && !$mom_sim_nurbs_start } {
return
   }

  # Set feed & speed
   PB_SIM_call PB_CMD_vnc__set_feed
   PB_SIM_call PB_CMD_vnc__set_speed


  # We'll simulate the sub-spindle movements with different codes.
   if $mom_sim_nc_register(CROSS_MACHINING) {
return
   }


global mom_sim_o_buffer
global mom_sim_message
set mom_sim_message "** $mom_sim_nc_register(MOTION) -- $mom_sim_o_buffer **"
PB_CMD_vnc__send_message


  # Reset start position for next motion after a fixture offset transformation is applied.
  # - See PB_CMD_vnc__G_misc_code.
  #
   if [info exists mom_sim_nc_register(FIXTURE_OFFSET)] {

      if { ![catch {set ref_pt [PB_SIM_call SIM_ask_last_position_zcs]} ] } {
         global mom_sim_prev_pos
         set mom_sim_prev_pos(0) [lindex $ref_pt 0]
         set mom_sim_prev_pos(1) [lindex $ref_pt 1]
         set mom_sim_prev_pos(2) [lindex $ref_pt 2]
      }
   }


  # Ready parameters for polar mode simulation
   PB_SIM_call PB_CMD_vnc__start_polar_motion


  # Create a temp jct for subsequent moves incase the tool is not set properly.
   PB_SIM_call VNC_create_tmp_jct

   switch $mom_sim_nc_register(MOTION) {
      "RAPID" {
         PB_SIM_call VNC_rapid_move
      }

      "LINEAR" {
         PB_SIM_call VNC_linear_move
      }

      "CIRCULAR_CLW" {
         PB_SIM_call VNC_circular_move CLW
      }

      "CIRCULAR_CCLW" {
         PB_SIM_call VNC_circular_move CCLW
      }

      "NURBS" {
         if $mom_sim_nurbs_start {
            PB_SIM_call VNC_nurbs_move
         }
      }
   }


   if [string match "CYCLE_*" $mom_sim_nc_register(MOTION)] {
      PB_SIM_call VNC_cycle_move
   }


  # Restore ZCS base to main after the 1st move
   if [info exists mom_sim_nc_register(FIXTURE_OFFSET)] {

      global mom_sim_zcs_base mom_sim_zcs_base_MCS

      if { [info exists mom_sim_zcs_base_MCS] && ![string match "" [string trim $mom_sim_zcs_base_MCS]] }  {
         set mom_sim_zcs_base $mom_sim_zcs_base_MCS
         PB_SIM_call PB_CMD_vnc__set_kinematics
      }

      VNC_unset_vars  mom_sim_nc_register(FIXTURE_OFFSET)
   }


   PB_SIM_call PB_CMD_vnc__end_polar_motion
}


#=============================================================
proc PB_CMD_vnc__end_polar_mode { } {
#=============================================================
# This function ends polar mode and restores rotary axis configuration.
#
   global mom_sim_polar_mode

   if { [info exists mom_sim_polar_mode] && $mom_sim_polar_mode == 1 } {

      global mom_sim_pos
      global mom_sim_mt_axis

      global mom_sim_num_machine_axes
      global mom_sim_4th_axis_has_limits
      global mom_sim_5th_axis_has_limits
      global mom_sim_result

      switch $mom_sim_num_machine_axes {
         "4" {
            PB_SIM_call SIM_set_rotary_axes_config  [concat $mom_sim_mt_axis(4)]
         }
         "5" {
            PB_SIM_call SIM_set_rotary_axes_config  [concat $mom_sim_mt_axis(4) $mom_sim_mt_axis(5)]
         }
      }

      PB_SIM_call SIM_set_machining_mode MILL


     # Do not unwind rotary table, if it's limitless.
      set nx $mom_sim_num_machine_axes

      if ![eval set mom_sim_${nx}th_axis_has_limits] {

         PB_SIM_call SIM_normalize_rotary_axis $mom_sim_mt_axis($nx) NORM_180

        # Fetch current angle from machine
         PB_SIM_call SIM_ask_axis_position $mom_sim_mt_axis($nx)
         if [EQ_is_zero $mom_sim_result] {
            set mom_sim_result 0.0
            PB_SIM_call SIM_move_rotary_axis 5 $mom_sim_mt_axis($nx) 0.0
         }
         set mom_sim_pos([expr $nx - 1]) $mom_sim_result
      }
   }
}


#=============================================================
proc PB_CMD_vnc__end_polar_motion { } {
#=============================================================
# This function restores motion's sim positions after a
# polarized motion is simulated.
#
   global mom_sim_polar_mode

   if { [info exists mom_sim_polar_mode] && $mom_sim_polar_mode > 0 } {

      if { $mom_sim_polar_mode == 2 } {

         global mom_sim_pos
         global mom_sim_current_x mom_sim_current_c

        # Restore to values in the block
         set mom_sim_pos(0) $mom_sim_current_x
         set mom_sim_pos(4) $mom_sim_current_c

        return
      }

      PB_SIM_call PB_CMD_vnc__end_polar_mode
   }
}


#=============================================================
proc PB_CMD_vnc__start_polar_motion { } {
#=============================================================
# This function alters motion's sim positions for polar simulation.
# Polar mode should have been initiated when certain N/C code
# has been encounterred.
#
   global mom_sim_polar_mode

   if { [info exists mom_sim_polar_mode] && $mom_sim_polar_mode > 0 } {

     # Always turn it on here, incase it's off
      PB_SIM_call SIM_set_linearization ON

      if { $mom_sim_polar_mode == 2 } {

         PB_SIM_call PB_CMD_vnc__linearize_polar_motion

       return
      }

      global mom_sim_pos
      global mom_sim_prev_pos

      global mom_sim_lg_axis
      global mom_sim_nc_register

     # If needed, make Z move first
      if ![EQ_is_equal $mom_sim_pos(2) $mom_sim_prev_pos(2)] {
        # PB_SIM_call VNC_move_linear_zcs CUT  $mom_sim_lg_axis(Z) $mom_sim_pos(2)
        # set mom_sim_nc_register(LAST_Z) $mom_sim_pos(2)
      }


      global mom_sim_mt_axis


      if [info exists mom_sim_mt_axis(5)] {

         PB_SIM_call SIM_set_rotary_axes_config  [concat $mom_sim_mt_axis(5)]

        # C is Y
         set mom_sim_pos(1) $mom_sim_pos(4)

        # Fall back to previous angle
         set mom_sim_pos(4) $mom_sim_prev_pos(4)

      } elseif [info exists mom_sim_mt_axis(4)] {

         PB_SIM_call SIM_set_rotary_axes_config  [concat $mom_sim_mt_axis(4)]

        # C is Y
         set mom_sim_pos(1) $mom_sim_pos(3)

        # Fall back to previous angle
         set mom_sim_pos(3) $mom_sim_prev_pos(3)
      }

      global mom_sim_x_factor
      if { $mom_sim_x_factor == -1 } {
         set mom_sim_pos(0) [expr $mom_sim_pos(0)*$mom_sim_x_factor]
         set mom_sim_pos(1) [expr $mom_sim_pos(1)*$mom_sim_x_factor]
         set mom_sim_pos(5) [expr $mom_sim_pos(5)*$mom_sim_x_factor]
         set mom_sim_pos(6) [expr $mom_sim_pos(6)*$mom_sim_x_factor]
      }

      PB_SIM_call SIM_set_machining_mode MILL_CX
   }
}


#=============================================================
proc PB_CMD_vnc__G_adjust_code { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nc_func


   set codes_list [list]

   set var_list {mom_sim_nc_func(TL_ADJUST_PLUS)\
                 mom_sim_nc_func(TL_ADJUST_MINUS)\
                 mom_sim_nc_func(TL_ADJUST_CANCEL)}

   foreach var $var_list {
     if [info exists $var] {
       lappend codes_list [set $var]
     }
   }

   global mom_sim_o_buffer
   foreach code $codes_list {

      if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

         if [string match "$mom_sim_nc_func(TL_ADJUST_PLUS)" $code] {

           # When there's been a tool change, reset ref junction.
           # We may need to retrieve the actual tool length, if any, from H register.

            set mom_sim_nc_register(TL_ADJUST) PLUS

         } elseif [string match "$mom_sim_nc_func(TL_ADJUST_MINUS)"  $code] {

            set mom_sim_nc_register(TL_ADJUST) MINUS

         } elseif [string match "$mom_sim_nc_func(TL_ADJUST_CANCEL)" $code] {

            set mom_sim_nc_register(TL_ADJUST) OFF
         }

         break
      }
   }
}


#=============================================================
proc PB_CMD_vnc__G_cutcom_code { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nc_func


   set codes_list [list]

   set var_list {mom_sim_nc_func(CUTCOM_LEFT)\
                 mom_sim_nc_func(CUTCOM_RIGHT)\
                 mom_sim_nc_func(CUTCOM_OFF)}

   foreach var $var_list {
     if [info exists $var] {
       lappend codes_list [set $var]
     }
   }

   global mom_sim_o_buffer
   foreach code $codes_list {

      if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

         if [string match "$mom_sim_nc_func(CUTCOM_LEFT)" $code] {

            set mom_sim_nc_register(CUTCOM) LEFT

         } elseif [string match "$mom_sim_nc_func(CUTCOM_RIGHT)" $code] {

            set mom_sim_nc_register(CUTCOM) RIGHT

         } elseif [string match "$mom_sim_nc_func(CUTCOM_OFF)" $code] {

            set mom_sim_nc_register(CUTCOM) OFF
         }

         break
      }
   }
}


#=============================================================
proc PB_CMD_vnc__G_feed_code { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nc_func


   if [string match "IN" $mom_sim_nc_register(UNIT)] {

      set codes_list [list]

      set var_list {mom_sim_nc_func(FEED_IPM)\
                    mom_sim_nc_func(FEED_IPR)\
                    mom_sim_nc_func(FEED_FRN)}

      foreach var $var_list {
        if [info exists $var] {
          lappend codes_list [set $var]
        }
      }

      global mom_sim_o_buffer
      foreach code $codes_list {

         if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

            if [string match "$mom_sim_nc_func(FEED_IPM)" $code] {

               set mom_sim_nc_register(FEED_MODE) INCH_PER_MIN

            } elseif [string match "$mom_sim_nc_func(FEED_IPR)"  $code] {

               set mom_sim_nc_register(FEED_MODE) INCH_PER_REV

            } elseif [string match "$mom_sim_nc_func(FEED_FRN)"  $code] {

               set mom_sim_nc_register(FEED_MODE) MM_PER_100REV
            }

         break
        }
      }

   } elseif [string match "MM" $mom_sim_nc_register(UNIT)] {

      set codes_list [list]

      set var_list {mom_sim_nc_func(FEED_MMPM)\
                    mom_sim_nc_func(FEED_MMPR)\
                    mom_sim_nc_func(FEED_FRN)}

      foreach var $var_list {
        if [info exists $var] {
          lappend codes_list [set $var]
        }
      }

      global mom_sim_o_buffer
      foreach code $codes_list {

         if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

            if [string match "$mom_sim_nc_func(FEED_MMPM)" $code] {

               set mom_sim_nc_register(FEED_MODE) MM_PER_MIN

            } elseif [string match "$mom_sim_nc_func(FEED_MMPR)"  $code] {

               set mom_sim_nc_register(FEED_MODE) MM_PER_REV

            } elseif [string match "$mom_sim_nc_func(FEED_FRN)"  $code] {

               set mom_sim_nc_register(FEED_MODE) MM_PER_100REV
            }

           break
         }
      }
   }
}


#=============================================================
proc PB_CMD_vnc__G_misc_code { } {
#=============================================================
  global mom_sim_pos
  global mom_sim_nc_register
  global mom_sim_nc_func
  global mom_sim_wcs_offsets


   set codes_list [list]

   set var_list [list]
    lappend var_list mom_sim_nc_func(DELAY_SEC)
    lappend var_list mom_sim_nc_func(DELAY_REV)
    lappend var_list mom_sim_nc_func(UNIT_IN)
    lappend var_list mom_sim_nc_func(UNIT_MM)
    lappend var_list mom_sim_nc_func(RETURN_HOME)
    lappend var_list mom_sim_nc_func(RETURN_HOME_P)
    lappend var_list mom_sim_nc_func(FROM_HOME)
    lappend var_list mom_sim_nc_func(MACH_CS_MOVE)
    lappend var_list mom_sim_nc_func(WORK_CS_1)
    lappend var_list mom_sim_nc_func(WORK_CS_2)
    lappend var_list mom_sim_nc_func(WORK_CS_3)
    lappend var_list mom_sim_nc_func(WORK_CS_4)
    lappend var_list mom_sim_nc_func(WORK_CS_5)
    lappend var_list mom_sim_nc_func(WORK_CS_6)
    lappend var_list mom_sim_nc_func(LOCAL_CS_SET)
    lappend var_list mom_sim_nc_func(WORK_CS_RESET)

   foreach var $var_list {
     if [info exists $var] {
       lappend codes_list [set $var]
     }
   }

   global mom_sim_o_buffer
   foreach code $codes_list {

      if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

         if [string match "$mom_sim_nc_func(DELAY_SEC)" $code] {

         } elseif [string match "$mom_sim_nc_func(DELAY_REV)" $code] {

         } elseif [string match "$mom_sim_nc_func(UNIT_IN)" $code] {

            set mom_sim_nc_register(UNIT) IN
            PB_SIM_call SIM_set_mtd_units "INCH" 


         } elseif [string match "$mom_sim_nc_func(UNIT_MM)" $code] {

            set mom_sim_nc_register(UNIT) MM
            PB_SIM_call SIM_set_mtd_units "MM" 


         } elseif [string match "$mom_sim_nc_func(RETURN_HOME)" $code] {

           # Coord specified with this command is stored as the "intermediate point" that
           # the tool will position in rapid mode before going to the reference point.
           # Intermediate point (each axis) stays modal for future G28/G29.
           #
           # This command cancels cutcom and tool offsets.
           #
           # Axes of the "intermediate point" only exist when specified. Default it to
           # the ref. pt. will not be sufficient.
           # The int. pt. floats with respect to the active WCS (G54 - G59).
           # Reference point is fixed on a machine.
   
            set mom_sim_nc_register(RETURN_HOME) 1

           # Fetch the main home position, if any.
            global mom_sim_main_home_pos mom_sim_home_pos
            if [info exists mom_sim_main_home_pos] {
               set mom_sim_home_pos(0) $mom_sim_main_home_pos(0)
               set mom_sim_home_pos(1) $mom_sim_main_home_pos(1)
               set mom_sim_home_pos(2) $mom_sim_main_home_pos(2)
            }


         } elseif [string match "$mom_sim_nc_func(RETURN_HOME_P)" $code] {

           # G30 P2 XYZ -- Return to the 2nd ref pt. P2 can be omitted.
           # G30 P3 XYZ -- Return to the 3rd ref pt.
           # G30 P4 XYZ -- Return to the 4th ref pt.
           #
           # G30 & G28 share the same intermediate point. I think?.

            set mom_sim_nc_register(RETURN_HOME_P) 1

           # Save away the main home position.
            global mom_sim_main_home_pos
            if ![info exists mom_sim_main_home_pos] {
               set mom_sim_main_home_pos(0) $mom_sim_home_pos(0)
               set mom_sim_main_home_pos(1) $mom_sim_home_pos(1)
               set mom_sim_main_home_pos(2) $mom_sim_home_pos(2)
            }

           # Set an auxiliary home position as the target.


         } elseif [string match "$mom_sim_nc_func(FROM_HOME)" $code] {

           # This command is normally issued immediately after a G28.
           #
           # Coord specified with this function is the target that the tool will position.
           # The tool will first position from the ref. pt. to the "intermediate point"
           # that have been defined in the previous G28 command, if any, in rapid mode
           # before going to its final destination.

            set mom_sim_nc_register(FROM_HOME) 1

         } elseif [string match "$mom_sim_nc_func(WORK_CS_RESET)" $code] {

           # Disable work coord reset if S is in the block.
           # G92 is used to set max spindle speed to S register.
            global mom_sim_address
            if [VNC_parse_nc_word mom_sim_o_buffer $mom_sim_address(S,leader) 2] {
return
            }


           # G92 redefines the 0th WCS (main CSYS). This can also be done with "G10 L2 P0 X Y Z",
           # MDI'ed or set by machine builder.  Both G92 & G10 observe G90/G91 mode.
           # The coordinates in the block will be used to calculate the offsets in
           # PB_CMD_vnc__reset_coordinate. No motion will be produced.
           #
           # Offsets will be added to the subsequent moves regardless of which WCS is in use.
           #
           # Subsequent reference to any of the WCS will have the offsets in effect, until
           # a Manual Reference Point Return (G28?) cancels G92 and all WCSs return to normal (??).


            set mom_sim_nc_register(RESET_WCS) 1

           # Defer offsets calculation until entire block is parsed.
            set mom_sim_nc_register(MAIN_OFFSET)  [list 0.0 0.0 0.0 0.0 0.0]

global mom_sim_message
set mom_sim_message "-- RESET WCS"
PB_CMD_vnc__send_message


         } elseif [string match "$mom_sim_nc_func(LOCAL_CS_SET)" $code] {

           # Specify a local coordiante system within the active WCS.
           # Offsets will ONLY be applied to the WCS in effect.
           # Change of WCS or return cancels the offsets.
           # G52 IP0(i.e. 0 0 0) or G92 command also cancels this mode.


            set mom_sim_nc_register(SET_LOCAL) 1

           # Defer offsets calculation until entire block is parsed.
            set mom_sim_nc_register(LOCAL_OFFSET) [list 0.0 0.0 0.0 0.0 0.0]


         } elseif [string match "$mom_sim_nc_func(MACH_CS_MOVE)" $code] {

           # Moves to a position in the Machine Coordinate System (MCS).
           # The origin of MCS (Machine Zero, Machine Datum) never changes.
           # One shot instruction block. Ignored in incremental mode (G91).
           # MCS is never affected by G92 or G52 (LCS) until machine is powered off.
           # (I think, guess), G53 is used in the M06 macro for the tool change.
           #
           # ** It's ignored in (G91) incremental mode!
           # ** It's a one-shot instruction!

            if [string match "ABS" $mom_sim_nc_register(INPUT)] {

               set mom_sim_nc_register(MCS_MOVE) 1

              # Preserve and fake the offsets. Restore them after the move.
               global mom_sim_prev_main_offsets mom_sim_prev_local_offsets

               set mom_sim_prev_main_offsets  $mom_sim_nc_register(MAIN_OFFSET)
               set mom_sim_prev_local_offsets $mom_sim_nc_register(LOCAL_OFFSET)

               set mom_sim_nc_register(MAIN_OFFSET)  [list 0.0 0.0 0.0 0.0 0.0]
               set mom_sim_nc_register(LOCAL_OFFSET) [list 0.0 0.0 0.0 0.0 0.0]
               set mom_sim_nc_register(WORK_OFFSET)  [list 0.0 0.0 0.0 0.0 0.0]

 
              # Set ref. csys to Machine Zero CSYS on main ZCS component
               global mom_sim_machine_zero_csys_matrix
               global mom_sim_prev_csys_matrix
               global mom_sim_csys_matrix
               global mom_sim_prev_zcs_base mom_sim_zcs_base mom_sim_zcs_base_MCS

               array set mom_sim_prev_csys_matrix [array get mom_sim_csys_matrix]
               array set mom_sim_csys_matrix      [array get mom_sim_machine_zero_csys_matrix]

               set mom_sim_prev_zcs_base $mom_sim_zcs_base
               if [info exists mom_sim_zcs_base_MCS] {
                  set mom_sim_zcs_base $mom_sim_zcs_base_MCS
               }
               PB_SIM_call PB_CMD_vnc__set_kinematics
            }

           #<12-06-06 gsl>
            global mom_sim_csys_set
            set mom_sim_csys_set 1

         } elseif [string match "$mom_sim_nc_func(WORK_CS_1)" $code] {

           # Select Work Coordinate System.
           # G54 is selected when powered on (?).

            set mom_sim_nc_register(WCS) 1
            set mom_sim_nc_register(WORK_OFFSET) [PB_SIM_call VNC_map_to_machine_offsets $mom_sim_wcs_offsets(1)]

         } elseif [string match "$mom_sim_nc_func(WORK_CS_2)" $code] {

            set mom_sim_nc_register(WCS) 2
            set mom_sim_nc_register(WORK_OFFSET) [PB_SIM_call VNC_map_to_machine_offsets $mom_sim_wcs_offsets(2)]

         } elseif [string match "$mom_sim_nc_func(WORK_CS_3)" $code] {

            set mom_sim_nc_register(WCS) 3
            set mom_sim_nc_register(WORK_OFFSET) [PB_SIM_call VNC_map_to_machine_offsets $mom_sim_wcs_offsets(3)]

         } elseif [string match "$mom_sim_nc_func(WORK_CS_4)" $code] {

            set mom_sim_nc_register(WCS) 4
            set mom_sim_nc_register(WORK_OFFSET) [PB_SIM_call VNC_map_to_machine_offsets $mom_sim_wcs_offsets(4)]

         } elseif [string match "$mom_sim_nc_func(WORK_CS_5)" $code] {

            set mom_sim_nc_register(WCS) 5
            set mom_sim_nc_register(WORK_OFFSET) [PB_SIM_call VNC_map_to_machine_offsets $mom_sim_wcs_offsets(5)]

         } elseif [string match "$mom_sim_nc_func(WORK_CS_6)" $code] {

            set mom_sim_nc_register(WCS) 6
            set mom_sim_nc_register(WORK_OFFSET) [PB_SIM_call VNC_map_to_machine_offsets $mom_sim_wcs_offsets(6)]
         }


        # Perform CSYS transformation per choice of WCS.
         global mom_sim_csys_data

         if [info exists mom_sim_csys_data] {

            if [string match "$mom_sim_nc_func(MACH_CS_MOVE)" $code] {


            } elseif { [string match "$mom_sim_nc_func(WORK_CS_1)" $code] || [string match "$mom_sim_nc_func(WORK_CS_2)" $code] || [string match "$mom_sim_nc_func(WORK_CS_3)" $code] || [string match "$mom_sim_nc_func(WORK_CS_4)" $code] || [string match "$mom_sim_nc_func(WORK_CS_5)" $code] || [string match "$mom_sim_nc_func(WORK_CS_6)" $code] } {


              # Zero local offsets when change WCS
               set mom_sim_nc_register(LOCAL_OFFSET) [list 0.0 0.0 0.0 0.0 0.0]

              # Zero WCS offsets, since the actual CSYS will be referenced.
               set mom_sim_nc_register(WORK_OFFSET) [list 0.0 0.0 0.0 0.0 0.0]


#<05-05-06 gsl> ZCS base reassignment seems to cause problem with MS NT4200 driver.
if 0 {
              # Apply local CSYS transformation and reassign ZCS base to allow rotation
               global mom_sim_zcs_base mom_sim_zcs_base_LCS
               if { [info exists mom_sim_zcs_base_LCS] && [string length $mom_sim_zcs_base_LCS] > 0 } {
                  set mom_sim_zcs_base $mom_sim_zcs_base_LCS
               }
}

              # Fetch actual WCS matrix per WCS selection by G54 - G59 code.
               global mom_sim_csys_matrix

               for { set i 0 } { $i < 12 } { incr i } {
                  set mom_sim_csys_matrix($i) $mom_sim_csys_data($mom_sim_nc_register(WCS),$i)
               }

               PB_SIM_call PB_CMD_vnc__set_kinematics

              #<12-06-06 gsl>
               global mom_sim_csys_set
               set mom_sim_csys_set 1

              # Flag to reset (adjust) the start position in next motion. (See PB_CMD_vnc__sim_motion)
               set mom_sim_nc_register(FIXTURE_OFFSET) 1
            }
         }

         break
      }
   }
}


#=============================================================
proc PB_CMD_vnc__G_mode_code { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nc_func


   set codes_list [list]

   set var_list {mom_sim_nc_func(INPUT_ABS)\
                 mom_sim_nc_func(INPUT_INC)}

   foreach var $var_list {
     if [info exists $var] {
       lappend codes_list [set $var]
     }
   }

   global mom_sim_o_buffer
   foreach code $codes_list {

      if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

         if [string match "$mom_sim_nc_func(INPUT_ABS)" $code] {

            set mom_sim_nc_register(INPUT) ABS

         } elseif [string match "$mom_sim_nc_func(INPUT_INC)" $code] {

            set mom_sim_nc_register(INPUT) INC
         }

         break
      }
   }
}


#=============================================================
proc PB_CMD_vnc__G_motion_code { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nc_func


   set codes_list [list]

   set var_list [list]
    lappend var_list mom_sim_nc_func(MOTION_RAPID)
    lappend var_list mom_sim_nc_func(MOTION_LINEAR)
    lappend var_list mom_sim_nc_func(MOTION_CIRCULAR_CLW)
    lappend var_list mom_sim_nc_func(MOTION_CIRCULAR_CCLW)
    lappend var_list mom_sim_nc_func(CYCLE_DRILL)
    lappend var_list mom_sim_nc_func(CYCLE_DRILL_DWELL)
    lappend var_list mom_sim_nc_func(CYCLE_DRILL_DEEP)
    lappend var_list mom_sim_nc_func(CYCLE_DRILL_BREAK_CHIP)
    lappend var_list mom_sim_nc_func(CYCLE_TAP)
    lappend var_list mom_sim_nc_func(CYCLE_BORE)
    lappend var_list mom_sim_nc_func(CYCLE_BORE_DRAG)
    lappend var_list mom_sim_nc_func(CYCLE_BORE_NO_DRAG)
    lappend var_list mom_sim_nc_func(CYCLE_BORE_BACK)
    lappend var_list mom_sim_nc_func(CYCLE_BORE_MANUAL)
    lappend var_list mom_sim_nc_func(CYCLE_BORE_MANUAL_DWELL)
    lappend var_list mom_sim_nc_func(CYCLE_START)
    lappend var_list mom_sim_nc_func(CYCLE_OFF)

   foreach var $var_list {
     if [info exists $var] {
       lappend codes_list [set $var]
     }
   }

   global mom_sim_o_buffer
   foreach code $codes_list {

      if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

         if [string match "$mom_sim_nc_func(MOTION_RAPID)"               $code] {

            set mom_sim_nc_register(MOTION) "RAPID"

         } elseif [string match "$mom_sim_nc_func(MOTION_LINEAR)"        $code] {

            set mom_sim_nc_register(MOTION) "LINEAR"

         } elseif [string match "$mom_sim_nc_func(MOTION_CIRCULAR_CLW)"  $code] {

            set mom_sim_nc_register(MOTION) "CIRCULAR_CLW"

         } elseif [string match "$mom_sim_nc_func(MOTION_CIRCULAR_CCLW)" $code] {

            set mom_sim_nc_register(MOTION) "CIRCULAR_CCLW"

         } elseif [string match "$mom_sim_nc_func(CYCLE_DRILL)"          $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_DRILL"

         } elseif [string match "$mom_sim_nc_func(CYCLE_DRILL_DWELL)"    $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_DRILL_DWELL"

         } elseif [string match "$mom_sim_nc_func(CYCLE_DRILL_DEEP)"     $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_DRILL_DEEP"

         } elseif [string match "$mom_sim_nc_func(CYCLE_DRILL_BREAK_CHIP)"  $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_DRILL_BREAK_CHIP"

         } elseif [string match "$mom_sim_nc_func(CYCLE_TAP)"               $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_TAP"

         } elseif [string match "$mom_sim_nc_func(CYCLE_BORE)"              $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_BORE"

         } elseif [string match "$mom_sim_nc_func(CYCLE_BORE_DRAG)"         $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_BORE_DRAG"

         } elseif [string match "$mom_sim_nc_func(CYCLE_BORE_NO_DRAG)"      $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_BORE_NO_DRAG"

         } elseif [string match "$mom_sim_nc_func(CYCLE_BORE_BACK)"         $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_BORE_BACK"

         } elseif [string match "$mom_sim_nc_func(CYCLE_BORE_MANUAL)"       $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_BORE_MANUAL"

         } elseif [string match "$mom_sim_nc_func(CYCLE_BORE_MANUAL_DWELL)" $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_BORE_MANUAL_DWELL"

         } elseif [string match "$mom_sim_nc_func(CYCLE_START)"             $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_START"

         } elseif [string match "$mom_sim_nc_func(CYCLE_OFF)"               $code] {

            set mom_sim_nc_register(MOTION) "CYCLE_OFF"

           # Cycle Off - force tool to move to the initial pt (entry pos) of next set of holes.
            global mom_sim_pos mom_sim_cycle_retract_to_pos
            if [info exists mom_sim_cycle_retract_to_pos] {
               set mom_sim_pos(0) $mom_sim_cycle_retract_to_pos(0)
               set mom_sim_pos(1) $mom_sim_cycle_retract_to_pos(1)
               set mom_sim_pos(2) $mom_sim_cycle_retract_to_pos(2)
            }
         }

         break
      }
   }
}


#=============================================================
proc PB_CMD_vnc__G_plane_code { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nc_func
  global mom_sim_cycle_spindle_axis


   set codes_list [list]

   set var_list {mom_sim_nc_func(PLANE_XY)\
                 mom_sim_nc_func(PLANE_YZ)\
                 mom_sim_nc_func(PLANE_ZX)}

   foreach var $var_list {
     if [info exists $var] {
       lappend codes_list [set $var]
     }
   }

   global mom_sim_o_buffer
   foreach code $codes_list {

      if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

         if [string match "$mom_sim_nc_func(PLANE_XY)"        $code] {

            set mom_sim_nc_register(PLANE) XY
            set mom_sim_cycle_spindle_axis 2

         } elseif [string match "$mom_sim_nc_func(PLANE_YZ)"  $code] {

            set mom_sim_nc_register(PLANE) YZ
            set mom_sim_cycle_spindle_axis 0

         } elseif [string match "$mom_sim_nc_func(PLANE_ZX)"  $code] {

            set mom_sim_nc_register(PLANE) ZX
            set mom_sim_cycle_spindle_axis 1
         }

         break
      }
   }
}


#=============================================================
proc PB_CMD_vnc__G_spin_code { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nc_func


   if [string match "IN" $mom_sim_nc_register(UNIT)] {

      set codes_list [list]

      set var_list {mom_sim_nc_func(SPEED_SFM)\
                    mom_sim_nc_func(SPEED_RPM)}

      foreach var $var_list {
        if [info exists $var] {
          lappend codes_list [set $var]
        }
      }

      global mom_sim_o_buffer
      foreach code $codes_list {

         if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

            if [string match "$mom_sim_nc_func(SPEED_SFM)" $code] {

               set mom_sim_nc_register(SPINDLE_MODE) SFM

            } elseif [string match "$mom_sim_nc_func(SPEED_RPM)"  $code] {

               set mom_sim_nc_register(SPINDLE_MODE) REV_PER_MIN
            }

            break
         }
      }

   } else {

      set codes_list [list]

      set var_list {mom_sim_nc_func(SPEED_SMM)\
                    mom_sim_nc_func(SPEED_RPM)}

      foreach var $var_list {
        if [info exists $var] {
          lappend codes_list [set $var]
        }
      }

      global mom_sim_o_buffer
      foreach code $codes_list {

         if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

            if [string match "$mom_sim_nc_func(SPEED_SMM)"  $code] {

               set mom_sim_nc_register(SPINDLE_MODE) SMM

            } elseif [string match "$mom_sim_nc_func(SPEED_RPM)"  $code] {

               set mom_sim_nc_register(SPINDLE_MODE) REV_PER_MIN
            }

            break
         }
      }
   }
}


#=============================================================
proc PB_CMD_vnc__M_coolant_code { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nc_func


   set codes_list [list]

   set var_list {mom_sim_nc_func(COOLANT_ON)\
                 mom_sim_nc_func(COOLANT_FLOOD)\
                 mom_sim_nc_func(COOLANT_MIST)\
                 mom_sim_nc_func(COOLANT_TAP)\
                 mom_sim_nc_func(COOLANT_OFF)\
                 mom_sim_nc_func(COOLANT_THRU)}

   foreach var $var_list {
     if [info exists $var] {
       lappend codes_list [set $var]
     }
   }

   global mom_sim_o_buffer
   foreach code $codes_list {

      if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

         if [string match "$mom_sim_nc_func(COOLANT_OFF)" $code] {
            PB_SIM_call SIM_set_coolant OFF
         } else {
            PB_SIM_call SIM_set_coolant ON
         }

         break
      }
   }
}


#=============================================================
proc PB_CMD_vnc__M_misc_code { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nc_func


   set codes_list [list]

   set var_list {mom_sim_nc_func(PROG_STOP)\
                 mom_sim_nc_func(PROG_OPSTOP)\
                 mom_sim_nc_func(PROG_END)\
                 mom_sim_nc_func(TOOL_CHANGE)\
                 mom_sim_nc_func(PROG_STOP_REWIND)}

   foreach var $var_list {
     if [info exists $var] {
       lappend codes_list [set $var]
     }
   }

   global mom_sim_o_buffer

   foreach code $codes_list {

      if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

         if [string match "$mom_sim_nc_func(PROG_STOP)"         $code] {

         } elseif [string match "$mom_sim_nc_func(PROG_OPSTOP)" $code] {

         } elseif [string match "$mom_sim_nc_func(PROG_END)"    $code] {

           # Reset following functions on NC controller to the initial state.
           # (Fanuc System 9 Series)
           #
           #  G22 - Store stroke limit function ON
           #  G40 - Cutcom OFF
           #  G49 - Tool length adjust OFF
           #  G50 - Scaling OFF
           #  G54 - Work coordinate system 1
           #  G64 - Cutting mode
           #  G67 - Macro modal call cancel
           #  G69 - Coordinate system rotation OFF
           #  G80 - Canned cycle cancel
           #  G98 - Return to initial level (cycle)

            PB_SIM_call VNC_reset_controller

         } elseif [string match "$mom_sim_nc_func(TOOL_CHANGE)"      $code] {

            PB_SIM_call VNC_tool_change

         } elseif [string match "$mom_sim_nc_func(PROG_STOP_REWIND)" $code] {

            PB_SIM_call VNC_rewind_stop_program

         } else {
         }

         break
      }
   }
}


#=============================================================
proc PB_CMD_vnc__M_spindle_code { } {
#=============================================================
  global mom_sim_nc_register
  global mom_sim_nc_func


   set codes_list [list]

   set var_list {mom_sim_nc_func(SPINDLE_CLW)\
                 mom_sim_nc_func(SPINDLE_CCLW)\
                 mom_sim_nc_func(SPINDLE_OFF)}

   foreach var $var_list {
     if [info exists $var] {
       lappend codes_list [set $var]
     }
   }

   global mom_sim_o_buffer
   foreach code $codes_list {

      if [VNC_parse_nc_word mom_sim_o_buffer $code 1] {

         if [string match "$mom_sim_nc_func(SPINDLE_CLW)" $code] {

            set mom_sim_nc_register(SPINDLE_DIRECTION) CLW

         } elseif [string match "$mom_sim_nc_func(SPINDLE_CCLW)"  $code] {

            set mom_sim_nc_register(SPINDLE_DIRECTION) CCLW

         } elseif [string match "$mom_sim_nc_func(SPINDLE_OFF)"  $code] {

            set mom_sim_nc_register(SPINDLE_DIRECTION) OFF
         }

         break
      }
   }
}



