Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

rs274ngc_pre.cc

Go to the documentation of this file.
00001 /* rs274ngc.cc
00002 
00003 This rs274ngc.cc file contains the source code for (1) the kernel of
00004 several rs274ngc interpreters and (2) two of the four sets of interface
00005 functions declared in canon.hh:
00006 1. interface functions to call to tell the interpreter what to do.
00007    These all return a status value.
00008 2. interface functions to call to get information from the interpreter.
00009 
00010 Kernel functions call each other. A few kernel functions are called by
00011 interface functions.
00012 
00013 Interface function names all begin with "rs274ngc_".
00014 
00015 Error handling is by returning a status value of either a non-error
00016 code (RS274NGC_OK, RS274NGC_EXIT, etc.) or some specific error code
00017 from each function where there is a possibility of error.  If an error
00018 occurs, processing is always stopped, and control is passed back up
00019 through the function call hierarchy to an interface function; the
00020 error code is also passed back up. The stack of functions called is
00021 also recorded. The external program calling an interface function may
00022 then handle the error further as it sees fit.
00023 
00024 Since returned values are usually used as just described to handle the
00025 possibility of errors, an alternative method of passing calculated
00026 values is required. In general, if function A needs a value for
00027 variable V calculated by function B, this is handled by passing a
00028 pointer to V from A to B, and B calculates and sets V.
00029 
00030 There are a lot of functions named read_XXXX. All such functions read
00031 characters from a string using a counter. They all reset the counter
00032 to point at the character in the string following the last one used by
00033 the function. The counter is passed around from function to function
00034 by using pointers to it. The first character read by each of these
00035 functions is expected to be a member of some set of characters (often
00036 a specific character), and each function checks the first character.
00037 
00038 This version of the interpreter not saving input lines. A list of all
00039 lines will be needed in future versions to implement loops, and
00040 probably for other purposes.
00041 
00042 This version does not use any additional memory as it runs. No
00043 memory is allocated by the source code.
00044 
00045 This version does not suppress superfluous commands, such as a command
00046 to start the spindle when the spindle is already turning, or a command
00047 to turn on flood coolant, when flood coolant is already on.  When the
00048 interpreter is being used for direct control of the machining center,
00049 suppressing superfluous commands might confuse the user and could be
00050 dangerous, but when it is used to translate from one file to another,
00051 suppression can produce more concise output. Future versions might
00052 include an option for suppressing superfluous commands.
00053 
00054 This file has been arranged typographically so that it may be used
00055 for compiling fifteen different executables. The file may be compiled
00056 as is for a six-axis interpreter. The file may be pre-preprocessed
00057 into "pre.cc" by "prepre" (a lex-based pre-processor). All
00058 fifteen executables may be compiled from the pre.cc file. The special
00059 typography items are:
00060 
00061 1. Any line with the comment /^AA^/, /^BB^/, or /^CC^/ at the end
00062 (where ^ is replaced by *).
00063 
00064 2. Calls to the canonical functions STRAIGHT_FEED, STRAIGHT_TRAVERSE,
00065 STRAIGHT_PROBE, and ARC_FEED. These are always set on two lines
00066 with the rotary axes on the second line:
00067 
00068 3. Calls to the canonical function SET_ORIGIN_OFFSETS.  These are
00069 always set on six lines, with one argument per line.
00070 
00071 4. Anywhere else AA, BB, or CC appears followed by an underscore.
00072 
00073 The pre-preprocessor looks for these items of typography and, in the output
00074 file (pre.cc), resets them appropriately marked with #ifdef and #endif.
00075 The rest of the text is put into the output file unchanged.
00076 
00077 The compiler flags are:
00078 
00079 1. -DAA to have an A-axis
00080 
00081 2. -DBB to have a B-axis
00082 
00083 3. -DCC to have a C-axis
00084 
00085 4. -DALL_AXES to have a 3-, 4-, or 5-axis interpreter use all three
00086 rotary axes in canonical function calls. In those calls, the value
00087 for a rotary axis not compiled into an interpreter is always zero.
00088 
00089 5. -DAXIS_ERROR to have a 3-, 4-, or 5-axis interpreter signal an error
00090 if the input RS274 code has a value for an axis not compiled in. If
00091 this flag is not used, the interpreter will read and ignore values for
00092 axes not compiled in.
00093 
00094 */
00095 
00096 /****************************************************************************/
00097 
00098 #include <stdio.h>
00099 #include <stdlib.h>
00100 #include <math.h>
00101 #include <string.h>
00102 #include <ctype.h>
00103 #include "rs274ngc.hh"
00104 #include "rs274ngc_return.hh"
00105 #include "rs274ngc_errors.cc"
00106 
00107 #define DEBUG_EMC
00108 
00109 /*
00110 
00111 The _setup model includes a stack array for the names of function
00112 calls. This stack is written into if an error occurs. Just before each
00113 function returns an error code, it writes its name in the next
00114 available string, initializes the following string, and increments
00115 the array index. The following four macros do the work.
00116 
00117 The size of the stack array is 50. An error in the middle of a very
00118 complex expression would cause the ERP and CHP macros to write past the
00119 bounds of the array if a check were not provided. No real program
00120 would contain such a thing, but the check is included to make the
00121 macros totally crash-proof. If the function call stack is deeper than
00122 49, the top of the stack will be missing.
00123 
00124 */
00125 
00126 #define ERM(error_code) if (1) {                    \
00127   _setup.stack_index SET_TO 0;                      \
00128   strcpy(_setup.stack[_setup.stack_index++], name); \
00129   _setup.stack[_setup.stack_index][0] SET_TO 0;     \
00130   return error_code;                                \
00131   } else
00132 
00133 #define ERP(error_code) if (_setup.stack_index < 49) { \
00134   strcpy(_setup.stack[_setup.stack_index++], name);    \
00135   _setup.stack[_setup.stack_index][0] SET_TO 0;        \
00136   return error_code;                                   \
00137   } else return error_code
00138 
00139 #define CHK(bad, error_code) if (bad) {             \
00140   _setup.stack_index SET_TO 0;                      \
00141   strcpy(_setup.stack[_setup.stack_index++], name); \
00142   _setup.stack[_setup.stack_index][0] SET_TO 0;     \
00143   return error_code;                                \
00144   } else
00145 
00146 #define CHP(try_this)                                      \
00147   if ((status SET_TO (try_this)) ISNT RS274NGC_OK) {       \
00148      if (_setup.stack_index < 49)                          \
00149         {strcpy(_setup.stack[_setup.stack_index++], name); \
00150          _setup.stack[_setup.stack_index][0] SET_TO 0;     \
00151          return status;}                                   \
00152      else {return status;}                                 \
00153   } else
00154 
00155 /*
00156 
00157 Function prototypes for all static functions
00158 
00159 */
00160 
00161 static int arc_data_comp_ijk(int move, int side, double tool_radius,
00162   double current_x, double current_y, double end_x, double end_y,
00163   double i_number, double j_number, double * center_x, double * center_y,
00164   int * turn, double tolerance);
00165 static int arc_data_comp_r(int move, int side, double tool_radius,
00166   double current_x, double current_y, double end_x, double end_y,
00167   double big_radius, double * center_x, double * center_y, int * turn);
00168 static int arc_data_ijk(int move, double current_x, double current_y,
00169   double end_x, double end_y, double i_number, double j_number,
00170   double * center_x, double * center_y, int * turn, double tolerance);
00171 static int arc_data_r(int move, double current_x, double current_y,
00172   double end_x, double end_y, double radius, double * center_x,
00173   double * center_y, int * turn);
00174 static int check_g_codes(block_pointer block, setup_pointer settings);
00175 static int check_items(block_pointer block, setup_pointer settings);
00176 static int check_m_codes(block_pointer block);
00177 static int check_other_codes(block_pointer block);
00178 static int close_and_downcase(char * line);
00179 static int convert_arc(int move, block_pointer block, setup_pointer settings);
00180 static int convert_arc2(int move, block_pointer block,
00181   setup_pointer settings, double * current1, double * current2,
00182   double * current3, double end1, double end2,
00183   double end3
00184 #ifdef AA
00185 , double AA_end
00186 #endif
00187 
00188 #ifdef BB
00189 , double BB_end
00190 #endif
00191 
00192 #ifdef CC
00193 , double CC_end
00194 #endif
00195 , double offset1,
00196   double offset2);
00197 static int convert_arc_comp1(int move, block_pointer block,
00198   setup_pointer settings, double end_x, double end_y,
00199   double end_z
00200 #ifdef AA
00201 , double AA_end
00202 #endif
00203 
00204 #ifdef BB
00205 , double BB_end
00206 #endif
00207 
00208 #ifdef CC
00209 , double CC_end
00210 #endif
00211 );
00212 static int convert_arc_comp2(int move, block_pointer block,
00213   setup_pointer settings, double end_x, double end_y,
00214   double end_z
00215 #ifdef AA
00216 , double AA_end
00217 #endif
00218 
00219 #ifdef BB
00220 , double BB_end
00221 #endif
00222 
00223 #ifdef CC
00224 , double CC_end
00225 #endif
00226 );
00227 static int convert_axis_offsets(int g_code, block_pointer block,
00228   setup_pointer settings);
00229 static int convert_comment(char * comment);
00230 static int convert_control_mode(int g_code, setup_pointer settings);
00231 static int convert_coordinate_system(int g_code, setup_pointer settings);
00232 static int convert_cutter_compensation(int g_code, block_pointer block,
00233   setup_pointer settings);
00234 static int convert_cutter_compensation_off(setup_pointer settings);
00235 static int convert_cutter_compensation_on(int side, block_pointer block,
00236   setup_pointer settings);
00237 static int convert_cycle(int motion, block_pointer block,
00238   setup_pointer settings);
00239 static int convert_cycle_g81(CANON_PLANE plane, double x, double y,
00240   double clear_z, double bottom_z);
00241 static int convert_cycle_g82(CANON_PLANE plane, double x, double y,
00242   double clear_z, double bottom_z, double dwell);
00243 static int convert_cycle_g83(CANON_PLANE plane, double x, double y,
00244   double r, double clear_z, double bottom_z, double delta);
00245 static int convert_cycle_g84(CANON_PLANE plane, double x, double y,
00246   double clear_z, double bottom_z, CANON_DIRECTION direction,
00247   CANON_SPEED_FEED_MODE mode);
00248 static int convert_cycle_g85(CANON_PLANE plane, double x, double y,
00249   double clear_z, double bottom_z);
00250 static int convert_cycle_g86(CANON_PLANE plane, double x, double y,
00251   double clear_z, double bottom_z, double dwell, CANON_DIRECTION direction);
00252 static int convert_cycle_g87(CANON_PLANE plane, double x, double offset_x,
00253   double y, double offset_y, double r, double clear_z, double middle_z,
00254   double bottom_z, CANON_DIRECTION direction);
00255 static int convert_cycle_g88(CANON_PLANE plane, double x, double y,
00256   double bottom_z, double dwell, CANON_DIRECTION direction);
00257 static int convert_cycle_g89(CANON_PLANE plane, double x, double y,
00258   double clear_z, double bottom_z, double dwell);
00259 static int convert_cycle_xy(int motion, block_pointer block,
00260   setup_pointer settings);
00261 static int convert_cycle_yz(int motion, block_pointer block,
00262   setup_pointer settings);
00263 static int convert_cycle_zx(int motion, block_pointer block,
00264   setup_pointer settings);
00265 static int convert_distance_mode(int g_code, setup_pointer settings);
00266 static int convert_dwell(double time);
00267 static int convert_feed_mode(int g_code, setup_pointer settings);
00268 static int convert_feed_rate(block_pointer block, setup_pointer settings);
00269 static int convert_g(block_pointer block, setup_pointer settings);
00270 static int convert_home(int move, block_pointer block, setup_pointer settings);
00271 static int convert_length_units(int g_code, setup_pointer settings);
00272 static int convert_m(block_pointer block, setup_pointer settings);
00273 static int convert_modal_0(int code, block_pointer block,
00274   setup_pointer settings);
00275 static int convert_motion(int motion, block_pointer block,
00276   setup_pointer settings);
00277 static int convert_probe(block_pointer block, setup_pointer settings);
00278 static int convert_retract_mode(int g_code, setup_pointer settings);
00279 static int convert_setup(block_pointer block, setup_pointer settings);
00280 static int convert_set_plane(int g_code, setup_pointer settings);
00281 static int convert_speed(block_pointer block, setup_pointer settings);
00282 static int convert_stop(block_pointer block, setup_pointer settings);
00283 static int convert_straight(int move, block_pointer block,
00284   setup_pointer settings);
00285 static int convert_straight_comp1(int move, block_pointer block,
00286   setup_pointer settings, double px, double py,
00287   double end_z
00288 #ifdef AA
00289 , double AA_end
00290 #endif
00291 
00292 #ifdef BB
00293 , double BB_end
00294 #endif
00295 
00296 #ifdef CC
00297 , double CC_end
00298 #endif
00299 );
00300 static int convert_straight_comp2(int move, block_pointer block,
00301   setup_pointer settings, double px, double py,
00302   double end_z
00303 #ifdef AA
00304 , double AA_end
00305 #endif
00306 
00307 #ifdef BB
00308 , double BB_end
00309 #endif
00310 
00311 #ifdef CC
00312 , double CC_end
00313 #endif
00314 );
00315 static int convert_tool_change(setup_pointer settings);
00316 static int convert_tool_length_offset(int g_code, block_pointer block,
00317   setup_pointer settings);
00318 static int convert_tool_select(block_pointer block, setup_pointer settings);
00319 static int cycle_feed(CANON_PLANE plane, double end1,
00320   double end2, double end3);
00321 static int cycle_traverse(CANON_PLANE plane, double end1, double end2,
00322   double end3);
00323 static int enhance_block(block_pointer block, setup_pointer settings);
00324 static int execute_binary(double * left, int operation, double * right);
00325 static int execute_binary1(double * left, int operation, double * right);
00326 static int execute_binary2(double * left, int operation, double * right);
00327 static int execute_block(block_pointer block, setup_pointer settings);
00328 static int execute_unary(double * double_ptr, int operation);
00329 static double find_arc_length(double x1, double y1, double z1,
00330   double center_x, double center_y, int turn, double x2, double y2, double z2);
00331 static int find_ends(block_pointer block, setup_pointer settings, double * px,
00332   double * py, double * pz
00333 #ifdef AA
00334 , double * AA_p
00335 #endif
00336 
00337 #ifdef BB
00338 , double * BB_p
00339 #endif
00340 
00341 #ifdef CC
00342 , double * CC_p
00343 #endif
00344 );
00345 static int find_relative(double x1, double y1,
00346   double z1
00347 #ifdef AA
00348 , double AA_1
00349 #endif
00350 
00351 #ifdef BB
00352 , double BB_1
00353 #endif
00354 
00355 #ifdef CC
00356 , double CC_1
00357 #endif
00358 , double * x2, double * y2,
00359   double * z2
00360 #ifdef AA
00361 , double * AA_2
00362 #endif
00363 
00364 #ifdef BB
00365 , double * BB_2
00366 #endif
00367 
00368 #ifdef CC
00369 , double * CC_2
00370 #endif
00371 ,
00372   setup_pointer settings);
00373 static double find_straight_length(double x2, double y2,
00374   double z2
00375 #ifdef AA
00376 , double AA_2
00377 #endif
00378 
00379 #ifdef BB
00380 , double BB_2
00381 #endif
00382 
00383 #ifdef CC
00384 , double CC_2
00385 #endif
00386 , double x1, double y1,
00387   double z1
00388 #ifdef AA
00389 , double AA_1
00390 #endif
00391 
00392 #ifdef BB
00393 , double BB_1
00394 #endif
00395 
00396 #ifdef CC
00397 , double CC_1
00398 #endif
00399 );
00400 static double find_turn(double x1, double y1, double center_x, double center_y,
00401   int turn, double x2, double y2);
00402 static int init_block(block_pointer block);
00403 static int inverse_time_rate_arc(double x1, double y1, double z1,
00404   double cx, double cy, int turn, double x2, double y2, double z2,
00405   block_pointer block, setup_pointer settings);
00406 static int inverse_time_rate_arc2(double start_x, double start_y, int turn1,
00407   double mid_x, double mid_y, double cx, double cy, int turn2, double end_x,
00408   double end_y, double end_z, block_pointer block, setup_pointer settings);
00409 static int inverse_time_rate_as(double start_x, double start_y, int turn,
00410   double mid_x, double mid_y, double end_x, double end_y,
00411   double end_z
00412 #ifdef AA
00413 , double AA_end
00414 #endif
00415 
00416 #ifdef BB
00417 , double BB_end
00418 #endif
00419 
00420 #ifdef CC
00421 , double CC_end
00422 #endif
00423 ,
00424   block_pointer block, setup_pointer settings);
00425 static int inverse_time_rate_straight(double end_x, double end_y,
00426   double end_z
00427 #ifdef AA
00428 , double AA_end
00429 #endif
00430 
00431 #ifdef BB
00432 , double BB_end
00433 #endif
00434 
00435 #ifdef CC
00436 , double CC_end
00437 #endif
00438 ,
00439   block_pointer block, setup_pointer settings);
00440 static int parse_line(char * line, block_pointer block,setup_pointer settings);
00441 static int precedence(int an_operator);
00442 static int read_a(char * line, int * counter, block_pointer block,
00443   double * parameters);
00444 static int read_atan(char * line, int * counter, double * double_ptr,
00445   double * parameters);
00446 static int read_b(char * line, int * counter, block_pointer block,
00447   double * parameters);
00448 static int read_c(char * line, int * counter, block_pointer block,
00449   double * parameters);
00450 static int read_comment(char * line, int * counter, block_pointer block,
00451   double * parameters);
00452 static int read_d(char * line, int * counter, block_pointer block,
00453   double * parameters);
00454 static int read_f(char * line, int * counter, block_pointer block,
00455   double * parameters);
00456 static int read_g(char * line, int * counter, block_pointer block,
00457   double * parameters);
00458 static int read_h(char * line, int * counter, block_pointer block,
00459   double * parameters);
00460 static int read_i(char * line, int * counter, block_pointer block,
00461   double * parameters);
00462 static int read_integer_unsigned(char * line, int * counter,
00463   int * integer_ptr);
00464 static int read_integer_value(char * line, int * counter, int * integer_ptr,
00465   double * parameters);
00466 static int read_items(block_pointer block, char * line, double * parameters);
00467 static int read_j(char * line, int * counter, block_pointer block,
00468   double * parameters);
00469 static int read_k(char * line, int * counter, block_pointer block,
00470   double * parameters);
00471 static int read_l(char * line, int * counter, block_pointer block,
00472   double * parameters);
00473 static int read_line_number(char * line, int * counter, block_pointer block);
00474 static int read_m(char * line, int * counter, block_pointer block,
00475   double * parameters);
00476 static int read_one_item(char * line, int * counter, block_pointer block,
00477   double * parameters);
00478 static int read_operation(char * line, int * counter, int * operation);
00479 static int read_operation_unary(char * line, int * counter, int * operation);
00480 static int read_p(char * line, int * counter, block_pointer block,
00481   double * parameters);
00482 static int read_parameter(char * line, int * counter, double * double_ptr,
00483   double * parameters);
00484 static int read_parameter_setting(char * line, int * counter,
00485   block_pointer block, double * parameters);
00486 static int read_q(char * line, int * counter, block_pointer block,
00487   double * parameters);
00488 static int read_r(char * line, int * counter, block_pointer block,
00489   double * parameters);
00490 static int read_real_expression(char * line, int * counter,
00491   double * hold2, double * parameters);
00492 static int read_real_number(char * line, int * counter, double * double_ptr);
00493 static int read_real_value(char * line, int * counter, double * double_ptr,
00494   double * parameters);
00495 static int read_s(char * line, int * counter, block_pointer block,
00496   double * parameters);
00497 static int read_t(char * line, int * counter, block_pointer block,
00498   double * parameters);
00499 static int read_text(const char * command, FILE * inport, char * raw_line,
00500   char * line, int * length);
00501 static int read_unary(char * line, int * counter, double * double_ptr,
00502   double * parameters);
00503 static int read_x(char * line, int * counter, block_pointer block,
00504   double * parameters);
00505 static int read_y(char * line, int * counter, block_pointer block,
00506   double * parameters);
00507 static int read_z(char * line, int * counter, block_pointer block,
00508   double * parameters);
00509 static int set_probe_data(setup_pointer settings);
00510 static int write_g_codes(block_pointer block, setup_pointer settings);
00511 static int write_m_codes(block_pointer block, setup_pointer settings);
00512 static int write_settings(setup_pointer settings);
00513 
00514 /* Interpreter global arrays for g_codes and m_codes. The nth entry
00515 in each array is the modal group number corresponding to the nth
00516 code. Entries which are -1 represent illegal codes. Remember g_codes
00517 in this interpreter are multiplied by 10.
00518 
00519 The modal g groups and group numbers defined in [NCMS, pages 71 - 73]
00520 (see also [Fanuc, pages 43 - 45]) are used here, except the canned
00521 cycles (g80 - g89), which comprise modal g group 9 in [Fanuc], are
00522 treated here as being in the same modal group (group 1) with the
00523 straight moves and arcs (g0, g1, g2,g3).  [Fanuc, page 45] says only
00524 one g_code from any one group may appear on a line, and we are
00525 following that rule. The straight_probe move, g38.2, is in group 1; it
00526 is not defined in [NCMS].
00527 
00528 Some g_codes are non-modal (g4, g10, g28, g30, g53, g92, g92.1, g92.2,
00529 and g92.3 here - many more in [NCMS]). [Fanuc] and [NCMS] put all
00530 these in the same group 0, so we do also. Logically, there are two
00531 subgroups, those which require coordinate values (g10, g28, g30, and
00532 g92) and those which do not (g4, g53, g92.1, g92.2, and g92.3).
00533 The subgroups are identified by itemization when necessary.
00534 
00535 Those in group 0 which require coordinate values may not be on the
00536 same line as those in group 1 (except g80) because they would be
00537 competing for the coordinate values. Others in group 0 may be used on
00538 the same line as those in group 1.
00539 
00540 A total of 52 G-codes are implemented.
00541 
00542 The groups are:
00543 group  0 = {g4,g10,g28,g30,g53,g92,g92.1,g92.2,g92.3} - NON-MODAL
00544             dwell, setup, return to ref1, return to ref2,
00545             motion in machine coordinates, set and unset axis offsets
00546 group  1 = {g0,g1,g2,g3,g38.2,g80,g81,g82,g83,g84,g85,g86,g87,g88,g89} - motion
00547 group  2 = {g17,g18,g19}   - plane selection
00548 group  3 = {g90,g91}       - distance mode
00549 group  5 = {g93,g94}       - feed rate mode
00550 group  6 = {g20,g21}       - units
00551 group  7 = {g40,g41,g42}   - cutter diameter compensation
00552 group  8 = {g43,g49}       - tool length offset
00553 group 10 = {g98,g99}       - return mode in canned cycles
00554 group 12 = {g54,g55,g56,g57,g58,g59,g59.1,g59.2,g59.3} - coordinate system
00555 group 13 = {g61,g61.1,g64} - control mode
00556 
00557 */
00558 
00559 static const int _gees[] SET_TO {
00560 /*   0 */   1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00561 /*  20 */   1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00562 /*  40 */   0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00563 /*  60 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00564 /*  80 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00565 /* 100 */   0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00566 /* 120 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00567 /* 140 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00568 /* 160 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00569 /* 180 */   2,-1,-1,-1,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00570 /* 200 */   6,-1,-1,-1,-1,-1,-1,-1,-1,-1, 6,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00571 /* 220 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00572 /* 240 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00573 /* 260 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00574 /* 280 */   0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00575 /* 300 */   0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00576 /* 320 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00577 /* 340 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00578 /* 360 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00579 /* 380 */  -1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00580 /* 400 */   7,-1,-1,-1,-1,-1,-1,-1,-1,-1, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00581 /* 420 */   7,-1,-1,-1,-1,-1,-1,-1,-1,-1, 8,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00582 /* 440 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00583 /* 460 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00584 /* 480 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 8,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00585 /* 500 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00586 /* 520 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00587 /* 540 */  12,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00588 /* 560 */  12,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00589 /* 580 */  12,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,12,12,12,-1,-1,-1,-1,-1,-1,
00590 /* 600 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,13,13,-1,-1,-1,-1,-1,-1,-1,-1,
00591 /* 620 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00592 /* 640 */  13,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00593 /* 660 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00594 /* 680 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00595 /* 700 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00596 /* 720 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00597 /* 740 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00598 /* 760 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00599 /* 780 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00600 /* 800 */   1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00601 /* 820 */   1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00602 /* 840 */   1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00603 /* 860 */   1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00604 /* 880 */   1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00605 /* 900 */   3,-1,-1,-1,-1,-1,-1,-1,-1,-1, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00606 /* 920 */   0, 0, 0, 0,-1,-1,-1,-1,-1,-1, 5,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00607 /* 940 */   5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00608 /* 960 */  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00609 /* 980 */  10,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,-1,-1,-1,-1,-1,-1,-1,-1,-1};
00610 
00611 /*
00612 
00613 Modal groups and modal group numbers for M codes are not described in
00614 [Fanuc]. We have used the groups from [NCMS] and added M60, as an
00615 extension of the language for pallet shuttle and stop. This version has
00616 no codes related to axis clamping.
00617 
00618 The groups are:
00619 group 4 = {m0,m1,m2,m30,m60} - stopping
00620 group 6 = {m6}               - tool change
00621 group 7 = {m3,m4,m5}         - spindle turning
00622 group 8 = {m7,m8,m9}         - coolant
00623 group 9 = {m48,m49}          - feed and speed override switch bypass
00624 
00625 */
00626 
00627 static const int _ems[] SET_TO {
00628    4,  4,  4,  7,  7,  7,  6,  8,  8,  8,
00629   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00630   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00631    4, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00632   -1, -1, -1, -1, -1, -1, -1, -1,  9,  9,
00633   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00634    4, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00635   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00636   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00637   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
00638 
00639 /*
00640 
00641 This is an array of the index numbers of system parameters that must
00642 be included in a file used with the rs274ngc_restore_parameters
00643 function. The array is used by that function and by the
00644 rs274ngc_save_parameters function.
00645 
00646 */
00647 
00648 static const int _required_parameters[] SET_TO {
00649  5161, 5162, 5163,   /* G28 home */
00650 #ifdef AA
00651  5164, /*AA*/
00652 #endif
00653 #ifdef BB
00654  5165, /*BB*/
00655 #endif
00656 #ifdef CC
00657  5166, /*CC*/
00658 #endif
00659  5181, 5182, 5183,   /* G30 home */
00660 #ifdef AA
00661  5184, /*AA*/
00662 #endif
00663 #ifdef BB
00664  5185, /*BB*/
00665 #endif
00666 #ifdef CC
00667  5186, /*CC*/
00668 #endif
00669  5211, 5212, 5213,   /* G92 offsets */
00670 #ifdef AA
00671  5214, /*AA*/
00672 #endif
00673 #ifdef BB
00674  5215, /*BB*/
00675 #endif
00676 #ifdef CC
00677  5216, /*CC*/
00678 #endif
00679  5220,               /* selected coordinate */
00680  5221, 5222, 5223,   /* coordinate system 1 */
00681 #ifdef AA
00682  5224, /*AA*/
00683 #endif
00684 #ifdef BB
00685  5225, /*BB*/
00686 #endif
00687 #ifdef CC
00688  5226, /*CC*/
00689 #endif
00690  5241, 5242, 5243,   /* coordinate system 2 */
00691 #ifdef AA
00692  5244, /*AA*/
00693 #endif
00694 #ifdef BB
00695  5245, /*BB*/
00696 #endif
00697 #ifdef CC
00698  5246, /*CC*/
00699 #endif
00700  5261, 5262, 5263,   /* coordinate system 3 */
00701 #ifdef AA
00702  5264, /*AA*/
00703 #endif
00704 #ifdef BB
00705  5265, /*BB*/
00706 #endif
00707 #ifdef CC
00708  5266, /*CC*/
00709 #endif
00710  5281, 5282, 5283,   /* coordinate system 4 */
00711 #ifdef AA
00712  5284, /*AA*/
00713 #endif
00714 #ifdef BB
00715  5285, /*BB*/
00716 #endif
00717 #ifdef CC
00718  5286, /*CC*/
00719 #endif
00720  5301, 5302, 5303,   /* coordinate system 5 */
00721 #ifdef AA
00722  5304, /*AA*/
00723 #endif
00724 #ifdef BB
00725  5305, /*BB*/
00726 #endif
00727 #ifdef CC
00728  5306, /*CC*/
00729 #endif
00730  5321, 5322, 5323,   /* coordinate system 6 */
00731 #ifdef AA
00732  5324, /*AA*/
00733 #endif
00734 #ifdef BB
00735  5325, /*BB*/
00736 #endif
00737 #ifdef CC
00738  5326, /*CC*/
00739 #endif
00740  5341, 5342, 5343,   /* coordinate system 7 */
00741 #ifdef AA
00742  5344, /*AA*/
00743 #endif
00744 #ifdef BB
00745  5345, /*BB*/
00746 #endif
00747 #ifdef CC
00748  5346, /*CC*/
00749 #endif
00750  5361, 5362, 5363,   /* coordinate system 8 */
00751 #ifdef AA
00752  5364, /*AA*/
00753 #endif
00754 #ifdef BB
00755  5365, /*BB*/
00756 #endif
00757 #ifdef CC
00758  5366, /*CC*/
00759 #endif
00760  5381, 5382, 5383,   /* coordinate system 9 */
00761 #ifdef AA
00762  5384, /*AA*/
00763 #endif
00764 #ifdef BB
00765  5385, /*BB*/
00766 #endif
00767 #ifdef CC
00768  5386, /*CC*/
00769 #endif
00770  RS274NGC_MAX_PARAMETERS
00771 };
00772 
00773 /*
00774 
00775 _readers is an array of pointers to functions that read.
00776 It is used by read_one_item.
00777 
00778 */
00779 
00780 static const read_function_pointer _readers[] SET_TO {
00781 0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
00782 0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
00783 0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
00784 0,      0,      0, 0, 0, read_parameter_setting,0,      0,      0,      0,
00785 read_comment, 0, 0,     0,      0,      0,      0,      0,      0,      0,
00786 0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
00787 0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
00788 0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
00789 0,      0,      0,      0,      0,      0,      0,      0,      0,      0,
00790 0,      0,      0,      0,      0,      0,      0,      read_a, read_b, read_c,
00791 read_d, 0,      read_f, read_g, read_h, read_i, read_j, read_k, read_l, read_m,
00792 0,      0,      read_p, read_q, read_r, read_s, read_t, 0     , 0,      0,
00793 read_x, read_y, read_z};
00794 
00795 /****************************************************************************/
00796 
00797 /* There are four global variables. The first three are _gees, _ems,
00798 and _readers. The last one, declared here, is for interpreter settings */
00799 
00800 static setup _setup;
00801 
00802 /****************************************************************************/
00803 /****************************************************************************/
00804 
00805 
00806 
00807 
00808 
00809 
00810 /*
00811 
00812 The functions in this section are the interpreter kernel functions
00813 
00814 */
00815 
00816 /***********************************************************************/
00817 
00818 /* arc_data_comp_ijk
00819 
00820 Returned Value: int
00821    If any of the following errors occur, this returns the error code shown.
00822    Otherwise, it returns RS274NGC_OK.
00823    1. The two calculable values of the radius differ by more than
00824       tolerance: NCE_RADIUS_TO_END_OF_ARC_DIFFERS_FROM_RADIUS_TO_START
00825    2. move is not G_2 or G_3: NCE_BUG_CODE_NOT_G2_OR_G3
00826 
00827 Side effects:
00828    This finds and sets the values of center_x, center_y, and turn.
00829 
00830 Called by: convert_arc_comp1
00831 
00832 This finds the center coordinates and number of full or partial turns
00833 counterclockwise of a helical or circular arc in ijk-format in the XY
00834 plane. The center is computed easily from the current point and center
00835 offsets, which are given. It is checked that the end point lies one
00836 tool radius from the arc.
00837 
00838 
00839 */
00840 
00841 static int arc_data_comp_ijk( /* ARGUMENTS                               */
00842  int move,           /* either G_2 (cw arc) or G_3 (ccw arc)             */
00843  int side,           /* either RIGHT or LEFT                             */
00844  double tool_radius, /* radius of the tool                               */
00845  double current_x,   /* first coordinate of current point                */
00846  double current_y,   /* second coordinate of current point               */
00847  double end_x,       /* first coordinate of arc end point                */
00848  double end_y,       /* second coordinate of arc end point               */
00849  double i_number,    /* first coordinate offset of center from current   */
00850  double j_number,    /* second coordinate offset of center from current  */
00851  double * center_x,  /* pointer to first coordinate of center of arc     */
00852  double * center_y,  /* pointer to second coordinate of center of arc    */
00853  int * turn,         /* pointer to number of full or partial circles CCW */
00854  double tolerance)   /* tolerance of differing radii                     */
00855 {
00856   static char name[] SET_TO "arc_data_comp_ijk";
00857   double arc_radius;
00858   double radius2;
00859 
00860   *center_x SET_TO (current_x + i_number);
00861   *center_y SET_TO (current_y + j_number);
00862   arc_radius SET_TO hypot(i_number, j_number);
00863   radius2 SET_TO hypot((*center_x - end_x), (*center_y - end_y));
00864   radius2 SET_TO
00865     (((side IS LEFT ) AND (move IS 30)) OR
00866      ((side IS RIGHT) AND (move IS 20))) ?
00867        (radius2 - tool_radius): (radius2 + tool_radius);
00868   CHK((fabs(arc_radius - radius2) > tolerance),
00869       NCE_RADIUS_TO_END_OF_ARC_DIFFERS_FROM_RADIUS_TO_START);
00870       /* This catches an arc too small for the tool, also */
00871   if (move IS G_2)
00872     *turn SET_TO -1;
00873   else if (move IS G_3)
00874     *turn SET_TO 1;
00875   else
00876     ERM(NCE_BUG_CODE_NOT_G2_OR_G3);
00877   return RS274NGC_OK;
00878 }
00879 
00880 /****************************************************************************/
00881 
00882 /* arc_data_comp_r
00883 
00884 Returned Value: int
00885    If any of the following errors occur, this returns the error code shown.
00886    Otherwise, it returns RS274NGC_OK.
00887    1. The arc radius is too small to reach the end point:
00888       NCE_RADIUS_TOO_SMALL_TO_REACH_END_POINT
00889    2. The arc radius is not greater than the tool_radius, but should be:
00890       NCE_TOOL_RADIUS_NOT_LESS_THAN_ARC_RADIUS_WITH_COMP
00891    3. An imaginary value for offset would be found, which should never
00892       happen if the theory is correct: NCE_BUG_IN_TOOL_RADIUS_COMP
00893 
00894 Side effects:
00895    This finds and sets the values of center_x, center_y, and turn.
00896 
00897 Called by: convert_arc_comp1
00898 
00899 This finds the center coordinates and number of full or partial turns
00900 counterclockwise of a helical or circular arc (call it arc1) in
00901 r-format in the XY plane.  Arc2 is constructed so that it is tangent
00902 to a circle whose radius is tool_radius and whose center is at the
00903 point (current_x, current_y) and passes through the point (end_x,
00904 end_y). Arc1 has the same center as arc2. The radius of arc1 is one
00905 tool radius larger or smaller than the radius of arc2.
00906 
00907 If the value of the big_radius argument is negative, that means [NCMS,
00908 page 21] that an arc larger than a semicircle is to be made.
00909 Otherwise, an arc of a semicircle or less is made.
00910 
00911 The algorithm implemented here is to construct a line L from the
00912 current point to the end point, and a perpendicular to it from the
00913 center of the arc which intersects L at point P. Since the distance
00914 from the end point to the center and the distance from the current
00915 point to the center are known, two equations for the length of the
00916 perpendicular can be written. The right sides of the equations can be
00917 set equal to one another and the resulting equation solved for the
00918 length of the line from the current point to P. Then the location of
00919 P, the length of the perpendicular, the angle of the perpendicular,
00920 and the location of the center, can be found in turn.
00921 
00922 This needs to be better documented, with figures. There are eight
00923 possible arcs, since there are three binary possibilities: (1) tool
00924 inside or outside arc, (2) clockwise or counterclockwise (3) two
00925 positions for each arc (of the given radius) tangent to the tool
00926 outline and through the end point. All eight are calculated below,
00927 since theta, radius2, and turn may each have two values.
00928 
00929 To see two positions for each arc, imagine the arc is a hoop, the
00930 tool is a cylindrical pin, and the arc may rotate around the end point.
00931 The rotation covers all possible positions of the arc. It is easy to
00932 see the hoop is constrained by the pin at two different angles, whether
00933 the pin is inside or outside the hoop.
00934 
00935 */
00936 
00937 static int arc_data_comp_r( /* ARGUMENTS                                 */
00938  int move,           /* either G_2 (cw arc) or G_3 (ccw arc)             */
00939  int side,           /* either RIGHT or LEFT                             */
00940  double tool_radius, /* radius of the tool                               */
00941  double current_x,   /* first coordinate of current point                */
00942  double current_y,   /* second coordinate of current point               */
00943  double end_x,       /* first coordinate of arc end point                */
00944  double end_y,       /* second coordinate of arc end point               */
00945  double big_radius,  /* radius of arc                                    */
00946  double * center_x,  /* pointer to first coordinate of center of arc     */
00947  double * center_y,  /* pointer to second coordinate of center of arc    */
00948  int * turn)         /* pointer to number of full or partial circles CCW */
00949 {
00950   static char name[] SET_TO "arc_data_comp_r";
00951   double abs_radius; /* absolute value of big_radius          */
00952   double alpha;      /* direction of line from current to end */
00953   double distance;   /* length of line L from current to end  */
00954   double mid_length; /* length from current point to point P  */
00955   double offset;     /* length of line from P to center       */
00956   double radius2;    /* distance from center to current point */
00957   double mid_x;      /* x-value of point P                    */
00958   double mid_y;      /* y-value of point P                    */
00959   double theta;      /* direction of line from P to center    */
00960 
00961   abs_radius SET_TO fabs(big_radius);
00962   CHK(((abs_radius <= tool_radius) AND (((side IS LEFT ) AND (move IS G_3)) OR
00963                                         ((side IS RIGHT) AND (move IS G_2)))),
00964       NCE_TOOL_RADIUS_NOT_LESS_THAN_ARC_RADIUS_WITH_COMP);
00965 
00966   distance SET_TO hypot((end_x - current_x), (end_y - current_y));
00967   alpha SET_TO atan2 ((end_y - current_y), (end_x - current_x));
00968   theta SET_TO (((move IS G_3) AND (big_radius > 0)) OR
00969                 ((move IS G_2) AND (big_radius < 0))) ?
00970                   (alpha + PI2) : (alpha - PI2);
00971   radius2 SET_TO (((side IS LEFT ) AND (move IS G_3)) OR
00972                   ((side IS RIGHT) AND (move IS G_2))) ?
00973                     (abs_radius - tool_radius) : (abs_radius + tool_radius);
00974   CHK((distance > (radius2 + abs_radius)),
00975       NCE_RADIUS_TOO_SMALL_TO_REACH_END_POINT);
00976   mid_length SET_TO (((radius2 * radius2) + (distance * distance) -
00977                       (abs_radius * abs_radius)) / (2.0 * distance));
00978   mid_x SET_TO (current_x + (mid_length * cos(alpha)));
00979   mid_y SET_TO (current_y + (mid_length * sin(alpha)));
00980   CHK(((radius2 * radius2) <= (mid_length * mid_length)),
00981       NCE_BUG_IN_TOOL_RADIUS_COMP);
00982   offset SET_TO sqrt((radius2 * radius2) - (mid_length * mid_length));
00983   *center_x SET_TO mid_x + (offset * cos(theta));
00984   *center_y SET_TO mid_y + (offset * sin(theta));
00985   *turn SET_TO (move IS G_2) ? -1 : 1;
00986 
00987   return RS274NGC_OK;
00988 }
00989 
00990 /****************************************************************************/
00991 
00992 /* arc_data_ijk
00993 
00994 Returned Value: int
00995    If any of the following errors occur, this returns the error code shown.
00996    Otherwise, it returns RS274NGC_OK.
00997    1. The two calculable values of the radius differ by more than
00998       tolerance: NCE_RADIUS_TO_END_OF_ARC_DIFFERS_FROM_RADIUS_TO_START
00999    2. The move code is not G_2 or G_3: NCE_BUG_CODE_NOT_G2_OR_G3
01000    3. Either of the two calculable values of the radius is zero:
01001       NCE_ZERO_RADIUS_ARC
01002 
01003 Side effects:
01004    This finds and sets the values of center_x, center_y, and turn.
01005 
01006 Called by:
01007    convert_arc2
01008    convert_arc_comp2
01009 
01010 This finds the center coordinates and number of full or partial turns
01011 counterclockwise of a helical or circular arc in ijk-format. This
01012 function is used by convert_arc2 for all three planes, so "x" and
01013 "y" really mean "first_coordinate" and "second_coordinate" wherever
01014 they are used here as suffixes of variable names. The i and j prefixes
01015 are handled similarly.
01016 
01017 */
01018 
01019 static int arc_data_ijk( /* ARGUMENTS                                       */
01020  int move,               /* either G_2 (cw arc) or G_3 (ccw arc)            */
01021  double current_x,       /* first coordinate of current point               */
01022  double current_y,       /* second coordinate of current point              */
01023  double end_x,           /* first coordinate of arc end point               */
01024  double end_y,           /* second coordinate of arc end point              */
01025  double i_number,        /* first coordinate offset of center from current  */
01026  double j_number,        /* second coordinate offset of center from current */
01027  double * center_x,      /* pointer to first coordinate of center of arc    */
01028  double * center_y,      /* pointer to second coordinate of center of arc   */
01029  int * turn,             /* pointer to no. of full or partial circles CCW   */
01030  double tolerance)       /* tolerance of differing radii                    */
01031 {
01032   static char name[] SET_TO "arc_data_ijk";
01033   double radius;    /* radius to current point */
01034   double radius2;   /* radius to end point     */
01035   *center_x SET_TO (current_x + i_number);
01036   *center_y SET_TO (current_y + j_number);
01037   radius SET_TO hypot((*center_x - current_x), (*center_y - current_y));
01038   radius2 SET_TO hypot((*center_x - end_x), (*center_y - end_y));
01039   CHK(((radius IS 0.0) OR (radius2 IS 0.0)), NCE_ZERO_RADIUS_ARC);
01040   CHK((fabs(radius - radius2) > tolerance),
01041       NCE_RADIUS_TO_END_OF_ARC_DIFFERS_FROM_RADIUS_TO_START);
01042   if (move IS G_2)
01043     *turn SET_TO -1;
01044   else if (move IS G_3)
01045     *turn SET_TO 1;
01046   else
01047     ERM(NCE_BUG_CODE_NOT_G2_OR_G3);
01048   return RS274NGC_OK;
01049 }
01050 
01051 /****************************************************************************/
01052 
01053 /* arc_data_r
01054 
01055 Returned Value: int
01056    If any of the following errors occur, this returns the error shown.
01057    Otherwise, it returns RS274NGC_OK.
01058    1. The radius is too small to reach the end point:
01059       NCE_ARC_RADIUS_TOO_SMALL_TO_REACH_END_POINT
01060    2. The current point is the same as the end point of the arc
01061       (so that it is not possible to locate the center of the circle):
01062       NCE_CURRENT_POINT_SAME_AS_END_POINT_OF_ARC
01063 
01064 Side effects:
01065    This finds and sets the values of center_x, center_y, and turn.
01066 
01067 Called by:
01068    convert_arc2
01069    convert_arc_comp2
01070 
01071 This finds the center coordinates and number of full or partial turns
01072 counterclockwise of a helical or circular arc in the r format. This
01073 function is used by convert_arc2 for all three planes, so "x" and
01074 "y" really mean "first_coordinate" and "second_coordinate" wherever
01075 they are used here as suffixes of variable names.
01076 
01077 If the value of the radius argument is negative, that means [NCMS,
01078 page 21] that an arc larger than a semicircle is to be made.
01079 Otherwise, an arc of a semicircle or less is made.
01080 
01081 The algorithm used here is based on finding the midpoint M of the line
01082 L between the current point and the end point of the arc. The center
01083 of the arc lies on a line through M perpendicular to L.
01084 
01085 */
01086 
01087 static int arc_data_r( /* ARGUMENTS                                     */
01088  int move,             /* either G_2 (cw arc) or G_3 (ccw arc)          */
01089  double current_x,     /* first coordinate of current point             */
01090  double current_y,     /* second coordinate of current point            */
01091  double end_x,         /* first coordinate of arc end point             */
01092  double end_y,         /* second coordinate of arc end point            */
01093  double radius,        /* radius of arc                                 */
01094  double * center_x,    /* pointer to first coordinate of center of arc  */
01095  double * center_y,    /* pointer to second coordinate of center of arc */
01096  int * turn)           /* pointer to no. of full or partial circles CCW */
01097 {
01098   static char name[] SET_TO "arc_data_r";
01099   double abs_radius;  /* absolute value of given radius */
01100   double half_length; /* distance from M to end point   */
01101   double mid_x;       /* first coordinate of M          */
01102   double mid_y;       /* second coordinate of M         */
01103   double offset;      /* distance from M to center      */
01104   double theta;       /* angle of line from M to center */
01105   double turn2;       /* absolute value of half of turn */
01106 
01107   CHK(((end_x IS current_x) AND (end_y IS current_y)),
01108       NCE_CURRENT_POINT_SAME_AS_END_POINT_OF_ARC);
01109   abs_radius SET_TO fabs(radius);
01110   mid_x SET_TO (end_x + current_x)/2.0;
01111   mid_y SET_TO (end_y + current_y)/2.0;
01112   half_length SET_TO hypot((mid_x - end_x), (mid_y - end_y));
01113   CHK(((half_length/abs_radius) > (1+TINY)),
01114       NCE_ARC_RADIUS_TOO_SMALL_TO_REACH_END_POINT);
01115   if ((half_length/abs_radius) > (1-TINY))
01116     half_length SET_TO abs_radius; /* allow a small error for semicircle */
01117                                    /* check needed before calling asin   */
01118   if (((move IS G_2) AND (radius > 0)) OR
01119       ((move IS G_3) AND (radius < 0)))
01120     theta SET_TO atan2((end_y - current_y), (end_x - current_x)) - PI2;
01121   else
01122     theta SET_TO atan2((end_y - current_y), (end_x - current_x)) + PI2;
01123 
01124   turn2 SET_TO asin (half_length/abs_radius);
01125   offset SET_TO abs_radius * cos(turn2);
01126   *center_x SET_TO mid_x + (offset * cos(theta));
01127   *center_y SET_TO mid_y + (offset * sin(theta));
01128   *turn SET_TO (move IS G_2) ? -1 : 1;
01129 
01130   return RS274NGC_OK;
01131 }
01132 
01133 /****************************************************************************/
01134 
01135 /* check_g_codes
01136 
01137 Returned Value: int
01138    If any of the following errors occur, this returns the error shown.
01139    Otherwise, it returns RS274NGC_OK.
01140    1. NCE_DWELL_TIME_MISSING_WITH_G4
01141    2. NCE_MUST_USE_G0_OR_G1_WITH_G53
01142    3. NCE_CANNOT_USE_G53_INCREMENTAL
01143    4. NCE_LINE_WITH_G10_DOES_NOT_HAVE_L2
01144    5. NCE_P_VALUE_NOT_AN_INTEGER_WITH_G10_L2
01145    6. NCE_P_VALUE_OUT_OF_RANGE_WITH_G10_L2
01146    7. NCE_BUG_BAD_G_CODE_MODAL_GROUP_0
01147 
01148 Side effects: none
01149 
01150 Called by: check_items
01151 
01152 This runs checks on g_codes from a block of RS274/NGC instructions.
01153 Currently, all checks are on g_codes in modal group 0.
01154 
01155 The read_g function checks for errors which would foul up the reading.
01156 The enhance_block function checks for logical errors in the use of
01157 axis values by g-codes in modal groups 0 and 1.
01158 This function checks for additional logical errors in g_codes.
01159 
01160 [Fanuc, page 45, note 4] says there is no maximum for how many g_codes
01161 may be put on the same line, [NCMS] says nothing one way or the other,
01162 so the test for that is not used.
01163 
01164 We are suspending any implicit motion g_code when a g_code from our
01165 group 0 is used.  The implicit motion g_code takes effect again
01166 automatically after the line on which the group 0 g_code occurs.  It
01167 is not clear what the intent of [Fanuc] is in this regard. The
01168 alternative is to require that any implicit motion be explicitly
01169 cancelled.
01170 
01171 Not all checks on g_codes are included here. Those checks that are
01172 sensitive to whether other g_codes on the same line have been executed
01173 yet are made by the functions called by convert_g.
01174 
01175 Our reference sources differ regarding what codes may be used for
01176 dwell time.  [Fanuc, page 58] says use "p" or "x". [NCMS, page 23] says
01177 use "p", "x", or "u". We are allowing "p" only, since it is consistent
01178 with both sources and "x" would be confusing. However, "p" is also used
01179 with G10, where it must be an integer, so reading "p" values is a bit
01180 more trouble than would be nice.
01181 
01182 */
01183 
01184 static int check_g_codes( /* ARGUMENTS                        */
01185  block_pointer block,     /* pointer to a block to be checked */
01186  setup_pointer settings)  /* pointer to machine settings      */
01187 {
01188   static char name[] SET_TO "check_g_codes";
01189   int mode0;
01190   int p_int;
01191 
01192   mode0 SET_TO block->g_modes[0];
01193 
01194   if (mode0 IS -1)
01195     {}
01196   else if (mode0 IS G_4)
01197     {
01198       CHK((block->p_number IS -1.0), NCE_DWELL_TIME_MISSING_WITH_G4);
01199     }
01200   else if (mode0 IS G_10)
01201     {
01202       p_int SET_TO (int)(block->p_number + 0.0001);
01203       CHK((block->l_number ISNT 2), NCE_LINE_WITH_G10_DOES_NOT_HAVE_L2);
01204       CHK((((block->p_number + 0.0001) - p_int) > 0.0002),
01205           NCE_P_VALUE_NOT_AN_INTEGER_WITH_G10_L2);
01206       CHK(((p_int < 1) OR (p_int > 9)), NCE_P_VALUE_OUT_OF_RANGE_WITH_G10_L2);
01207     }
01208   else if (mode0 IS G_28)
01209     {}
01210   else if (mode0 IS G_30)
01211     {}
01212   else if (mode0 IS G_53)
01213     {
01214       CHK(((block->motion_to_be ISNT G_0) AND (block->motion_to_be ISNT G_1)),
01215           NCE_MUST_USE_G0_OR_G1_WITH_G53);
01216       CHK(((block->g_modes[3] IS G_91) OR
01217            ((block->g_modes[3] ISNT G_90) AND
01218             (settings->distance_mode IS MODE_INCREMENTAL))),
01219           NCE_CANNOT_USE_G53_INCREMENTAL);
01220     }
01221   else if (mode0 IS G_92)
01222     {}
01223   else if ((mode0 IS G_92_1) OR (mode0 IS G_92_2) OR (mode0 IS G_92_3))
01224     {}
01225   else
01226     ERM(NCE_BUG_BAD_G_CODE_MODAL_GROUP_0);
01227   return RS274NGC_OK;
01228 }
01229 
01230 /****************************************************************************/
01231 
01232 /* check_items
01233 
01234 Returned Value: int
01235    If any one of check_g_codes, check_m_codes, and check_other_codes
01236    returns an error code, this returns that code.
01237    Otherwise, it returns RS274NGC_OK.
01238 
01239 Side effects: none
01240 
01241 Called by: parse_line
01242 
01243 This runs checks on a block of RS274 code.
01244 
01245 The functions named read_XXXX check for errors which would foul up the
01246 reading. This function checks for additional logical errors.
01247 
01248 A block has an array of g_codes, which are initialized to -1
01249 (meaning no code). This calls check_g_codes to check the g_codes.
01250 
01251 A block has an array of m_codes, which are initialized to -1
01252 (meaning no code). This calls check_m_codes to check the m_codes.
01253 
01254 Items in the block which are not m or g codes are checked by
01255 check_other_codes.
01256 
01257 */
01258 
01259 static int check_items(   /* ARGUMENTS                        */
01260  block_pointer block,     /* pointer to a block to be checked */
01261  setup_pointer settings)  /* pointer to machine settings      */
01262 {
01263   static char name[] SET_TO "check_items";
01264   int status;
01265 
01266   CHP(check_g_codes(block, settings));
01267   CHP(check_m_codes(block));
01268   CHP(check_other_codes(block));
01269   return RS274NGC_OK;
01270 }
01271 
01272 /****************************************************************************/
01273 
01274 /* check_m_codes
01275 
01276 Returned Value: int
01277    If any of the following errors occur, this returns the error code shown.
01278    Otherwise, it returns RS274NGC_OK.
01279    1. There are too many m codes in the block: NCE_TOO_MANY_M_CODES_ON_LINE
01280 
01281 Side effects: none
01282 
01283 Called by: check_items
01284 
01285 This runs checks on m_codes from a block of RS274/NGC instructions.
01286 
01287 The read_m function checks for errors which would foul up the
01288 reading. This function checks for additional errors in m_codes.
01289 
01290 */
01291 
01292 static int check_m_codes( /* ARGUMENTS                        */
01293  block_pointer block)     /* pointer to a block to be checked */
01294 {
01295   static char name[] SET_TO "check_m_codes";
01296 
01297   CHK((block->m_count > MAX_EMS), NCE_TOO_MANY_M_CODES_ON_LINE);
01298   return RS274NGC_OK;
01299 }
01300 
01301 /****************************************************************************/
01302 
01303 /* check_other_codes
01304 
01305 Returned Value: int
01306    If any of the following errors occur, this returns the error code shown.
01307    Otherwise, it returns RS274NGC_OK.
01308    1. An A-axis value is given with a canned cycle (g80 to g89):
01309       NCE_CANNOT_PUT_AN_A_IN_CANNED_CYCLE
01310    2. A B-axis value is given with a canned cycle (g80 to g89):
01311       NCE_CANNOT_PUT_A_B_IN_CANNED_CYCLE
01312    3. A C-axis value is given with a canned cycle (g80 to g89):
01313       NCE_CANNOT_PUT_A_C_IN_CANNED_CYCLE
01314    4. A d word is in a block with no cutter_radius_compensation_on command:
01315       NCE_D_WORD_WITH_NO_G41_OR_G42
01316    5. An h_number is in a block with no tool length offset setting:
01317       NCE_H_WORD_WITH_NO_G43
01318    6. An i_number is in a block with no G code that uses it:
01319       NCE_I_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT
01320    7. A j_number is in a block with no G code that uses it:
01321       NCE_J_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT
01322    8. A k_number is in a block with no G code that uses it:
01323       NCE_K_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT
01324    9. A l_number is in a block with no G code that uses it:
01325       NCE_L_WORD_WITH_NO_CANNED_CYCLE_OR_G10
01326   10. A p_number is in a block with no G code that uses it:
01327       NCE_P_WORD_WITH_NO_G4_G10_G82_G86_G88_G89
01328   11. A q_number is in a block with no G code that uses it:
01329       NCE_Q_WORD_WITH_NO_G83
01330   12. An r_number is in a block with no G code that uses it:
01331       NCE_R_WORD_WITH_NO_G_CODE_THAT_USES_IT
01332 
01333 Side effects: none
01334 
01335 Called by: check_items
01336 
01337 This runs checks on codes from a block of RS274/NGC code which are
01338 not m or g codes.
01339 
01340 The functions named read_XXXX check for errors which would foul up the
01341 reading. This function checks for additional logical errors in codes.
01342 
01343 */
01344 
01345 static int check_other_codes( /* ARGUMENTS                               */
01346  block_pointer block)    /* pointer to a block of RS274/NGC instructions */
01347 {
01348   static char name[] SET_TO "check_other_codes";
01349   int motion;
01350 
01351   motion SET_TO block->motion_to_be;
01352 #ifdef AA
01353   if (block->a_flag ISNT OFF)
01354     {
01355       CHK(((block->g_modes[1] > G_80) AND (block->g_modes[1] < G_90)),
01356           NCE_CANNOT_PUT_AN_A_IN_CANNED_CYCLE);
01357     }
01358 #endif
01359 #ifdef BB
01360   if (block->b_flag ISNT OFF)
01361     {
01362       CHK(((block->g_modes[1] > G_80) AND (block->g_modes[1] < G_90)),
01363           NCE_CANNOT_PUT_A_B_IN_CANNED_CYCLE);
01364     }
01365 #endif
01366 #ifdef CC
01367   if (block->c_flag ISNT OFF)
01368     {
01369       CHK(((block->g_modes[1] > G_80) AND (block->g_modes[1] < G_90)),
01370           NCE_CANNOT_PUT_A_C_IN_CANNED_CYCLE);
01371     }
01372 #endif
01373   if (block->d_number ISNT -1)
01374     {
01375       CHK(((block->g_modes[7] ISNT G_41) AND (block->g_modes[7] ISNT G_42)),
01376           NCE_D_WORD_WITH_NO_G41_OR_G42);
01377     }
01378   if (block->h_number ISNT -1)
01379     {
01380       CHK((block->g_modes[8] ISNT G_43), NCE_H_WORD_WITH_NO_G43);
01381     }
01382 
01383   if (block->i_flag IS ON) /* could still be useless if yz_plane arc */
01384     {
01385       CHK(((motion ISNT G_2) AND (motion ISNT G_3) AND (motion ISNT G_87)),
01386           NCE_I_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT);
01387     }
01388 
01389   if (block->j_flag IS ON) /* could still be useless if xz_plane arc */
01390     {
01391       CHK(((motion ISNT G_2) AND (motion ISNT G_3) AND (motion ISNT G_87)),
01392           NCE_J_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT);
01393     }
01394 
01395   if (block->k_flag IS ON) /* could still be useless if xy_plane arc */
01396     {
01397       CHK(((motion ISNT G_2) AND (motion ISNT G_3) AND (motion ISNT G_87)),
01398           NCE_K_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT);
01399     }
01400 
01401   if (block->l_number ISNT -1)
01402     {
01403       CHK((((motion < G_81) OR (motion > G_89)) AND
01404            (block->g_modes[0] ISNT G_10)),
01405           NCE_L_WORD_WITH_NO_CANNED_CYCLE_OR_G10);
01406     }
01407 
01408   if (block->p_number ISNT -1.0)
01409     {
01410       CHK(((block->g_modes[0] ISNT G_10) AND
01411            (block->g_modes[0] ISNT G_4) AND
01412            (motion ISNT G_82) AND (motion ISNT G_86) AND
01413            (motion ISNT G_88) AND (motion ISNT G_89)),
01414           NCE_P_WORD_WITH_NO_G4_G10_G82_G86_G88_G89);
01415     }
01416 
01417   if (block->q_number ISNT -1.0)
01418     {
01419       CHK((motion ISNT G_83), NCE_Q_WORD_WITH_NO_G83);
01420     }
01421 
01422   if (block->r_flag IS ON)
01423     {
01424       CHK((((motion ISNT G_2) AND (motion ISNT G_3)) AND
01425            ((motion < G_81) OR (motion > G_89))),
01426           NCE_R_WORD_WITH_NO_G_CODE_THAT_USES_IT);
01427     }
01428 
01429   return RS274NGC_OK;
01430 }
01431 
01432 /****************************************************************************/
01433 
01434 /* close_and_downcase
01435 
01436 Returned Value: int
01437    If any of the following errors occur, this returns the error code shown.
01438    Otherwise, it returns RS274NGC_OK.
01439    1. A left parenthesis is found inside a comment:
01440       NCE_NESTED_COMMENT_FOUND
01441    2. The line ends before an open comment is closed:
01442       NCE_UNCLOSED_COMMENT_FOUND
01443    3. A newline character is found that is not followed by null:
01444       NCE_NULL_MISSING_AFTER_NEWLINE
01445 
01446 Side effects: See below
01447 
01448 Called by:  read_text
01449 
01450 To simplify handling upper case letters, spaces, and tabs, this
01451 function removes spaces and and tabs and downcases everything on a
01452 line which is not part of a comment.
01453 
01454 Comments are left unchanged in place. Comments are anything
01455 enclosed in parentheses. Nested comments, indicated by a left
01456 parenthesis inside a comment, are illegal.
01457 
01458 The line must have a null character at the end when it comes in.
01459 The line may have one newline character just before the end. If
01460 there is a newline, it will be removed.
01461 
01462 Although this software system detects and rejects all illegal characters
01463 and illegal syntax, this particular function does not detect problems
01464 with anything but comments.
01465 
01466 We are treating RS274 code here as case-insensitive and spaces and
01467 tabs as if they have no meaning. [RS274D, page 6] says spaces and tabs
01468 are to be ignored by control.
01469 
01470 The KT and NGC manuals say nothing about case or spaces and tabs.
01471 
01472 */
01473 
01474 static int close_and_downcase( /* ARGUMENTS                   */
01475  char * line)                  /* string: one line of NC code */
01476 {
01477   static char name[] SET_TO "close_and_downcase";
01478   int m;
01479   int n;
01480   int comment;
01481   char item;
01482   comment SET_TO 0;
01483   for (n SET_TO 0, m SET_TO 0; (item SET_TO line[m]) ISNT (char) NULL; m++)
01484     {
01485       if (comment)
01486         {
01487           line[n++] SET_TO item;
01488           if (item IS ')')
01489             {
01490               comment SET_TO 0;
01491             }
01492           else if (item IS '(')
01493             ERM(NCE_NESTED_COMMENT_FOUND);
01494         }
01495       else if ((item IS ' ') OR (item IS '\t') OR (item IS '\r'));
01496                                       /* don't copy blank or tab or CR */
01497       else if (item IS '\n')          /* don't copy newline            */
01498         {                             /* but check null follows        */
01499           CHK((line[m+1] ISNT 0), NCE_NULL_MISSING_AFTER_NEWLINE);
01500         }
01501       else if ((64 < item) AND (item < 91)) /* downcase upper case letters */
01502         {
01503           line[n++] SET_TO (32 + item);
01504         }
01505       else if (item IS '(')   /* comment is starting */
01506         {
01507           comment SET_TO 1;
01508           line[n++] SET_TO item;
01509         }
01510       else
01511         {
01512           line[n++] SET_TO item; /* copy anything else */
01513         }
01514     }
01515   CHK((comment), NCE_UNCLOSED_COMMENT_FOUND);
01516   line[n] SET_TO 0;
01517   return RS274NGC_OK;
01518 }
01519 
01520 /****************************************************************************/
01521 
01522 /* convert_arc
01523 
01524 Returned Value: int
01525    If one of the following functions returns an error code,
01526    this returns that error code.
01527       convert_arc_comp1
01528       convert_arc_comp2
01529       convert_arc2
01530    If any of the following errors occur, this returns the error code shown.
01531    Otherwise, this returns RS274NGC_OK.
01532    1. The block has neither an r value nor any i,j,k values:
01533       NCE_R_I_J_K_WORDS_ALL_MISSING_FOR_ARC
01534    2. The block has both an r value and one or more i,j,k values:
01535       NCE_MIXED_RADIUS_IJK_FORMAT_FOR_ARC
01536    3. In the ijk format the XY-plane is selected and
01537       the block has a k value: NCE_K_WORD_GIVEN_FOR_ARC_IN_XY_PLANE
01538    4. In the ijk format the YZ-plane is selected and
01539       the block has an i value: NCE_I_WORD_GIVEN_FOR_ARC_IN_YZ_PLANE
01540    5. In the ijk format the XZ-plane is selected and
01541       the block has a j value: NCE_J_WORD_GIVEN_FOR_ARC_IN_XZ_PLANE
01542    6. In either format any of the following occurs.
01543       a. The XY-plane is selected and the block has no x or y value:
01544          NCE_X_AND_Y_WORDS_MISSING_FOR_ARC_IN_XY_PLANE
01545       b. The YZ-plane is selected and the block has no y or z value:
01546          NCE_Y_AND_Z_WORDS_MISSING_FOR_ARC_IN_YZ_PLANE
01547       c. The ZX-plane is selected and the block has no z or x value:
01548          NCE_X_AND_Z_WORDS_MISSING_FOR_ARC_IN_XZ_PLANE
01549    7. The selected plane is an unknown plane:
01550       NCE_BUG_PLANE_NOT_XY_YZ__OR_XZ
01551    8. The feed rate mode is UNITS_PER_MINUTE and feed rate is zero:
01552       NCE_CANNOT_MAKE_ARC_WITH_ZERO_FEED_RATE
01553    9. The feed rate mode is INVERSE_TIME and the block has no f word:
01554       NCE_F_WORD_MISSING_WITH_INVERSE_TIME_ARC_MOVE
01555 
01556 Side effects:
01557    This generates and executes an arc command at feed rate
01558    (and, possibly a second arc command). It also updates the setting
01559    of the position of the tool point to the end point of the move.
01560 
01561 Called by: convert_motion.
01562 
01563 This converts a helical or circular arc.  The function calls:
01564 convert_arc2 (when cutter radius compensation is off) or
01565 convert_arc_comp1 (when cutter comp is on and this is the first move) or
01566 convert_arc_comp2 (when cutter comp is on and this is not the first move).
01567 
01568 If the ijk format is used, at least one of the offsets in the current
01569 plane must be given in the block; it is common but not required to
01570 give both offsets. The offsets are always incremental [NCMS, page 21].
01571 
01572 */
01573 
01574 static int convert_arc(  /* ARGUMENTS                                */
01575  int move,               /* either G_2 (cw arc) or G_3 (ccw arc)     */
01576  block_pointer block,    /* pointer to a block of RS274 instructions */
01577  setup_pointer settings) /* pointer to machine settings              */
01578 {
01579   static char name[] SET_TO "convert_arc";
01580   int status;
01581   int first;          /* flag set ON if this is first move after comp ON */
01582   int ijk_flag;       /* flag set ON if any of i,j,k present in NC code  */
01583   double end_x;
01584   double end_y;
01585   double end_z;
01586 #ifdef AA
01587   double AA_end;       /*AA*/
01588 #endif
01589 #ifdef BB
01590   double BB_end;       /*BB*/
01591 #endif
01592 #ifdef CC
01593   double CC_end;       /*CC*/
01594 #endif
01595 
01596   ijk_flag SET_TO
01597     ((block->i_flag OR block->j_flag) OR block->k_flag) ? ON : OFF;
01598   first SET_TO (settings->program_x IS UNKNOWN);
01599 
01600   CHK(((block->r_flag ISNT ON) AND (ijk_flag ISNT ON)),
01601       NCE_R_I_J_K_WORDS_ALL_MISSING_FOR_ARC);
01602   CHK(((block->r_flag IS ON) AND (ijk_flag IS ON)),
01603       NCE_MIXED_RADIUS_IJK_FORMAT_FOR_ARC);
01604   if (settings->feed_mode IS UNITS_PER_MINUTE)
01605     {
01606       CHK((settings->feed_rate IS 0.0),
01607           NCE_CANNOT_MAKE_ARC_WITH_ZERO_FEED_RATE);
01608     }
01609   else if (settings->feed_mode IS INVERSE_TIME)
01610     {
01611       CHK((block->f_number IS -1.0),
01612           NCE_F_WORD_MISSING_WITH_INVERSE_TIME_ARC_MOVE);
01613     }
01614   if (ijk_flag)
01615     {
01616       if (settings->plane IS CANON_PLANE_XY)
01617         {
01618           CHK((block->k_flag), NCE_K_WORD_GIVEN_FOR_ARC_IN_XY_PLANE);
01619           if (block->i_flag IS OFF) /* i or j flag on to get here */
01620             block->i_number SET_TO 0.0;
01621           else if (block->j_flag IS OFF)
01622             block->j_number SET_TO 0.0;
01623         }
01624       else if (settings->plane IS CANON_PLANE_YZ)
01625         {
01626           CHK((block->i_flag), NCE_I_WORD_GIVEN_FOR_ARC_IN_YZ_PLANE);
01627           if (block->j_flag IS OFF) /* j or k flag on to get here */
01628             block->j_number SET_TO 0.0;
01629           else if (block->k_flag IS OFF)
01630             block->k_number SET_TO 0.0;
01631         }
01632       else if (settings->plane IS CANON_PLANE_XZ)
01633         {
01634           CHK((block->j_flag), NCE_J_WORD_GIVEN_FOR_ARC_IN_XZ_PLANE);
01635           if (block->i_flag IS OFF) /* i or k flag on to get here */
01636             block->i_number SET_TO 0.0;
01637           else if (block->k_flag IS OFF)
01638             block->k_number SET_TO 0.0;
01639         }
01640       else
01641         ERM(NCE_BUG_PLANE_NOT_XY_YZ_OR_XZ);
01642     }
01643   else; /* r format arc; no other checks needed specific to this format */
01644 
01645   if (settings->plane IS CANON_PLANE_XY) /* checks for both formats */
01646     {
01647       CHK(((block->x_flag IS OFF) AND (block->y_flag IS OFF)),
01648           NCE_X_AND_Y_WORDS_MISSING_FOR_ARC_IN_XY_PLANE);
01649     }
01650   else if (settings->plane IS CANON_PLANE_YZ)
01651     {
01652       CHK(((block->y_flag IS OFF) AND (block->z_flag IS OFF)),
01653           NCE_Y_AND_Z_WORDS_MISSING_FOR_ARC_IN_YZ_PLANE);
01654     }
01655   else if (settings->plane IS CANON_PLANE_XZ)
01656     {
01657       CHK(((block->x_flag IS OFF) AND (block->z_flag IS OFF)),
01658           NCE_X_AND_Z_WORDS_MISSING_FOR_ARC_IN_XZ_PLANE);
01659     }
01660 
01661   find_ends(block, settings, &end_x, &end_y,
01662             &end_z
01663 #ifdef AA
01664 , &AA_end
01665 #endif
01666 
01667 #ifdef BB
01668 , &BB_end
01669 #endif
01670 
01671 #ifdef CC
01672 , &CC_end
01673 #endif
01674 );
01675   settings->motion_mode SET_TO move;
01676 
01677   if (settings->plane IS CANON_PLANE_XY)
01678     {
01679       if ((settings->cutter_comp_side IS OFF) OR
01680           (settings->cutter_comp_radius IS 0.0))
01681         {
01682           status SET_TO
01683             convert_arc2(move, block, settings,
01684                          &(settings->current_x), &(settings->current_y),
01685                          &(settings->current_z), end_x, end_y,
01686                          end_z
01687 #ifdef AA
01688 , AA_end
01689 #endif
01690 
01691 #ifdef BB
01692 , BB_end
01693 #endif
01694 
01695 #ifdef CC
01696 , CC_end
01697 #endif
01698 , block->i_number,
01699                          block->j_number);
01700           CHP(status);
01701         }
01702       else if (first)
01703         {
01704           status SET_TO
01705             convert_arc_comp1(move, block, settings, end_x, end_y,
01706                               end_z
01707 #ifdef AA
01708 , AA_end
01709 #endif
01710 
01711 #ifdef BB
01712 , BB_end
01713 #endif
01714 
01715 #ifdef CC
01716 , CC_end
01717 #endif
01718 );
01719           CHP(status);
01720         }
01721       else
01722         {
01723           status SET_TO
01724             convert_arc_comp2(move, block, settings, end_x, end_y,
01725                               end_z
01726 #ifdef AA
01727 , AA_end
01728 #endif
01729 
01730 #ifdef BB
01731 , BB_end
01732 #endif
01733 
01734 #ifdef CC
01735 , CC_end
01736 #endif
01737 );
01738 
01739           CHP(status);
01740         }
01741     }
01742   else if (settings->plane IS CANON_PLANE_XZ)
01743     {
01744       status SET_TO
01745         convert_arc2 (move, block, settings,
01746                       &(settings->current_z), &(settings->current_x),
01747                       &(settings->current_y), end_z, end_x,
01748                       end_y
01749 #ifdef AA
01750 , AA_end
01751 #endif
01752 
01753 #ifdef BB
01754 , BB_end
01755 #endif
01756 
01757 #ifdef CC
01758 , CC_end
01759 #endif
01760 , block->k_number,
01761                       block->i_number);
01762       CHP(status);
01763     }
01764   else if (settings->plane IS CANON_PLANE_YZ)
01765     {
01766       status SET_TO
01767         convert_arc2 (move, block, settings,
01768                       &(settings->current_y), &(settings->current_z),
01769                       &(settings->current_x), end_y, end_z,
01770                       end_x
01771 #ifdef AA
01772 , AA_end
01773 #endif
01774 
01775 #ifdef BB
01776 , BB_end
01777 #endif
01778 
01779 #ifdef CC
01780 , CC_end
01781 #endif
01782 , block->j_number,
01783                       block->k_number);
01784       CHP(status);
01785     }
01786   else
01787     ERM(NCE_BUG_PLANE_NOT_XY_YZ_OR_XZ);
01788   return RS274NGC_OK;
01789 }
01790 
01791 /****************************************************************************/
01792 
01793 /* convert_arc2
01794 
01795 Returned Value: int
01796    If arc_data_ijk or arc_data_r returns an error code,
01797    this returns that code.
01798    Otherwise, it returns RS274NGC_OK.
01799 
01800 Side effects:
01801    This executes an arc command at feed rate. It also updates the
01802    setting of the position of the tool point to the end point of the move.
01803    If inverse time feed rate is in effect, it also resets the feed rate.
01804 
01805 Called by: convert_arc.
01806 
01807 This converts a helical or circular arc.
01808 
01809 */
01810 
01811 static int convert_arc2( /* ARGUMENTS                                */
01812  int move,               /* either G_2 (cw arc) or G_3 (ccw arc)     */
01813  block_pointer block,    /* pointer to a block of RS274 instructions */
01814  setup_pointer settings, /* pointer to machine settings              */
01815  double * current1,      /* pointer to current value of coordinate 1 */
01816  double * current2,      /* pointer to current value of coordinate 2 */
01817  double * current3,      /* pointer to current value of coordinate 3 */
01818  double end1,            /* coordinate 1 value at end of arc         */
01819  double end2,            /* coordinate 2 value at end of arc         */
01820  double end3,            /* coordinate 3 value at end of arc         */
01821 #ifdef AA
01822  double AA_end,          /* a-value at end of arc                    *//*AA*/
01823 #endif
01824 #ifdef BB
01825  double BB_end,          /* b-value at end of arc                    *//*BB*/
01826 #endif
01827 #ifdef CC
01828  double CC_end,          /* c-value at end of arc                    *//*CC*/
01829 #endif
01830  double offset1,         /* offset of center from current1           */
01831  double offset2)         /* offset of center from current2           */
01832 {
01833   static char name[] SET_TO "convert_arc2";
01834   double center1;
01835   double center2;
01836   int status;         /* status returned from CHP function call     */
01837   double tolerance;   /* tolerance for difference of radii          */
01838   int turn;           /* number of full or partial turns CCW in arc */
01839 
01840   tolerance SET_TO (settings->length_units IS CANON_UNITS_INCHES) ?
01841     TOLERANCE_INCH : TOLERANCE_MM;
01842 
01843   if (block->r_flag)
01844     {
01845       CHP(arc_data_r(move, *current1, *current2, end1, end2,
01846                      block->r_number, &center1, &center2, &turn));
01847     }
01848   else
01849     {
01850       CHP(arc_data_ijk(move, *current1, *current2, end1, end2, offset1,
01851                        offset2, &center1, &center2, &turn, tolerance));
01852     }
01853 
01854   if (settings->feed_mode IS INVERSE_TIME)
01855     inverse_time_rate_arc(*current1, *current2, *current3, center1, center2,
01856                           turn, end1, end2, end3, block, settings);
01857   ARC_FEED(end1, end2, center1, center2, turn,
01858             end3
01859 #ifdef AA
01860 , AA_end
01861 #else
01862 #ifdef ALL_AXES
01863 , 0
01864 #endif
01865 #endif
01866 #ifdef BB
01867 , BB_end
01868 #else
01869 #ifdef ALL_AXES
01870 , 0
01871 #endif
01872 #endif
01873 #ifdef CC
01874 , CC_end
01875 #else
01876 #ifdef ALL_AXES
01877 , 0
01878 #endif
01879 #endif
01880 );
01881   *current1 SET_TO end1;
01882   *current2 SET_TO end2;
01883   *current3 SET_TO end3;
01884 #ifdef AA
01885   settings->AA_current SET_TO AA_end;  /*AA*/
01886 #endif
01887 #ifdef BB
01888   settings->BB_current SET_TO BB_end;  /*BB*/
01889 #endif
01890 #ifdef CC
01891   settings->CC_current SET_TO CC_end;  /*CC*/
01892 #endif
01893   return RS274NGC_OK;
01894 }
01895 
01896 /****************************************************************************/
01897 
01898 /* convert_arc_comp1
01899 
01900 Returned Value: int
01901    If arc_data_comp_ijk or arc_data_comp_r returns an error code,
01902    this returns that code.
01903    Otherwise, it returns RS274NGC_OK.
01904 
01905 Side effects:
01906    This executes an arc command at
01907    feed rate. It also updates the setting of the position of
01908    the tool point to the end point of the move.
01909 
01910 Called by: convert_arc.
01911 
01912 This function converts a helical or circular arc, generating only one
01913 arc. The axis must be parallel to the z-axis. This is called when
01914 cutter radius compensation is on and this is the first cut after the
01915 turning on.
01916 
01917 The arc which is generated is derived from a second arc which passes
01918 through the programmed end point and is tangent to the cutter at its
01919 current location. The generated arc moves the tool so that it stays
01920 tangent to the second arc throughout the move.
01921 
01922 */
01923 
01924 static int convert_arc_comp1( /* ARGUMENTS                                   */
01925  int move,               /* either G_2 (cw arc) or G_3 (ccw arc)             */
01926  block_pointer block,    /* pointer to a block of RS274/NGC instructions     */
01927  setup_pointer settings, /* pointer to machine settings                      */
01928  double end_x,           /* x-value at end of programmed (then actual) arc   */
01929  double end_y,           /* y-value at end of programmed (then actual) arc   */
01930  double end_z            /* z-value at end of arc                            */
01931 #ifdef AA
01932  , double AA_end         /* a-value at end of arc                      *//*AA*/
01933 #endif
01934 #ifdef BB
01935  , double BB_end         /* b-value at end of arc                      *//*BB*/
01936 #endif
01937 #ifdef CC
01938  , double CC_end         /* c-value at end of arc                      *//*CC*/
01939 #endif
01940 )
01941 {
01942   static char name[] SET_TO "convert_arc_comp1";
01943   double center_x;
01944   double center_y;
01945   double gamma;       /* direction of perpendicular to arc at end */
01946   int side;           /* offset side - right or left              */
01947   int status;         /* status returned from CHP function call   */
01948   double tolerance;   /* tolerance for difference of radii        */
01949   double tool_radius;
01950   int turn;           /* 1 for counterclockwise, -1 for clockwise */
01951 
01952   side SET_TO settings->cutter_comp_side;
01953   tool_radius SET_TO settings->cutter_comp_radius; /* always is positive */
01954   tolerance SET_TO (settings->length_units IS CANON_UNITS_INCHES) ?
01955     TOLERANCE_INCH : TOLERANCE_MM;
01956 
01957   CHK((hypot((end_x - settings->current_x),
01958              (end_y - settings->current_y)) <= tool_radius),
01959       NCE_CUTTER_GOUGING_WITH_CUTTER_RADIUS_COMP);
01960 
01961   if (block->r_flag)
01962     {
01963       CHP(arc_data_comp_r(move, side, tool_radius, settings->current_x,
01964                           settings->current_y, end_x, end_y, block->r_number,
01965                           &center_x, &center_y, &turn));
01966     }
01967   else
01968     {
01969       CHP(arc_data_comp_ijk(move, side, tool_radius, settings->current_x,
01970                             settings->current_y, end_x, end_y,
01971                             block->i_number, block->j_number,
01972                             &center_x, &center_y, &turn, tolerance));
01973     }
01974 
01975   gamma SET_TO
01976     (((side IS LEFT) AND (move IS G_3)) OR
01977      ((side IS RIGHT) AND (move IS G_2))) ?
01978        atan2 ((center_y - end_y), (center_x - end_x)) :
01979        atan2 ((end_y - center_y), (end_x - center_x));
01980 
01981   settings->program_x SET_TO end_x;
01982   settings->program_y SET_TO end_y;
01983   end_x SET_TO (end_x + (tool_radius * cos(gamma))); /* end_x reset actual */
01984   end_y SET_TO (end_y + (tool_radius * sin(gamma))); /* end_y reset actual */
01985 
01986   if (settings->feed_mode IS INVERSE_TIME)
01987     inverse_time_rate_arc(settings->current_x, settings->current_y,
01988                           settings->current_z, center_x, center_y, turn,
01989                           end_x, end_y, end_z, block, settings);
01990   ARC_FEED(end_x, end_y, center_x, center_y, turn,
01991            end_z
01992 #ifdef AA
01993 , AA_end
01994 #else
01995 #ifdef ALL_AXES
01996 , 0
01997 #endif
01998 #endif
01999 #ifdef BB
02000 , BB_end
02001 #else
02002 #ifdef ALL_AXES
02003 , 0
02004 #endif
02005 #endif
02006 #ifdef CC
02007 , CC_end
02008 #else
02009 #ifdef ALL_AXES
02010 , 0
02011 #endif
02012 #endif
02013 );
02014   settings->current_x SET_TO end_x;
02015   settings->current_y SET_TO end_y;
02016   settings->current_z SET_TO end_z;
02017 #ifdef AA
02018   settings->AA_current SET_TO AA_end;  /*AA*/
02019 #endif
02020 #ifdef BB
02021   settings->BB_current SET_TO BB_end;  /*BB*/
02022 #endif
02023 #ifdef CC
02024   settings->CC_current SET_TO CC_end;  /*CC*/
02025 #endif
02026 
02027   return RS274NGC_OK;
02028 }
02029 
02030 /****************************************************************************/
02031 
02032 /* convert_arc_comp2
02033 
02034 Returned Value: int
02035    If arc_data_ijk or arc_data_r returns an error code,
02036    this returns that code.
02037    If any of the following errors occurs, this returns the error code shown.
02038    Otherwise, it returns RS274NGC_OK.
02039    1. A concave corner is found: NCE_CONCAVE_CORNER_WITH_CUTTER_RADIUS_COMP
02040    2. The tool will not fit inside an arc:
02041       NCE_TOOL_RADIUS_NOT_LESS_THAN_ARC_RADIUS_WITH_COMP
02042 
02043 Side effects:
02044    This executes an arc command feed rate. If needed, at also generates
02045    an arc to go around a convex corner. It also updates the setting of
02046    the position of the tool point to the end point of the move. If
02047    inverse time feed rate mode is in effect, the feed rate is reset.
02048 
02049 Called by: convert_arc.
02050 
02051 This function converts a helical or circular arc. The axis must be
02052 parallel to the z-axis. This is called when cutter radius compensation
02053 is on and this is not the first cut after the turning on.
02054 
02055 If one or more rotary axes is moved in this block and an extra arc is
02056 required to go around a sharp corner, all the rotary axis motion
02057 occurs on the main arc and none on the extra arc.  An alternative
02058 might be to distribute the rotary axis motion over the extra arc and
02059 the programmed arc in proportion to their lengths.
02060 
02061 If the Z-axis is moved in this block and an extra arc is required to
02062 go around a sharp corner, all the Z-axis motion occurs on the main arc
02063 and none on the extra arc.  An alternative might be to distribute the
02064 Z-axis motion over the extra arc and the main arc in proportion to
02065 their lengths.
02066 
02067 */
02068 
02069 static int convert_arc_comp2( /* ARGUMENTS                                 */
02070  int move,               /* either G_2 (cw arc) or G_3 (ccw arc)           */
02071  block_pointer block,    /* pointer to a block of RS274/NGC instructions   */
02072  setup_pointer settings, /* pointer to machine settings                    */
02073  double end_x,           /* x-value at end of programmed (then actual) arc */
02074  double end_y,           /* y-value at end of programmed (then actual) arc */
02075  double end_z            /* z-value at end of arc                          */
02076 #ifdef AA
02077  , double AA_end         /* a-value at end of arc                    *//*AA*/
02078 #endif
02079 #ifdef BB
02080  , double BB_end         /* b-value at end of arc                    *//*BB*/
02081 #endif
02082 #ifdef CC
02083  , double CC_end         /* c-value at end of arc                    *//*CC*/
02084 #endif
02085 )
02086 {
02087   static char name[] SET_TO "convert_arc_comp2";
02088   double alpha;    /* direction of tangent to start of arc */
02089   double arc_radius;
02090   double beta;     /* angle between two tangents above */
02091   double center_x; /* center of arc */
02092   double center_y;
02093   double delta;    /* direction of radius from start of arc to center of arc */
02094   double gamma;    /* direction of perpendicular to arc at end */
02095   double mid_x;
02096   double mid_y;
02097   int side;
02098   double small SET_TO TOLERANCE_CONCAVE_CORNER; /* angle for testing corners */
02099   double start_x;
02100   double start_y;
02101   int status;      /* status returned from CHP function call     */
02102   double theta;    /* direction of tangent to last cut */
02103   double tolerance;
02104   double tool_radius;
02105   int turn;        /* number of full or partial circles CCW */
02106 
02107 /* find basic arc data: center_x, center_y, and turn */
02108 
02109   start_x SET_TO settings->program_x;
02110   start_y SET_TO settings->program_y;
02111   tolerance SET_TO (settings->length_units IS CANON_UNITS_INCHES) ?
02112     TOLERANCE_INCH : TOLERANCE_MM;
02113 
02114   if (block->r_flag)
02115     {
02116       CHP(arc_data_r(move, start_x, start_y, end_x, end_y,
02117                      block->r_number, &center_x, &center_y, &turn));
02118     }
02119   else
02120     {
02121       CHP(arc_data_ijk(move, start_x, start_y, end_x, end_y,
02122                        block->i_number, block->j_number,
02123                        &center_x, &center_y, &turn, tolerance));
02124     }
02125 
02126 /* compute other data */
02127   side SET_TO settings->cutter_comp_side;
02128   tool_radius SET_TO settings->cutter_comp_radius; /* always is positive */
02129   arc_radius SET_TO hypot((center_x - end_x), (center_y - end_y));
02130   theta SET_TO
02131     atan2(settings->current_y - start_y, settings->current_x - start_x);
02132   theta SET_TO (side IS LEFT) ? (theta - PI2) : (theta + PI2);
02133   delta SET_TO atan2(center_y - start_y, center_x - start_x);
02134   alpha SET_TO (move IS G_3) ? (delta - PI2) : (delta + PI2);
02135   beta SET_TO (side IS LEFT) ? (theta - alpha) : (alpha - theta);
02136   beta SET_TO (beta > (1.5 * PI))  ? (beta - TWO_PI) :
02137               (beta < -PI2) ? (beta + TWO_PI) : beta;
02138 
02139   if (((side IS LEFT)  AND (move IS G_3)) OR
02140       ((side IS RIGHT) AND (move IS G_2)))
02141     {
02142       gamma SET_TO atan2 ((center_y - end_y), (center_x - end_x));
02143       CHK((arc_radius <= tool_radius),
02144           NCE_TOOL_RADIUS_NOT_LESS_THAN_ARC_RADIUS_WITH_COMP);
02145     }
02146   else
02147     {
02148       gamma SET_TO atan2 ((end_y - center_y), (end_x - center_x));
02149       delta SET_TO (delta + PI);
02150     }
02151 
02152   settings->program_x SET_TO end_x;
02153   settings->program_y SET_TO end_y;
02154   end_x SET_TO (end_x + (tool_radius * cos(gamma))); /* end_x reset actual */
02155   end_y SET_TO (end_y + (tool_radius * sin(gamma))); /* end_y reset actual */
02156 
02157 /* check if extra arc needed and insert if so */
02158 
02159   CHK(((beta < -small) OR (beta > (PI + small))),
02160       NCE_CONCAVE_CORNER_WITH_CUTTER_RADIUS_COMP);
02161   if (beta > small) /* two arcs needed */
02162     {
02163       mid_x SET_TO (start_x + (tool_radius * cos(delta)));
02164       mid_y SET_TO (start_y + (tool_radius * sin(delta)));
02165       if (settings->feed_mode IS INVERSE_TIME)
02166         inverse_time_rate_arc2(start_x, start_y, (side IS LEFT) ? -1 : 1,
02167                                mid_x, mid_y, center_x, center_y, turn,
02168                                end_x, end_y, end_z, block, settings);
02169       ARC_FEED(mid_x, mid_y, start_x, start_y, ((side IS LEFT) ? -1 : 1),
02170                settings->current_z
02171 #ifdef AA
02172 , AA_end
02173 #else
02174 #ifdef ALL_AXES
02175 , 0
02176 #endif
02177 #endif
02178 #ifdef BB
02179 , BB_end
02180 #else
02181 #ifdef ALL_AXES
02182 , 0
02183 #endif
02184 #endif
02185 #ifdef CC
02186 , CC_end
02187 #else
02188 #ifdef ALL_AXES
02189 , 0
02190 #endif
02191 #endif
02192 );
02193       ARC_FEED(end_x, end_y, center_x, center_y, turn,
02194                end_z
02195 #ifdef AA
02196 , AA_end
02197 #else
02198 #ifdef ALL_AXES
02199 , 0
02200 #endif
02201 #endif
02202 #ifdef BB
02203 , BB_end
02204 #else
02205 #ifdef ALL_AXES
02206 , 0
02207 #endif
02208 #endif
02209 #ifdef CC
02210 , CC_end
02211 #else
02212 #ifdef ALL_AXES
02213 , 0
02214 #endif
02215 #endif
02216 );
02217     }
02218   else /* one arc needed */
02219     {
02220       if (settings->feed_mode IS INVERSE_TIME)
02221         inverse_time_rate_arc(settings->current_x, settings->current_y,
02222                               settings->current_z, center_x, center_y, turn,
02223                               end_x, end_y, end_z, block, settings);
02224       ARC_FEED(end_x, end_y, center_x, center_y, turn,
02225                end_z
02226 #ifdef AA
02227 , AA_end
02228 #else
02229 #ifdef ALL_AXES
02230 , 0
02231 #endif
02232 #endif
02233 #ifdef BB
02234 , BB_end
02235 #else
02236 #ifdef ALL_AXES
02237 , 0
02238 #endif
02239 #endif
02240 #ifdef CC
02241 , CC_end
02242 #else
02243 #ifdef ALL_AXES
02244 , 0
02245 #endif
02246 #endif
02247 );
02248     }
02249 
02250   settings->current_x SET_TO end_x;
02251   settings->current_y SET_TO end_y;
02252   settings->current_z SET_TO end_z;
02253 #ifdef AA
02254   settings->AA_current SET_TO AA_end;                      /*AA*/
02255 #endif
02256 #ifdef BB
02257   settings->BB_current SET_TO BB_end;                      /*BB*/
02258 #endif
02259 #ifdef CC
02260   settings->CC_current SET_TO CC_end;                      /*CC*/
02261 #endif
02262 
02263   return RS274NGC_OK;
02264 }
02265 
02266 /****************************************************************************/
02267 
02268 /* convert_axis_offsets
02269 
02270 Returned Value: int
02271    If any of the following errors occur, this returns the error code shown.
02272    Otherwise, it returns RS274NGC_OK.
02273    1. The function is called when cutter radius compensation is on:
02274       NCE_CANNOT_CHANGE_AXIS_OFFSETS_WITH_CUTTER_RADIUS_COMP
02275    2. The g_code argument is not G_92, G_92_1, G_92_2, or G_92_3
02276       NCE_BUG_CODE_NOT_IN_G92_SERIES
02277 
02278 Side effects:
02279    SET_PROGRAM_ORIGIN is called, and the coordinate
02280    values for the axis offsets are reset. The coordinates of the
02281    current point are reset. Parameters may be set.
02282 
02283 Called by: convert_modal_0.
02284 
02285 The action of G92 is described in [NCMS, pages 10 - 11] and {Fanuc,
02286 pages 61 - 63]. [NCMS] is ambiguous about the intent, but [Fanuc]
02287 is clear. When G92 is executed, an offset of the origin is calculated
02288 so that the coordinates of the current point with respect to the moved
02289 origin are as specified on the line containing the G92. If an axis
02290 is not mentioned on the line, the coordinates of the current point
02291 are not changed. The execution of G92 results in an axis offset being
02292 calculated and saved for each of the six axes, and the axis offsets
02293 are always used when motion is specified with respect to absolute
02294 distance mode using any of the nine coordinate systems (those designated
02295 by G54 - G59.3). Thus all nine coordinate systems are affected by G92.
02296 
02297 Being in incremental distance mode has no effect on the action of G92
02298 in this implementation. [NCMS] is not explicit about this, but it is
02299 implicit in the second sentence of [Fanuc, page 61].
02300 
02301 The offset is the amount the origin must be moved so that the
02302 coordinate of the controlled point has the specified value. For
02303 example, if the current point is at X=4 in the currently specified
02304 coordinate system and the current X-axis offset is zero, then "G92 x7"
02305 causes the X-axis offset to be reset to -3.
02306 
02307 Since a non-zero offset may be already be in effect when the G92 is
02308 called, that must be taken into account.
02309 
02310 In addition to causing the axis offset values in the _setup model to be
02311 set, G92 sets parameters 5211 to 5216 to the x,y,z,a,b,c axis offsets.
02312 
02313 The action of G92.2 is described in [NCMS, page 12]. There is no
02314 equivalent command in [Fanuc]. G92.2 resets axis offsets to zero.
02315 G92.1, also included in [NCMS, page 12] (but the usage here differs
02316 slightly from the spec), is like G92.2, except that it also causes
02317 the axis offset parameters to be set to zero, whereas G92.2 does not
02318 zero out the parameters.
02319 
02320 G92.3 is not in [NCMS]. It sets the axis offset values to the values
02321 given in the parameters.
02322 
02323 */
02324 
02325 static int convert_axis_offsets( /* ARGUMENTS                               */
02326  int g_code,              /* g_code being executed (must be in G_92 series) */
02327  block_pointer block,     /* pointer to a block of RS274/NGC instructions   */
02328  setup_pointer settings)  /* pointer to machine settings                    */
02329 {
02330   static char name[] SET_TO "convert_axis_offsets";
02331   double * pars;          /* short name for settings->parameters            */
02332 
02333   CHK((settings->cutter_comp_side ISNT OFF), /* not "IS ON" */
02334       NCE_CANNOT_CHANGE_AXIS_OFFSETS_WITH_CUTTER_RADIUS_COMP);
02335   pars SET_TO settings->parameters;
02336   if (g_code IS G_92)
02337     {
02338       if (block->x_flag IS ON)
02339         {
02340           settings->axis_offset_x SET_TO
02341             (settings->current_x + settings->axis_offset_x - block->x_number);
02342           settings->current_x SET_TO block->x_number;
02343         }
02344 
02345       if (block->y_flag IS ON)
02346         {
02347           settings->axis_offset_y SET_TO
02348             (settings->current_y + settings->axis_offset_y - block->y_number);
02349           settings->current_y SET_TO block->y_number;
02350         }
02351 
02352       if (block->z_flag IS ON)
02353         {
02354           settings->axis_offset_z SET_TO
02355             (settings->current_z + settings->axis_offset_z - block->z_number);
02356           settings->current_z SET_TO block->z_number;
02357         }
02358 
02359 #ifdef AA
02360       if (block->a_flag IS ON)                                           /*AA*/
02361 #endif
02362 #ifdef AA
02363         {settings->AA_axis_offset SET_TO (settings->AA_current +         /*AA*/
02364 #endif
02365 #ifdef AA
02366                             settings->AA_axis_offset - block->a_number); /*AA*/
02367 #endif
02368 #ifdef AA
02369           settings->AA_current SET_TO block->a_number;}                  /*AA*/
02370 #endif
02371 
02372 #ifdef BB
02373       if (block->b_flag IS ON)                                           /*BB*/
02374 #endif
02375 #ifdef BB
02376         {settings->BB_axis_offset SET_TO (settings->BB_current +         /*BB*/
02377 #endif
02378 #ifdef BB
02379                             settings->BB_axis_offset - block->b_number); /*BB*/
02380 #endif
02381 #ifdef BB
02382           settings->BB_current SET_TO block->b_number;}                  /*BB*/
02383 #endif
02384 
02385 #ifdef CC
02386       if (block->c_flag IS ON)                                           /*CC*/
02387 #endif
02388 #ifdef CC
02389         {settings->CC_axis_offset SET_TO (settings->CC_current +         /*CC*/
02390 #endif
02391 #ifdef CC
02392                             settings->CC_axis_offset - block->c_number); /*CC*/
02393 #endif
02394 #ifdef CC
02395           settings->CC_current SET_TO block->c_number;}                  /*CC*/
02396 #endif
02397 
02398       SET_ORIGIN_OFFSETS(settings->origin_offset_x + settings->axis_offset_x,
02399                          settings->origin_offset_y + settings->axis_offset_y,
02400                          settings->origin_offset_z + settings->axis_offset_z
02401 #ifdef AA
02402 ,                      (settings->AA_origin_offset + settings->AA_axis_offset)
02403 #else
02404 #ifdef ALL_AXES
02405 , 0
02406 #endif
02407 #endif
02408 #ifdef BB
02409 ,                      (settings->BB_origin_offset + settings->BB_axis_offset)
02410 #else
02411 #ifdef ALL_AXES
02412 , 0
02413 #endif
02414 #endif
02415 #ifdef CC
02416 ,                      (settings->CC_origin_offset + settings->CC_axis_offset)
02417 #else
02418 #ifdef ALL_AXES
02419 , 0
02420 #endif
02421 #endif
02422 );
02423       pars[5211] SET_TO settings->axis_offset_x;
02424       pars[5212] SET_TO settings->axis_offset_y;
02425       pars[5213] SET_TO settings->axis_offset_z;
02426 #ifdef AA
02427       pars[5214] SET_TO settings->AA_axis_offset;                      /*AA*/
02428 #endif
02429 #ifdef BB
02430       pars[5215] SET_TO settings->BB_axis_offset;                      /*BB*/
02431 #endif
02432 #ifdef CC
02433       pars[5216] SET_TO settings->CC_axis_offset;                      /*CC*/
02434 #endif
02435 
02436     }
02437   else if ((g_code IS G_92_1) OR (g_code IS G_92_2))
02438     {
02439       settings->current_x SET_TO
02440         settings->current_x + settings->axis_offset_x;
02441       settings->current_y SET_TO
02442         settings->current_y + settings->axis_offset_y;
02443       settings->current_z SET_TO
02444         settings->current_z + settings->axis_offset_z;
02445 #ifdef AA
02446       settings->AA_current SET_TO                                      /*AA*/
02447 #endif
02448 #ifdef AA
02449         (settings->AA_current + settings->AA_axis_offset);             /*AA*/
02450 #endif
02451 #ifdef BB
02452       settings->BB_current SET_TO                                      /*BB*/
02453 #endif
02454 #ifdef BB
02455         (settings->BB_current + settings->BB_axis_offset);             /*BB*/
02456 #endif
02457 #ifdef CC
02458       settings->CC_current SET_TO                                      /*CC*/
02459 #endif
02460 #ifdef CC
02461         (settings->CC_current + settings->CC_axis_offset);             /*CC*/
02462 #endif
02463       SET_ORIGIN_OFFSETS(settings->origin_offset_x,
02464                          settings->origin_offset_y,
02465                          settings->origin_offset_z
02466 #ifdef AA
02467 ,                        settings->AA_origin_offset
02468 #else
02469 #ifdef ALL_AXES
02470 , 0
02471 #endif
02472 #endif
02473 #ifdef BB
02474 ,                        settings->BB_origin_offset
02475 #else
02476 #ifdef ALL_AXES
02477 , 0
02478 #endif
02479 #endif
02480 #ifdef CC
02481 ,                        settings->CC_origin_offset
02482 #else
02483 #ifdef ALL_AXES
02484 , 0
02485 #endif
02486 #endif
02487 );
02488       settings->axis_offset_x SET_TO 0.0;
02489       settings->axis_offset_y SET_TO 0.0;
02490       settings->axis_offset_z SET_TO 0.0;
02491 #ifdef AA
02492       settings->AA_axis_offset SET_TO 0.0;                             /*AA*/
02493 #endif
02494 #ifdef BB
02495       settings->BB_axis_offset SET_TO 0.0;                             /*BB*/
02496 #endif
02497 #ifdef CC
02498       settings->CC_axis_offset SET_TO 0.0;                             /*CC*/
02499 #endif
02500       if (g_code IS G_92_1)
02501         {
02502           pars[5211] SET_TO 0.0;
02503           pars[5212] SET_TO 0.0;
02504           pars[5213] SET_TO 0.0;
02505 #ifdef AA
02506           pars[5214] SET_TO 0.0;                                       /*AA*/
02507 #endif
02508 #ifdef BB
02509           pars[5215] SET_TO 0.0;                                       /*BB*/
02510 #endif
02511 #ifdef CC
02512           pars[5216] SET_TO 0.0;                                       /*CC*/
02513 #endif
02514         }
02515     }
02516   else if (g_code IS G_92_3)
02517     {
02518       settings->current_x SET_TO
02519         settings->current_x + settings->axis_offset_x - pars[5211];
02520       settings->current_y SET_TO
02521         settings->current_y + settings->axis_offset_y - pars[5212];
02522       settings->current_z SET_TO
02523         settings->current_z + settings->axis_offset_z - pars[5213];
02524 #ifdef AA
02525       settings->AA_current SET_TO                                      /*AA*/
02526 #endif
02527 #ifdef AA
02528         settings->AA_current + settings->AA_axis_offset - pars[5214];  /*AA*/
02529 #endif
02530 #ifdef BB
02531       settings->BB_current SET_TO                                      /*BB*/
02532 #endif
02533 #ifdef BB
02534         settings->BB_current + settings->BB_axis_offset - pars[5215];  /*BB*/
02535 #endif
02536 #ifdef CC
02537       settings->CC_current SET_TO                                      /*CC*/
02538 #endif
02539 #ifdef CC
02540         settings->CC_current + settings->CC_axis_offset - pars[5216];  /*CC*/
02541 #endif
02542       settings->axis_offset_x SET_TO pars[5211];
02543       settings->axis_offset_y SET_TO pars[5212];
02544       settings->axis_offset_z SET_TO pars[5213];
02545 #ifdef AA
02546       settings->AA_axis_offset SET_TO pars[5214];                      /*AA*/
02547 #endif
02548 #ifdef BB
02549       settings->BB_axis_offset SET_TO pars[5215];                      /*BB*/
02550 #endif
02551 #ifdef CC
02552       settings->CC_axis_offset SET_TO pars[5216];                      /*CC*/
02553 #endif
02554       SET_ORIGIN_OFFSETS(settings->origin_offset_x + settings->axis_offset_x,
02555                          settings->origin_offset_y + settings->axis_offset_y,
02556                          settings->origin_offset_z + settings->axis_offset_z
02557 #ifdef AA
02558 ,                      (settings->AA_origin_offset + settings->AA_axis_offset)
02559 #else
02560 #ifdef ALL_AXES
02561 , 0
02562 #endif
02563 #endif
02564 #ifdef BB
02565 ,                      (settings->BB_origin_offset + settings->BB_axis_offset)
02566 #else
02567 #ifdef ALL_AXES
02568 , 0
02569 #endif
02570 #endif
02571 #ifdef CC
02572 ,                      (settings->CC_origin_offset + settings->CC_axis_offset)
02573 #else
02574 #ifdef ALL_AXES
02575 , 0
02576 #endif
02577 #endif
02578 );
02579     }
02580   else
02581     ERM(NCE_BUG_CODE_NOT_IN_G92_SERIES);
02582 
02583   return RS274NGC_OK;
02584 }
02585 
02586 /****************************************************************************/
02587 
02588 /* convert_comment
02589 
02590 Returned Value: int (RS274NGC_OK)
02591 
02592 Side effects:
02593    The message function is called if the string starts with "MSG,".
02594    Otherwise, the comment function is called.
02595 
02596 Called by: execute_block
02597 
02598 To be a message, the first four characters of the comment after the
02599 opening left parenthesis must be "MSG,", ignoring the case of the
02600 letters and allowing spaces or tabs anywhere before the comma (to make
02601 the treatment of case and white space consistent with how it is
02602 handled elsewhere).
02603 
02604 Messages are not provided for in [NCMS]. They are implemented here as a
02605 subtype of comment. This is an extension to the rs274NGC language.
02606 
02607 */
02608 
02609 static int convert_comment( /*ARGUMENTS            */
02610  char * comment)            /* string with comment */
02611 {
02612   int m;
02613   int item;
02614 
02615   for (m SET_TO 0; ((item SET_TO comment[m]) IS ' ') OR (item IS '\t') ; m++);
02616   if ((item ISNT 'M') AND (item ISNT 'm'))
02617     {
02618       COMMENT(comment);
02619       return RS274NGC_OK;
02620     }
02621   for (m++; ((item SET_TO comment[m]) IS ' ') OR (item IS '\t') ; m++);
02622   if ((item ISNT 'S') AND (item ISNT 's'))
02623     {
02624       COMMENT(comment);
02625       return RS274NGC_OK;
02626     }
02627   for (m++; ((item SET_TO comment[m]) IS ' ') OR (item IS '\t') ; m++);
02628   if ((item ISNT 'G') AND (item ISNT 'g'))
02629     {
02630       COMMENT(comment);
02631       return RS274NGC_OK;
02632     }
02633   for (m++; ((item SET_TO comment[m]) IS ' ') OR (item IS '\t') ; m++);
02634   if (item ISNT ',')
02635     {
02636       COMMENT(comment);
02637       return RS274NGC_OK;
02638     }
02639   MESSAGE(comment + m + 1);
02640   return RS274NGC_OK;
02641 }
02642 
02643 /****************************************************************************/
02644 
02645 /* convert_control_mode
02646 
02647 Returned Value: int
02648    If any of the following errors occur, this returns the error code shown.
02649    Otherwise, it returns RS274NGC_OK.
02650    1. g_code isn't G_61, G_61_1 or G_64: NCE_BUG_CODE_NOT_G61_G61_1_OR_G64
02651 
02652 Side effects: See below
02653 
02654 Called by: convert_g.
02655 
02656 The interpreter switches the machine settings to indicate the
02657 control mode (CANON_EXACT_STOP, CANON_EXACT_PATH or CANON_CONTINUOUS).
02658 
02659 A call is made to SET_MOTION_CONTROL_MODE(CANON_XXX), where CANON_XXX is
02660 CANON_EXACT_PATH if g_code is G_61, CANON_EXACT_STOP if g_code is G_61_1,
02661 and CANON_CONTINUOUS if g_code is G_64.
02662 
02663 Setting the control mode to CANON_EXACT_STOP on G_61 would correspond
02664 more closely to the meaning of G_61 as given in [NCMS, page 40], but
02665 CANON_EXACT_PATH has the advantage that the tool does not stop if it
02666 does not have to, and no evident disadvantage compared to
02667 CANON_EXACT_STOP, so it is being used for G_61. G_61_1 is not defined
02668 in [NCMS], so it is available and is used here for setting the control
02669 mode to CANON_EXACT_STOP.
02670 
02671 It is OK to call SET_MOTION_CONTROL_MODE(CANON_XXX) when CANON_XXX is
02672 already in force.
02673 
02674 */
02675 
02676 static int convert_control_mode(  /* ARGUMENTS                             */
02677  int g_code,               /* g_code being executed (G_61, G61_1, OR G_64) */
02678  setup_pointer settings)   /* pointer to machine settings                  */
02679 {
02680   static char name[] SET_TO "convert_control_mode";
02681   if (g_code IS G_61)
02682     {
02683       SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH);
02684       settings->control_mode SET_TO CANON_EXACT_PATH;
02685     }
02686   else if (g_code IS G_61_1)
02687     {
02688       SET_MOTION_CONTROL_MODE(CANON_EXACT_STOP);
02689       settings->control_mode SET_TO CANON_EXACT_STOP;
02690     }
02691   else if (g_code IS G_64)
02692     {
02693       SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS);
02694       settings->control_mode SET_TO CANON_CONTINUOUS;
02695     }
02696   else
02697     ERM(NCE_BUG_CODE_NOT_G61_G61_1_OR_G64);
02698   return RS274NGC_OK;
02699 }
02700 
02701 /****************************************************************************/
02702 
02703 /* convert_coordinate_system
02704 
02705 Returned Value: int
02706    If any of the following errors occur, this returns the error code shown.
02707    Otherwise, it returns RS274NGC_OK.
02708    1. The value of the g_code argument is not 540, 550, 560, 570, 580, 590
02709       591, 592, or 593:
02710       NCE_BUG_CODE_NOT_IN_RANGE_G54_TO_G593
02711 
02712 Side effects:
02713    If the coordinate system selected by the g_code is not already in
02714    use, the canonical program coordinate system axis offset values are
02715    reset and the coordinate values of the current point are reset.
02716 
02717 Called by: convert_g.
02718 
02719 COORDINATE SYSTEMS (involves g10, g53, g54 - g59.3, g92)
02720 
02721 The canonical machining functions view of coordinate systems is:
02722 1. There are two coordinate systems: absolute and program.
02723 2. All coordinate values are given in terms of the program coordinate system.
02724 3. The offsets of the program coordinate system may be reset.
02725 
02726 The RS274/NGC view of coordinate systems, as given in section 3.2
02727 of [NCMS] is:
02728 1. there are ten coordinate systems: absolute and 9 program. The
02729    program coordinate systems are numbered 1 to 9.
02730 2. you can switch among the 9 but not to the absolute one. G54
02731    selects coordinate system 1, G55 selects 2, and so on through
02732    G56, G57, G58, G59, G59.1, G59.2, and G59.3.
02733 3. you can set the offsets of the 9 program coordinate systems
02734    using G10 L2 Pn (n is the number of the coordinate system) with
02735    values for the axes in terms of the absolute coordinate system.
02736 4. the first one of the 9 program coordinate systems is the default.
02737 5. data for coordinate systems is stored in parameters [NCMS, pages 59 - 60].
02738 6. g53 means to interpret coordinate values in terms of the absolute
02739    coordinate system for the one block in which g53 appears.
02740 7. You can offset the current coordinate system using g92. This offset
02741    will then apply to all nine program coordinate systems.
02742 
02743 The approach used in the interpreter mates the canonical and NGC views
02744 of coordinate systems as follows:
02745 
02746 During initialization, data from the parameters for the first NGC
02747 coordinate system is used in a SET_ORIGIN_OFFSETS function call and
02748 origin_index in the machine model is set to 1.
02749 
02750 If a g_code in the range g54 - g59.3 is encountered in an NC program,
02751 the data from the appropriate NGC coordinate system is copied into the
02752 origin offsets used by the interpreter, a SET_ORIGIN_OFFSETS function
02753 call is made, and the current position is reset.
02754 
02755 If a g10 is encountered, the convert_setup function is called to reset
02756 the offsets of the program coordinate system indicated by the P number
02757 given in the same block.
02758 
02759 If a g53 is encountered, the axis values given in that block are used
02760 to calculate what the coordinates are of that point in the current
02761 coordinate system, and a STRAIGHT_TRAVERSE or STRAIGHT_FEED function
02762 call to that point using the calculated values is made. No offset
02763 values are changed.
02764 
02765 If a g92 is encountered, that is handled by the convert_axis_offsets
02766 function. A g92 results in an axis offset for each axis being calculated
02767 and stored in the machine model. The axis offsets are applied to all
02768 nine coordinate systems. Axis offsets are initialized to zero.
02769 
02770 */
02771 
02772 static int convert_coordinate_system( /* ARGUMENTS                         */
02773  int g_code,              /* g_code called (must be one listed above)      */
02774  setup_pointer settings)  /* pointer to machine settings                   */
02775 {
02776   static char name[] SET_TO "convert_coordinate_system";
02777   int origin;
02778   double x;
02779   double y;
02780   double z;
02781 #ifdef AA
02782   double a; /*AA*/
02783 #endif
02784 #ifdef BB
02785   double b; /*BB*/
02786 #endif
02787 #ifdef CC
02788   double c; /*CC*/
02789 #endif
02790   double * parameters;
02791 
02792   parameters SET_TO settings->parameters;
02793   switch(g_code)
02794     {
02795     case 540:
02796       origin SET_TO 1;
02797       break;
02798     case 550:
02799       origin SET_TO 2;
02800       break;
02801     case 560:
02802       origin SET_TO 3;
02803       break;
02804     case 570:
02805       origin SET_TO 4;
02806       break;
02807     case 580:
02808       origin SET_TO 5;
02809       break;
02810     case 590:
02811       origin SET_TO 6;
02812       break;
02813     case 591:
02814       origin SET_TO 7;
02815       break;
02816     case 592:
02817       origin SET_TO 8;
02818       break;
02819     case 593:
02820       origin SET_TO 9;
02821       break;
02822     default:
02823       ERM(NCE_BUG_CODE_NOT_IN_RANGE_G54_TO_G593);
02824     }
02825 
02826   if (origin IS settings->origin_index) /* already using this origin */
02827     {
02828 #ifdef DEBUG_EMC
02829       COMMENT("interpreter: continuing to use same coordinate system");
02830 #endif
02831       return RS274NGC_OK;
02832     }
02833 
02834   settings->origin_index SET_TO origin;
02835   parameters[5220] SET_TO (double)origin;
02836 
02837 /* axis offsets could be included in the two set of calculations for
02838    current_x, current_y, etc., but do not need to be because the results
02839    would be the same. They would be added in then subtracted out. */
02840   settings->current_x SET_TO
02841     (settings->current_x + settings->origin_offset_x);
02842   settings->current_y SET_TO
02843     (settings->current_y + settings->origin_offset_y);
02844   settings->current_z SET_TO
02845     (settings->current_z + settings->origin_offset_z);
02846 #ifdef AA
02847   settings->AA_current SET_TO                                /*AA*/
02848 #endif
02849 #ifdef AA
02850     (settings->AA_current + settings->AA_origin_offset);     /*AA*/
02851 #endif
02852 #ifdef BB
02853   settings->BB_current SET_TO                                /*BB*/
02854 #endif
02855 #ifdef BB
02856     (settings->BB_current + settings->BB_origin_offset);     /*BB*/
02857 #endif
02858 #ifdef CC
02859   settings->CC_current SET_TO                                /*CC*/
02860 #endif
02861 #ifdef CC
02862     (settings->CC_current + settings->CC_origin_offset);     /*CC*/
02863 #endif
02864 
02865   x SET_TO parameters[5201 + (origin * 20)];
02866   y SET_TO parameters[5202 + (origin * 20)];
02867   z SET_TO parameters[5203 + (origin * 20)];
02868 #ifdef AA
02869   a SET_TO parameters[5204 + (origin * 20)]; /*AA*/
02870 #endif
02871 #ifdef BB
02872   b SET_TO parameters[5205 + (origin * 20)]; /*BB*/
02873 #endif
02874 #ifdef CC
02875   c SET_TO parameters[5206 + (origin * 20)]; /*CC*/
02876 #endif
02877 
02878   settings->origin_offset_x SET_TO x;
02879   settings->origin_offset_y SET_TO y;
02880   settings->origin_offset_z SET_TO z;
02881 #ifdef AA
02882   settings->AA_origin_offset SET_TO a;                       /*AA*/
02883 #endif
02884 #ifdef BB
02885   settings->BB_origin_offset SET_TO b;                       /*BB*/
02886 #endif
02887 #ifdef CC
02888   settings->CC_origin_offset SET_TO c;                       /*CC*/
02889 #endif
02890 
02891   settings->current_x SET_TO (settings->current_x - x);
02892   settings->current_y SET_TO (settings->current_y - y);
02893   settings->current_z SET_TO (settings->current_z - z);
02894 #ifdef AA
02895   settings->AA_current SET_TO (settings->AA_current - a);    /*AA*/
02896 #endif
02897 #ifdef BB
02898   settings->BB_current SET_TO (settings->BB_current - b);    /*BB*/
02899 #endif
02900 #ifdef CC
02901   settings->CC_current SET_TO (settings->CC_current - c);    /*CC*/
02902 #endif
02903 
02904   SET_ORIGIN_OFFSETS(x + settings->axis_offset_x,
02905                      y + settings->axis_offset_y,
02906                      z + settings->axis_offset_z
02907 #ifdef AA
02908 ,                    a + settings->AA_axis_offset
02909 #else
02910 #ifdef ALL_AXES
02911 , 0
02912 #endif
02913 #endif
02914 #ifdef BB
02915 ,                    b + settings->BB_axis_offset
02916 #else
02917 #ifdef ALL_AXES
02918 , 0
02919 #endif
02920 #endif
02921 #ifdef CC
02922 ,                    c + settings->CC_axis_offset
02923 #else
02924 #ifdef ALL_AXES
02925 , 0
02926 #endif
02927 #endif
02928 );
02929   return RS274NGC_OK;
02930 }
02931 
02932 /****************************************************************************/
02933 
02934 /* convert_cutter_compensation
02935 
02936 Returned Value: int
02937    If convert_cutter_compensation_on or convert_cutter_compensation_off
02938       is called and returns an error code, this returns that code.
02939    If any of the following errors occur, this returns the error shown.
02940    Otherwise, it returns RS274NGC_OK.
02941    1. g_code is not G_40, G_41, or G_42:
02942       NCE_BUG_CODE_NOT_G40_G41_OR_G42
02943 
02944 Side effects:
02945    The value of cutter_comp_side in the machine model mode is
02946    set to RIGHT, LEFT, or OFF. The currently active tool table index in
02947    the machine model (which is the index of the slot whose diameter
02948    value is used in cutter radius compensation) is updated.
02949 
02950 Since cutter radius compensation is performed in the interpreter, no
02951 call is made to any canonical function regarding cutter radius compensation.
02952 
02953 Called by: convert_g
02954 
02955 */
02956 
02957 static int convert_cutter_compensation( /* ARGUMENTS                  */
02958  int g_code,              /* must be G_40, G_41, or G_42              */
02959  block_pointer block,     /* pointer to a block of RS274 instructions */
02960  setup_pointer settings)  /* pointer to machine settings              */
02961 {
02962   static char name[] SET_TO "convert_cutter_compensation";
02963   int status;
02964 
02965   if (g_code IS G_40)
02966     {
02967       CHP(convert_cutter_compensation_off(settings));
02968     }
02969   else if (g_code IS G_41)
02970     {
02971       CHP(convert_cutter_compensation_on(LEFT, block, settings));
02972     }
02973   else if (g_code IS G_42)
02974     {
02975       CHP(convert_cutter_compensation_on(RIGHT, block, settings));
02976     }
02977   else
02978     ERM(NCE_BUG_CODE_NOT_G40_G41_OR_G42);
02979 
02980   return RS274NGC_OK;
02981 }
02982 
02983 /****************************************************************************/
02984 
02985 /* convert_cutter_compensation_off
02986 
02987 Returned Value: int (RS274NGC_OK)
02988 
02989 Side effects:
02990    A comment is made that cutter radius compensation is turned off.
02991    The machine model of the cutter radius compensation mode is set to OFF.
02992    The value of program_x in the machine model is set to UNKNOWN.
02993      This serves as a flag when cutter radius compensation is
02994      turned on again.
02995 
02996 Called by: convert_cutter_compensation
02997 
02998 */
02999 
03000 static int convert_cutter_compensation_off( /* ARGUMENTS                   */
03001  setup_pointer settings)                    /* pointer to machine settings */
03002 {
03003 #ifdef DEBUG_EMC
03004   COMMENT("interpreter: cutter radius compensation off");
03005 #endif
03006   settings->cutter_comp_side SET_TO OFF;
03007   settings->program_x SET_TO UNKNOWN;
03008   return RS274NGC_OK;
03009 }
03010 
03011 /****************************************************************************/
03012 
03013 /* convert_cutter_compensation_on
03014 
03015 Returned Value: int
03016    If any of the following errors occur, this returns the error code shown.
03017    Otherwise, it returns RS274NGC_OK.
03018    1. The selected plane is not the XY plane:
03019       NCE_CANNOT_TURN_CUTTER_RADIUS_COMP_ON_OUT_OF_XY_PLANE
03020    2. Cutter radius compensation is already on:
03021       NCE_CANNOT_TURN_CUTTER_RADIUS_COMP_ON_WHEN_ON
03022 
03023 Side effects:
03024    A COMMENT function call is made (conditionally) saying that the
03025    interpreter is switching mode so that cutter radius compensation is on.
03026    The value of cutter_comp_radius in the machine model mode is
03027    set to the absolute value of the radius given in the tool table.
03028    The value of cutter_comp_side in the machine model mode is
03029    set to RIGHT or LEFT. The currently active tool table index in
03030    the machine model is updated.
03031 
03032 Called by: convert_cutter_compensation
03033 
03034 check_other_codes checks that a d word occurs only in a block with g41
03035 or g42.
03036 
03037 Cutter radius compensation is carried out in the interpreter, so no
03038 call is made to a canonical function (although there is a canonical
03039 function, START_CUTTER_RADIUS_COMPENSATION, that could be called if
03040 the primitive level could execute it).
03041 
03042 This version uses a D word if there is one in the block, but it does
03043 not require a D word, since the sample programs which the interpreter
03044 is supposed to handle do not have them.  Logically, the D word is
03045 optional, since the D word is always (except in cases we have never
03046 heard of) the slot number of the tool in the spindle. Not requiring a
03047 D word is contrary to [Fanuc, page 116] and [NCMS, page 79], however.
03048 Both manuals require the use of the D-word with G41 and G42.
03049 
03050 This version handles a negative offset radius, which may be
03051 encountered if the programmed tool path is a center line path for
03052 cutting a profile and the path was constructed using a nominal tool
03053 diameter. Then the value in the tool table for the diameter is set to
03054 be the difference between the actual diameter and the nominal
03055 diameter. If the actual diameter is less than the nominal, the value
03056 in the table is negative. The method of handling a negative radius is
03057 to switch the side of the offset and use a positive radius. This
03058 requires that the profile use arcs (not straight lines) to go around
03059 convex corners.
03060 
03061 */
03062 
03063 static int convert_cutter_compensation_on( /* ARGUMENTS               */
03064  int side,               /* side of path cutter is on (LEFT or RIGHT) */
03065  block_pointer block,    /* pointer to a block of RS274 instructions  */
03066  setup_pointer settings) /* pointer to machine settings               */
03067 {
03068   static char name[] SET_TO "convert_cutter_compensation_on";
03069   double radius;
03070   int index;
03071 
03072   CHK((settings->plane ISNT CANON_PLANE_XY),
03073       NCE_CANNOT_TURN_CUTTER_RADIUS_COMP_ON_OUT_OF_XY_PLANE);
03074   CHK((settings->cutter_comp_side ISNT OFF),
03075       NCE_CANNOT_TURN_CUTTER_RADIUS_COMP_ON_WHEN_ON);
03076   index SET_TO
03077     (block->d_number ISNT -1) ? block->d_number : settings->current_slot;
03078   radius SET_TO ((settings->tool_table[index].diameter)/2.0);
03079 
03080   if (radius < 0.0) /* switch side & make radius positive if radius negative */
03081     {
03082       radius SET_TO -radius;
03083       if (side IS RIGHT)
03084         side SET_TO LEFT;
03085       else
03086         side SET_TO RIGHT;
03087     }
03088 
03089 #ifdef DEBUG_EMC
03090   if (side IS RIGHT)
03091     COMMENT("interpreter: cutter radius compensation on right");
03092   else
03093     COMMENT("interpreter: cutter radius compensation on left");
03094 #endif
03095 
03096   settings->cutter_comp_radius SET_TO radius;
03097   settings->tool_table_index SET_TO index;
03098   settings->cutter_comp_side SET_TO side;
03099   return RS274NGC_OK;
03100 }
03101 
03102 /****************************************************************************/
03103 
03104 /* convert_cycle
03105 
03106 Returned Value: int
03107    If any of the specific functions called returns an error code,
03108    this returns that code.
03109    If any of the following errors occur, this returns the error code shown.
03110    Otherwise, it returns RS274NGC_OK.
03111    1. The r-value is not given the first time this code is called after
03112       some other motion mode has been in effect:
03113       NCE_R_CLEARANCE_PLANE_UNSPECIFIED_IN_CYCLE
03114    2. The l number is zero: NCE_CANNOT_DO_ZERO_REPEATS_OF_CYCLE
03115    3. The currently selected plane in not XY, YZ, or XZ.
03116       NCE_BUG_PLANE_NOT_XY_YZ_OR_XZ
03117 
03118 Side effects:
03119    A number of moves are made to execute a canned cycle. The current
03120    position is reset. The values of the cycle attributes in the settings
03121    may be reset.
03122 
03123 Called by: convert_motion
03124 
03125 This function makes a couple checks and then calls one of three
03126 functions, according to which plane is currently selected.
03127 
03128 See the documentation of convert_cycle_xy for most of the details.
03129 
03130 */
03131 
03132 static int convert_cycle( /* ARGUMENTS                                      */
03133  int motion,              /* a g-code between G_81 and G_89, a canned cycle */
03134  block_pointer block,     /* pointer to a block of RS274 instructions       */
03135  setup_pointer settings)  /* pointer to machine settings                    */
03136 {
03137   static char name[] SET_TO "convert_cycle";
03138   CANON_PLANE plane;
03139   int status;
03140 
03141   plane SET_TO settings->plane;
03142   if (block->r_flag IS OFF)
03143     {
03144       if (settings->motion_mode IS motion)
03145         block->r_number SET_TO settings->cycle_r;
03146       else
03147         ERM(NCE_R_CLEARANCE_PLANE_UNSPECIFIED_IN_CYCLE);
03148     }
03149 
03150   CHK((block->l_number IS 0), NCE_CANNOT_DO_ZERO_REPEATS_OF_CYCLE);
03151   if (block->l_number IS -1)
03152     block->l_number SET_TO 1;
03153 
03154   if (plane IS CANON_PLANE_XY)
03155     {
03156       CHP(convert_cycle_xy(motion, block, settings));
03157     }
03158   else if (plane IS CANON_PLANE_YZ)
03159     {
03160       CHP(convert_cycle_yz(motion, block, settings));
03161     }
03162   else if (plane IS CANON_PLANE_XZ)
03163     {
03164       CHP(convert_cycle_zx(motion, block, settings));
03165     }
03166   else
03167     ERM(NCE_BUG_PLANE_NOT_XY_YZ_OR_XZ);
03168 
03169   settings->cycle_l SET_TO block->l_number;
03170   settings->cycle_r SET_TO block->r_number;
03171   settings->motion_mode SET_TO motion;
03172   return RS274NGC_OK;
03173 }
03174 
03175 /****************************************************************************/
03176 
03177 /* convert_cycle_g81
03178 
03179 Returned Value: int (RS274NGC_OK)
03180 
03181 Side effects: See below
03182 
03183 Called by:
03184    convert_cycle_xy
03185    convert_cycle_yz
03186    convert_cycle_zx
03187 
03188 For the XY plane, this implements the following RS274/NGC cycle, which
03189 is usually drilling:
03190 1. Move the z-axis only at the current feed rate to the specified bottom_z.
03191 2. Retract the z-axis at traverse rate to clear_z.
03192 
03193 See [NCMS, page 99].
03194 
03195 CYCLE_MACRO has positioned the tool at (x, y, r, a, b, c) when this starts.
03196 
03197 For the XZ and YZ planes, this makes analogous motions.
03198 
03199 */
03200 
03201 static int convert_cycle_g81( /* ARGUMENTS                        */
03202  CANON_PLANE plane,           /* selected plane                   */
03203  double x,                    /* x-value where cycle is executed  */
03204  double y,                    /* y-value where cycle is executed  */
03205  double clear_z,              /* z-value of clearance plane       */
03206  double bottom_z)             /* value of z at bottom of cycle    */
03207 {
03208   static char name[] SET_TO "convert_cycle_g81";
03209 
03210   cycle_feed(plane, x, y, bottom_z);
03211   cycle_traverse(plane, x, y, clear_z);
03212 
03213   return RS274NGC_OK;
03214 }
03215 
03216 /****************************************************************************/
03217 
03218 /* convert_cycle_g82
03219 
03220 Returned Value: int (RS274NGC_OK)
03221 
03222 Side effects: See below
03223 
03224 Called by:
03225    convert_cycle_xy
03226    convert_cycle_yz
03227    convert_cycle_zx
03228 
03229 For the XY plane, this implements the following RS274/NGC cycle, which
03230 is usually drilling:
03231 1. Move the z_axis only at the current feed rate to the specified z-value.
03232 2. Dwell for the given number of seconds.
03233 3. Retract the z-axis at traverse rate to the clear_z.
03234 
03235 CYCLE_MACRO has positioned the tool at (x, y, r, a, b, c) when this starts.
03236 
03237 For the XZ and YZ planes, this makes analogous motions.
03238 
03239 */
03240 
03241 static int convert_cycle_g82( /* ARGUMENTS                        */
03242  CANON_PLANE plane,           /* selected plane                   */
03243  double x,                    /* x-value where cycle is executed  */
03244  double y,                    /* y-value where cycle is executed  */
03245  double clear_z,              /* z-value of clearance plane       */
03246  double bottom_z,             /* value of z at bottom of cycle    */
03247  double dwell)                /* dwell time                       */
03248 {
03249   static char name[] SET_TO "convert_cycle_g82";
03250 
03251   cycle_feed(plane, x, y, bottom_z);
03252   DWELL(dwell);
03253   cycle_traverse(plane, x, y, clear_z);
03254 
03255   return RS274NGC_OK;
03256 }
03257 
03258 /****************************************************************************/
03259 
03260 /* convert_cycle_g83
03261 
03262 Returned Value: int (RS274NGC_OK)
03263 
03264 Side effects: See below
03265 
03266 Called by:
03267    convert_cycle_xy
03268    convert_cycle_yz
03269    convert_cycle_zx
03270 
03271 For the XY plane, this implements the following RS274/NGC cycle,
03272 which is usually peck drilling:
03273 1. Move the z-axis only at the current feed rate downward by delta or
03274    to the specified bottom_z, whichever is less deep.
03275 2. Rapid back out to the clear_z.
03276 3. Rapid back down to the current hole bottom, backed off a bit.
03277 4. Repeat steps 1, 2, and 3 until the specified bottom_z is reached.
03278 5. Retract the z-axis at traverse rate to clear_z.
03279 
03280 CYCLE_MACRO has positioned the tool at (x, y, r, a, b, c) when this starts.
03281 
03282 The rapid out and back in causes any long stringers (which are common
03283 when drilling in aluminum) to be cut off and clears chips from the
03284 hole.
03285 
03286 For the XZ and YZ planes, this makes analogous motions.
03287 
03288 */
03289 
03290 #define G83_RAPID_DELTA 0.010   /* how far above hole bottom for rapid
03291                                    return, in inches */
03292 
03293 static int convert_cycle_g83( /* ARGUMENTS                        */
03294  CANON_PLANE plane,           /* selected plane                   */
03295  double x,                    /* x-value where cycle is executed  */
03296  double y,                    /* y-value where cycle is executed  */
03297  double r,                    /* initial z-value                  */
03298  double clear_z,              /* z-value of clearance plane       */
03299  double bottom_z,             /* value of z at bottom of cycle    */
03300  double delta)                /* size of z-axis feed increment    */
03301 {
03302   static char name[] SET_TO "convert_cycle_g83";
03303   double current_depth;
03304   double rapid_delta;
03305 
03306   rapid_delta SET_TO G83_RAPID_DELTA;
03307   if (_setup.length_units IS CANON_UNITS_MM)
03308     rapid_delta SET_TO (rapid_delta * 25.4);
03309 
03310   for (current_depth SET_TO (r - delta);
03311        current_depth > bottom_z;
03312        current_depth SET_TO (current_depth - delta))
03313     {
03314       cycle_feed(plane, x, y, current_depth);
03315       cycle_traverse(plane, x, y, clear_z);
03316       cycle_traverse(plane, x, y, current_depth + rapid_delta);
03317     }
03318   cycle_feed(plane, x, y, bottom_z);
03319   cycle_traverse(plane, x, y, clear_z);
03320 
03321   return RS274NGC_OK;
03322 }
03323 
03324 /****************************************************************************/
03325 
03326 /* convert_cycle_g84
03327 
03328 Returned Value: int
03329    If the spindle is not turning clockwise, this returns
03330      NCE_SPINDLE_NOT_TURNING_CLOCKWISE_IN_G84.
03331    Otherwise, it returns RS274NGC_OK.
03332 
03333 Side effects: See below
03334 
03335 Called by:
03336    convert_cycle_xy
03337    convert_cycle_yz
03338    convert_cycle_zx
03339 
03340 For the XY plane, this implements the following RS274/NGC cycle,
03341 which is right-hand tapping:
03342 1. Start speed-feed synchronization.
03343 2. Move the z-axis only at the current feed rate to the specified bottom_z.
03344 3. Stop the spindle.
03345 4. Start the spindle counterclockwise.
03346 5. Retract the z-axis at current feed rate to clear_z.
03347 6. If speed-feed synch was not on before the cycle started, stop it.
03348 7. Stop the spindle.
03349 8. Start the spindle clockwise.
03350 
03351 CYCLE_MACRO has positioned the tool at (x, y, r, a, b, c) when this starts.
03352 The direction argument must be clockwise.
03353 
03354 For the XZ and YZ planes, this makes analogous motions.
03355 
03356 */
03357 
03358 static int convert_cycle_g84( /* ARGUMENTS                           */
03359  CANON_PLANE plane,           /* selected plane                      */
03360  double x,                    /* x-value where cycle is executed     */
03361  double y,                    /* y-value where cycle is executed     */
03362  double clear_z,              /* z-value of clearance plane          */
03363  double bottom_z,             /* value of z at bottom of cycle       */
03364  CANON_DIRECTION direction,   /* direction spindle turning at outset */
03365  CANON_SPEED_FEED_MODE mode)  /* the speed-feed mode at outset       */
03366 {
03367   static char name[] SET_TO "convert_cycle_g84";
03368 
03369   CHK((direction ISNT CANON_CLOCKWISE),
03370       NCE_SPINDLE_NOT_TURNING_CLOCKWISE_IN_G84);
03371   START_SPEED_FEED_SYNCH();
03372   cycle_feed(plane, x, y, bottom_z);
03373   STOP_SPINDLE_TURNING();
03374   START_SPINDLE_COUNTERCLOCKWISE();
03375   cycle_feed(plane, x, y, clear_z);
03376   if (mode ISNT CANON_SYNCHED)
03377     STOP_SPEED_FEED_SYNCH();
03378   STOP_SPINDLE_TURNING();
03379   START_SPINDLE_CLOCKWISE();
03380 
03381   return RS274NGC_OK;
03382 }
03383 
03384 /****************************************************************************/
03385 
03386 /* convert_cycle_g85
03387 
03388 Returned Value: int (RS274NGC_OK)
03389 
03390 Side effects:
03391    A number of moves are made as described below.
03392 
03393 Called by:
03394    convert_cycle_xy
03395    convert_cycle_yz
03396    convert_cycle_zx
03397 
03398 For the XY plane, this implements the following RS274/NGC cycle,
03399 which is usually boring or reaming:
03400 1. Move the z-axis only at the current feed rate to the specified z-value.
03401 2. Retract the z-axis at the current feed rate to clear_z.
03402 
03403 CYCLE_MACRO has positioned the tool at (x, y, r, ?, ?) when this starts.
03404 
03405 For the XZ and YZ planes, this makes analogous motions.
03406 
03407 */
03408 
03409 static int convert_cycle_g85( /* ARGUMENTS                        */
03410  CANON_PLANE plane,           /* selected plane                   */
03411  double x,                    /* x-value where cycle is executed  */
03412  double y,                    /* y-value where cycle is executed  */
03413  double clear_z,              /* z-value of clearance plane       */
03414  double bottom_z)             /* value of z at bottom of cycle    */
03415 {
03416   static char name[] SET_TO "convert_cycle_g85";
03417 
03418   cycle_feed(plane, x, y, bottom_z);
03419   cycle_feed(plane, x, y, clear_z);
03420 
03421   return RS274NGC_OK;
03422 }
03423 
03424 /****************************************************************************/
03425 
03426 /* convert_cycle_g86
03427 
03428 Returned Value: int
03429    If the spindle is not turning clockwise or counterclockwise,
03430    this returns NCE_SPINDLE_NOT_TURNING_IN_G86.
03431    Otherwise, it returns RS274NGC_OK.
03432 
03433 Side effects:
03434    A number of moves are made as described below.
03435 
03436 Called by:
03437    convert_cycle_xy
03438    convert_cycle_yz
03439    convert_cycle_zx
03440 
03441 For the XY plane, this implements the RS274/NGC following cycle,
03442 which is usually boring:
03443 1. Move the z-axis only at the current feed rate to bottom_z.
03444 2. Dwell for the given number of seconds.
03445 3. Stop the spindle turning.
03446 4. Retract the z-axis at traverse rate to clear_z.
03447 5. Restart the spindle in the direction it was going.
03448 
03449 CYCLE_MACRO has positioned the tool at (x, y, r, a, b, c) when this starts.
03450 
03451 For the XZ and YZ planes, this makes analogous motions.
03452 
03453 */
03454 
03455 static int convert_cycle_g86( /* ARGUMENTS                           */
03456  CANON_PLANE plane,           /* selected plane                      */
03457  double x,                    /* x-value where cycle is executed     */
03458  double y,                    /* y-value where cycle is executed     */
03459  double clear_z,              /* z-value of clearance plane          */
03460  double bottom_z,             /* value of z at bottom of cycle       */
03461  double dwell,                /* dwell time                          */
03462  CANON_DIRECTION direction)   /* direction spindle turning at outset */
03463 {
03464   static char name[] SET_TO "convert_cycle_g86";
03465 
03466   CHK(((direction ISNT CANON_CLOCKWISE) AND
03467        (direction ISNT CANON_COUNTERCLOCKWISE)),
03468       NCE_SPINDLE_NOT_TURNING_IN_G86);
03469 
03470   cycle_feed(plane, x, y, bottom_z);
03471   DWELL(dwell);
03472   STOP_SPINDLE_TURNING();
03473   cycle_traverse(plane, x, y, clear_z);
03474   if (direction IS CANON_CLOCKWISE)
03475     START_SPINDLE_CLOCKWISE();
03476   else
03477     START_SPINDLE_COUNTERCLOCKWISE();
03478 
03479   return RS274NGC_OK;
03480 }
03481 
03482 /****************************************************************************/
03483 
03484 /* convert_cycle_g87
03485 
03486 Returned Value: int
03487    If the spindle is not turning clockwise or counterclockwise,
03488    this returns NCE_SPINDLE_NOT_TURNING_IN_G87.
03489    Otherwise, it returns RS274NGC_OK.
03490 
03491 Side effects:
03492    A number of moves are made as described below. This cycle is a
03493    modified version of [Monarch, page 5-24] since [NCMS, pages 98 - 100]
03494    gives no clue as to what the cycle is supposed to do. [KT] does not
03495    have a back boring cycle. [Fanuc, page 132] in "Canned cycle II"
03496    describes the G87 cycle as given here, except that the direction of
03497    spindle turning is always clockwise and step 7 below is omitted
03498    in [Fanuc].
03499 
03500 Called by:
03501    convert_cycle_xy
03502    convert_cycle_yz
03503    convert_cycle_zx
03504 
03505 For the XY plane, this implements the following RS274/NGC cycle, which
03506 is usually back boring.  The situation is that you have a through hole
03507 and you want to counterbore the bottom of hole. To do this you put an
03508 L-shaped tool in the spindle with a cutting surface on the UPPER side
03509 of its base. You stick it carefully through the hole when it is not
03510 spinning and is oriented so it fits through the hole, then you move it
03511 so the stem of the L is on the axis of the hole, start the spindle,
03512 and feed the tool upward to make the counterbore. Then you get the
03513 tool out of the hole.
03514 
03515 1. Move at traverse rate parallel to the XY-plane to the point
03516    with x-value offset_x and y-value offset_y.
03517 2. Stop the spindle in a specific orientation.
03518 3. Move the z-axis only at traverse rate downward to the bottom_z.
03519 4. Move at traverse rate parallel to the XY-plane to the x,y location.
03520 5. Start the spindle in the direction it was going before.
03521 6. Move the z-axis only at the given feed rate upward to the middle_z.
03522 7. Move the z-axis only at the given feed rate back down to bottom_z.
03523 8. Stop the spindle in the same orientation as before.
03524 9. Move at traverse rate parallel to the XY-plane to the point
03525    with x-value offset_x and y-value offset_y.
03526 10. Move the z-axis only at traverse rate to the clear z value.
03527 11. Move at traverse rate parallel to the XY-plane to the specified x,y
03528     location.
03529 12. Restart the spindle in the direction it was going before.
03530 
03531 CYCLE_MACRO has positioned the tool at (x, y, r, a, b, c) before this starts.
03532 
03533 It might be useful to add a check that clear_z > middle_z > bottom_z.
03534 Without the check, however, this can be used to counterbore a hole in
03535 material that can only be accessed through a hole in material above it.
03536 
03537 For the XZ and YZ planes, this makes analogous motions.
03538 
03539 */
03540 
03541 static int convert_cycle_g87( /* ARGUMENTS                           */
03542  CANON_PLANE plane,           /* selected plane                      */
03543  double x,                    /* x-value where cycle is executed     */
03544  double offset_x,             /* x-axis offset position              */
03545  double y,                    /* y-value where cycle is executed     */
03546  double offset_y,             /* y-axis offset position              */
03547  double r,                    /* z_value of r_plane                  */
03548  double clear_z,              /* z-value of clearance plane          */
03549  double middle_z,             /* z-value of top of back bore         */
03550  double bottom_z,             /* value of z at bottom of cycle       */
03551  CANON_DIRECTION direction)   /* direction spindle turning at outset */
03552 {
03553   static char name[] SET_TO "convert_cycle_g87";
03554 
03555   CHK(((direction ISNT CANON_CLOCKWISE) AND
03556        (direction ISNT CANON_COUNTERCLOCKWISE)),
03557       NCE_SPINDLE_NOT_TURNING_IN_G87);
03558 
03559   cycle_traverse(plane, offset_x, offset_y, r);
03560   STOP_SPINDLE_TURNING();
03561   ORIENT_SPINDLE(0.0, direction);
03562   cycle_traverse(plane, offset_x, offset_y, bottom_z);
03563   cycle_traverse(plane, x, y, bottom_z);
03564   if (direction IS CANON_CLOCKWISE)
03565     START_SPINDLE_CLOCKWISE();
03566   else
03567     START_SPINDLE_COUNTERCLOCKWISE();
03568   cycle_feed(plane, x, y, middle_z);
03569   cycle_feed(plane, x, y, bottom_z);
03570   STOP_SPINDLE_TURNING();
03571   ORIENT_SPINDLE(0.0, direction);
03572   cycle_traverse(plane, offset_x, offset_y, bottom_z);
03573   cycle_traverse(plane, offset_x, offset_y, clear_z);
03574   cycle_traverse(plane, x, y, clear_z);
03575   if (direction IS CANON_CLOCKWISE)
03576     START_SPINDLE_CLOCKWISE();
03577   else
03578     START_SPINDLE_COUNTERCLOCKWISE();
03579 
03580   return RS274NGC_OK;
03581 }
03582 
03583 /****************************************************************************/
03584 
03585 /* convert_cycle_g88
03586 
03587 Returned Value: int
03588    If the spindle is not turning clockwise or counterclockwise, this
03589    returns NCE_SPINDLE_NOT_TURNING_IN_G88.
03590    Otherwise, it returns RS274NGC_OK.
03591 
03592 Side effects: See below
03593 
03594 Called by:
03595    convert_cycle_xy
03596    convert_cycle_yz
03597    convert_cycle_zx
03598 
03599 For the XY plane, this implements the following RS274/NGC cycle,
03600 which is usually boring:
03601 1. Move the z-axis only at the current feed rate to the specified z-value.
03602 2. Dwell for the given number of seconds.
03603 3. Stop the spindle turning.
03604 4. Stop the program so the operator can retract the spindle manually.
03605 5. Restart the spindle.
03606 
03607 CYCLE_MACRO has positioned the tool at (x, y, r, a, b, c) when this starts.
03608 
03609 For the XZ and YZ planes, this makes analogous motions.
03610 
03611 */
03612 
03613 static int convert_cycle_g88( /* ARGUMENTS                           */
03614  CANON_PLANE plane,           /* selected plane                      */
03615  double x,                    /* x-value where cycle is executed     */
03616  double y,                    /* y-value where cycle is executed     */
03617  double bottom_z,             /* value of z at bottom of cycle       */
03618  double dwell,                /* dwell time                          */
03619  CANON_DIRECTION direction)   /* direction spindle turning at outset */
03620 {
03621   static char name[] SET_TO "convert_cycle_g88";
03622 
03623   CHK(((direction ISNT CANON_CLOCKWISE) AND
03624        (direction ISNT CANON_COUNTERCLOCKWISE)),
03625       NCE_SPINDLE_NOT_TURNING_IN_G88);
03626 
03627   cycle_feed(plane, x, y, bottom_z);
03628   DWELL(dwell);
03629   STOP_SPINDLE_TURNING();
03630   PROGRAM_STOP(); /* operator retracts the spindle here */
03631   if (direction IS CANON_CLOCKWISE)
03632     START_SPINDLE_CLOCKWISE();
03633   else
03634     START_SPINDLE_COUNTERCLOCKWISE();
03635 
03636   return RS274NGC_OK;
03637 }
03638 
03639 /****************************************************************************/
03640 
03641 /* convert_cycle_g89
03642 
03643 Returned Value: int (RS274NGC_OK)
03644 
03645 Side effects: See below
03646 
03647 Called by:
03648    convert_cycle_xy
03649    convert_cycle_yz
03650    convert_cycle_zx
03651 
03652 This implements the following RS274/NGC cycle, which is intended for boring:
03653 1. Move the z-axis only at the current feed rate to the specified z-value.
03654 2. Dwell for the given number of seconds.
03655 3. Retract the z-axis at the current feed rate to clear_z.
03656 
03657 CYCLE_MACRO has positioned the tool at (x, y, r, a, b, c) when this starts.
03658 
03659 For the XZ and YZ planes, this makes analogous motions.
03660 
03661 */
03662 
03663 static int convert_cycle_g89( /* ARGUMENTS                        */
03664  CANON_PLANE plane,           /* selected plane                   */
03665  double x,                    /* x-value where cycle is executed  */
03666  double y,                    /* y-value where cycle is executed  */
03667  double clear_z,              /* z-value of clearance plane       */
03668  double bottom_z,             /* value of z at bottom of cycle    */
03669  double dwell)                /* dwell time                       */
03670 {
03671   static char name[] SET_TO "convert_cycle_g89";
03672 
03673   cycle_feed(plane, x, y, bottom_z);
03674   DWELL(dwell);
03675   cycle_feed(plane, x, y, clear_z);
03676 
03677   return RS274NGC_OK;
03678 }
03679 
03680 /****************************************************************************/
03681 
03682 /* convert_cycle_xy
03683 
03684 Returned Value: int
03685    If any of the specific functions called returns an error code,
03686    this returns that code.
03687    If any of the following errors occur, this returns the error code shown.
03688    Otherwise, it returns RS274NGC_OK.
03689    1. The z-value is not given the first time this code is called after
03690       some other motion mode has been in effect:
03691       NCE_Z_VALUE_UNSPECIFIED_IN_XY_PLANE_CANNED_CYCLE
03692    2. The r clearance plane is below the bottom_z:
03693       NCE_R_LESS_THAN_Z_IN_CYCLE_IN_XY_PLANE
03694    3. the distance mode is neither absolute or incremental:
03695       NCE_BUG_DISTANCE_MODE_NOT_G90_OR_G91
03696    4. G82, G86, G88, or G89 is called when it is not already in effect,
03697       and no p number is in the block:
03698       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G82
03699       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G86
03700       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G88
03701       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G89
03702    5. G83 is called when it is not already in effect,
03703       and no q number is in the block: NCE_Q_WORD_MISSING_WITH_G83
03704    6. G87 is called when it is not already in effect,
03705       and any of the i number, j number, or k number is missing:
03706       NCE_I_WORD_MISSING_WITH_G87
03707       NCE_J_WORD_MISSING_WITH_G87
03708       NCE_K_WORD_MISSING_WITH_G87
03709    7. the G code is not between G_81 and G_89.
03710       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
03711 
03712 Side effects:
03713    A number of moves are made to execute the g-code
03714 
03715 Called by: convert_cycle
03716 
03717 The function does not require that any of x,y,z, or r be specified in
03718 the block, except that if the last motion mode command executed was
03719 not the same as this one, the r-value and z-value must be specified.
03720 
03721 This function is handling the repeat feature of RS274/NGC, wherein
03722 the L word represents the number of repeats [NCMS, page 99]. We are
03723 not allowing L=0, contrary to the manual. We are allowing L > 1
03724 in absolute distance mode to mean "do the same thing in the same
03725 place several times", as provided in the manual, although this seems
03726 abnormal.
03727 
03728 In incremental distance mode, x, y, and r values are treated as
03729 increments to the current position and z as an increment from r.  In
03730 absolute distance mode, x, y, r, and z are absolute. In g87, i and j
03731 will always be increments, regardless of the distance mode setting, as
03732 implied in [NCMS, page 98], but k (z-value of top of counterbore) will
03733 be an absolute z-value in absolute distance mode, and an increment
03734 (from bottom z) in incremental distance mode.
03735 
03736 If the r position of a cycle is above the current_z position, this
03737 retracts the z-axis to the r position before moving parallel to the
03738 XY plane.
03739 
03740 In the code for this function, there is a nearly identical "for" loop
03741 in every case of the switch. The loop is the done with a compiler
03742 macro, "CYCLE_MACRO" so that the code is easy to read, automatically
03743 kept identical from case to case and, and much shorter than it would
03744 be without the macro. The loop could be put outside the switch, but
03745 then the switch would run every time around the loop, not just once,
03746 as it does here. The loop could also be placed in the called
03747 functions, but then it would not be clear that all the loops are the
03748 same, and it would be hard to keep them the same when the code is
03749 modified.  The macro would be very awkward as a regular function
03750 because it would have to be passed all of the arguments used by any of
03751 the specific cycles, and, if another switch in the function is to be
03752 avoided, it would have to passed a function pointer, but the different
03753 cycle functions have different arguments so the type of the pointer
03754 could not be declared unless the cycle functions were re-written to
03755 take the same arguments (in which case most of them would have several
03756 unused arguments).
03757 
03758 The motions within the CYCLE_MACRO (but outside a specific cycle) are
03759 a straight traverse parallel to the selected plane to the given
03760 position in the plane and a straight traverse of the third axis only
03761 (if needed) to the r position.
03762 
03763 The CYCLE_MACRO is defined here but is also used in convert_cycle_yz
03764 and convert_cycle_zx. The variables aa, bb, and cc are used in
03765 CYCLE_MACRO and in the other two functions just mentioned. Those
03766 variables represent the first axis of the selected plane, the second
03767 axis of the selected plane, and third axis which is perpendicular to
03768 the selected plane.  In this function aa represents x, bb represents
03769 y, and cc represents z. This usage makes it possible to have only one
03770 version of each of the cycle functions.  The cycle_traverse and
03771 cycle_feed functions help accomplish this.
03772 
03773 The height of the retract move at the end of each repeat of a cycle is
03774 determined by the setting of the retract_mode: either to the r
03775 position (if the retract_mode is R_PLANE) or to the original
03776 z-position (if that is above the r position and the retract_mode is
03777 not R_PLANE). This is a slight departure from [NCMS, page 98], which
03778 does not require checking that the original z-position is above r.
03779 
03780 The rotary axes may not move during a canned cycle.
03781 
03782 */
03783 
03784 #define CYCLE_MACRO(call) for (repeat SET_TO block->l_number; \
03785                                repeat > 0;                    \
03786                                repeat--)                      \
03787      {                                                        \
03788        aa SET_TO (aa + aa_increment);                         \
03789        bb SET_TO (bb + bb_increment);                         \
03790        cycle_traverse(plane, aa, bb, old_cc);                 \
03791        if (old_cc ISNT r)                                     \
03792          cycle_traverse(plane, aa, bb, r);                    \
03793        CHP(call);                                             \
03794        old_cc SET_TO clear_cc;                                \
03795      }
03796 
03797 static int convert_cycle_xy(  /* ARGUMENTS                                 */
03798  int motion,             /* a g-code between G_81 and G_89, a canned cycle */
03799  block_pointer block,    /* pointer to a block of RS274 instructions       */
03800  setup_pointer settings) /* pointer to machine settings                    */
03801 {
03802   static char name[] SET_TO "convert_cycle_xy";
03803   double aa;
03804   double aa_increment;
03805   double bb;
03806   double bb_increment;
03807   double cc;
03808   double clear_cc;
03809   double i;
03810   double j;
03811   double k;
03812   double old_cc;
03813   CANON_PLANE plane;
03814   double r;
03815   int repeat;
03816   CANON_MOTION_MODE save_mode;
03817   int status;
03818 
03819   plane SET_TO CANON_PLANE_XY;
03820   if (settings->motion_mode ISNT motion)
03821     {
03822       CHK((block->z_flag IS OFF),
03823           NCE_Z_VALUE_UNSPECIFIED_IN_XY_PLANE_CANNED_CYCLE);
03824     }
03825   block->z_number SET_TO
03826     block->z_flag IS ON ? block->z_number : settings->cycle_cc;
03827   old_cc SET_TO settings->current_z;
03828 
03829   if (settings->distance_mode IS MODE_ABSOLUTE)
03830     {
03831       aa_increment SET_TO 0.0;
03832       bb_increment SET_TO 0.0;
03833       r SET_TO block->r_number;
03834       cc SET_TO block->z_number;
03835       aa SET_TO block->x_flag IS ON ? block->x_number : settings->current_x;
03836       bb SET_TO block->y_flag IS ON ? block->y_number : settings->current_y;
03837     }
03838   else if (settings->distance_mode IS MODE_INCREMENTAL)
03839     {
03840       aa_increment SET_TO block->x_number;
03841       bb_increment SET_TO block->y_number;
03842       r SET_TO (block->r_number + old_cc);
03843       cc SET_TO (r + block->z_number); /* [NCMS, page 98] */
03844       aa SET_TO settings->current_x;
03845       bb SET_TO settings->current_y;
03846     }
03847   else
03848     ERM(NCE_BUG_DISTANCE_MODE_NOT_G90_OR_G91);
03849   CHK((r < cc), NCE_R_LESS_THAN_Z_IN_CYCLE_IN_XY_PLANE);
03850 
03851   if (old_cc < r)
03852     {
03853       STRAIGHT_TRAVERSE(settings->current_x, settings->current_y, r
03854 #ifdef AA
03855 ,         settings->AA_current
03856 #else
03857 #ifdef ALL_AXES
03858 , 0
03859 #endif
03860 #endif
03861 #ifdef BB
03862 ,  settings->BB_current
03863 #else
03864 #ifdef ALL_AXES
03865 , 0
03866 #endif
03867 #endif
03868 #ifdef CC
03869 ,  settings->CC_current
03870 #else
03871 #ifdef ALL_AXES
03872 , 0
03873 #endif
03874 #endif
03875 );
03876       old_cc SET_TO r;
03877     }
03878   clear_cc SET_TO (settings->retract_mode IS R_PLANE) ? r : old_cc;
03879 
03880   save_mode SET_TO GET_EXTERNAL_MOTION_CONTROL_MODE();
03881   if (save_mode ISNT CANON_EXACT_PATH)
03882     SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH);
03883 
03884   switch(motion)
03885     {
03886     case G_81:
03887       CYCLE_MACRO(convert_cycle_g81(CANON_PLANE_XY, aa, bb, clear_cc, cc))
03888       break;
03889     case G_82:
03890       CHK(((settings->motion_mode ISNT G_82) AND (block->p_number IS -1.0)),
03891           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G82);
03892       block->p_number SET_TO
03893         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
03894       CYCLE_MACRO(convert_cycle_g82 (CANON_PLANE_XY, aa, bb, clear_cc, cc,
03895                                      block->p_number))
03896       settings->cycle_p SET_TO block->p_number;
03897       break;
03898     case G_83:
03899       CHK(((settings->motion_mode ISNT G_83) AND (block->q_number IS -1.0)),
03900           NCE_Q_WORD_MISSING_WITH_G83);
03901       block->q_number SET_TO
03902         block->q_number IS -1.0 ? settings->cycle_q : block->q_number;
03903       CYCLE_MACRO(convert_cycle_g83 (CANON_PLANE_XY, aa, bb, r, clear_cc, cc,
03904                                      block->q_number))
03905       settings->cycle_q SET_TO block->q_number;
03906       break;
03907     case G_84:
03908       CYCLE_MACRO(convert_cycle_g84 (CANON_PLANE_XY, aa, bb, clear_cc, cc,
03909                       settings->spindle_turning, settings->speed_feed_mode))
03910       break;
03911     case G_85:
03912       CYCLE_MACRO(convert_cycle_g85 (CANON_PLANE_XY, aa, bb, clear_cc, cc))
03913       break;
03914     case G_86:
03915       CHK(((settings->motion_mode ISNT G_86) AND (block->p_number IS -1.0)),
03916           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G86);
03917       block->p_number SET_TO
03918         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
03919       CYCLE_MACRO(convert_cycle_g86 (CANON_PLANE_XY, aa, bb, clear_cc, cc,
03920                             block->p_number, settings->spindle_turning))
03921       settings->cycle_p SET_TO block->p_number;
03922       break;
03923     case G_87:
03924       if (settings->motion_mode ISNT G_87)
03925         {
03926           CHK((block->i_flag IS OFF), NCE_I_WORD_MISSING_WITH_G87);
03927           CHK((block->j_flag IS OFF), NCE_J_WORD_MISSING_WITH_G87);
03928           CHK((block->k_flag IS OFF), NCE_K_WORD_MISSING_WITH_G87);
03929         }
03930       i SET_TO block->i_flag IS ON ? block->i_number : settings->cycle_i;
03931       j SET_TO block->j_flag IS ON ? block->j_number : settings->cycle_j;
03932       k SET_TO block->k_flag IS ON ? block->k_number : settings->cycle_k;
03933       settings->cycle_i SET_TO i;
03934       settings->cycle_j SET_TO j;
03935       settings->cycle_k SET_TO k;
03936       if (settings->distance_mode IS MODE_INCREMENTAL)
03937         {
03938           k SET_TO (cc + k); /* k always absolute in function call below */
03939         }
03940       CYCLE_MACRO(convert_cycle_g87 (CANON_PLANE_XY, aa, (aa + i), bb,
03941                       (bb + j), r, clear_cc, k, cc, settings->spindle_turning))
03942       break;
03943     case G_88:
03944       CHK(((settings->motion_mode ISNT G_88) AND (block->p_number IS -1.0)),
03945           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G88);
03946       block->p_number SET_TO
03947         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
03948       CYCLE_MACRO(convert_cycle_g88 (CANON_PLANE_XY, aa, bb, cc,
03949                                 block->p_number, settings->spindle_turning))
03950       settings->cycle_p SET_TO block->p_number;
03951       break;
03952     case G_89:
03953       CHK(((settings->motion_mode ISNT G_89) AND (block->p_number IS -1.0)),
03954           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G89);
03955       block->p_number SET_TO
03956         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
03957       CYCLE_MACRO(convert_cycle_g89 (CANON_PLANE_XY, aa, bb, clear_cc, cc,
03958                                      block->p_number))
03959       settings->cycle_p SET_TO block->p_number;
03960       break;
03961     default:
03962       ERM(NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
03963     }
03964   settings->current_x SET_TO aa; /* CYCLE_MACRO updates aa and bb */
03965   settings->current_y SET_TO bb;
03966   settings->current_z SET_TO clear_cc;
03967   settings->cycle_cc SET_TO block->z_number;
03968 
03969   if (save_mode ISNT CANON_EXACT_PATH)
03970     SET_MOTION_CONTROL_MODE(save_mode);
03971 
03972   return RS274NGC_OK;
03973 }
03974 
03975 /****************************************************************************/
03976 
03977 /* convert_cycle_yz
03978 
03979 Returned Value: int
03980    If any of the specific functions called returns an error code,
03981    this returns that code.
03982    If any of the following errors occur, this returns the error code shown.
03983    Otherwise, it returns RS274NGC_OK.
03984    1. The x-value is not given the first time this code is called after
03985       some other motion mode has been in effect:
03986       NCE_X_VALUE_UNSPECIFIED_IN_YZ_PLANE_CANNED_CYCLE
03987    2. The r clearance plane is below the bottom_x:
03988       NCE_R_LESS_THAN_X_IN_CYCLE_IN_YZ_PLANE
03989    3. the distance mode is neither absolute or incremental:
03990       NCE_BUG_DISTANCE_MODE_NOT_G90_OR_G91
03991    4. G82, G86, G88, or G89 is called when it is not already in effect,
03992       and no p number is in the block:
03993       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G82
03994       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G86
03995       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G88
03996       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G89
03997    5. G83 is called when it is not already in effect,
03998       and no q number is in the block: NCE_Q_WORD_MISSING_WITH_G83
03999    6. G87 is called when it is not already in effect,
04000       and any of the i number, j number, or k number is missing:
04001       NCE_I_WORD_MISSING_WITH_G87
04002       NCE_J_WORD_MISSING_WITH_G87
04003       NCE_K_WORD_MISSING_WITH_G87
04004    7. the G code is not between G_81 and G_89.
04005       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
04006 
04007 Side effects:
04008    A number of moves are made to execute a canned cycle.
04009 
04010 Called by: convert_cycle
04011 
04012 See the documentation of convert_cycle_xy. This function is entirely
04013 similar. In this function aa represents y, bb represents z, and cc
04014 represents x.
04015 
04016 The CYCLE_MACRO is defined just before the convert_cycle_xy function.
04017 
04018 Tool length offsets work only when the tool axis is parallel to the
04019 Z-axis, so if this function is used, tool length offsets should be
04020 turned off, and the NC code written to take tool length into account.
04021 
04022 */
04023 
04024 static int convert_cycle_yz(  /* ARGUMENTS                                 */
04025  int motion,             /* a g-code between G_81 and G_89, a canned cycle */
04026  block_pointer block,    /* pointer to a block of RS274/NGC instructions   */
04027  setup_pointer settings) /* pointer to machine settings                    */
04028 {
04029   static char name[] SET_TO "convert_cycle_yz";
04030   double aa;
04031   double aa_increment;
04032   double bb;
04033   double bb_increment;
04034   double cc;
04035   double clear_cc;
04036   double i;
04037   double j;
04038   double k;
04039   double old_cc;
04040   CANON_PLANE plane;
04041   double r;
04042   int repeat;
04043   CANON_MOTION_MODE save_mode;
04044   int status;
04045 
04046   plane SET_TO CANON_PLANE_YZ;
04047   if (settings->motion_mode ISNT motion)
04048     {
04049       CHK((block->x_flag IS OFF),
04050           NCE_X_VALUE_UNSPECIFIED_IN_YZ_PLANE_CANNED_CYCLE);
04051     }
04052   block->x_number SET_TO
04053     block->x_flag IS ON ? block->x_number : settings->cycle_cc;
04054   old_cc SET_TO settings->current_x;
04055 
04056   if (settings->distance_mode IS MODE_ABSOLUTE)
04057     {
04058       aa_increment SET_TO 0.0;
04059       bb_increment SET_TO 0.0;
04060       r SET_TO block->r_number;
04061       cc SET_TO block->x_number;
04062       aa SET_TO block->y_flag IS ON ? block->y_number : settings->current_y;
04063       bb SET_TO block->z_flag IS ON ? block->z_number : settings->current_z;
04064     }
04065   else if (settings->distance_mode IS MODE_INCREMENTAL)
04066     {
04067       aa_increment SET_TO block->y_number;
04068       bb_increment SET_TO block->z_number;
04069       r SET_TO (block->r_number + old_cc);
04070       cc SET_TO (r + block->x_number); /* [NCMS, page 98] */
04071       aa SET_TO settings->current_y;
04072       bb SET_TO settings->current_z;
04073     }
04074   else
04075     ERM(NCE_BUG_DISTANCE_MODE_NOT_G90_OR_G91);
04076   CHK((r < cc), NCE_R_LESS_THAN_X_IN_CYCLE_IN_YZ_PLANE);
04077 
04078   if (old_cc < r)
04079     {
04080       STRAIGHT_TRAVERSE(r, settings->current_y, settings->current_z
04081 #ifdef AA
04082 ,          settings->AA_current
04083 #else
04084 #ifdef ALL_AXES
04085 , 0
04086 #endif
04087 #endif
04088 #ifdef BB
04089 ,  settings->BB_current
04090 #else
04091 #ifdef ALL_AXES
04092 , 0
04093 #endif
04094 #endif
04095 #ifdef CC
04096 ,  settings->CC_current
04097 #else
04098 #ifdef ALL_AXES
04099 , 0
04100 #endif
04101 #endif
04102 );
04103       old_cc SET_TO r;
04104     }
04105   clear_cc SET_TO (settings->retract_mode IS R_PLANE) ? r : old_cc;
04106 
04107   save_mode = GET_EXTERNAL_MOTION_CONTROL_MODE();
04108   if (save_mode ISNT CANON_EXACT_PATH)
04109     SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH);
04110 
04111   switch(motion)
04112     {
04113     case G_81:
04114       CYCLE_MACRO(convert_cycle_g81(CANON_PLANE_YZ, aa, bb, clear_cc, cc))
04115         break;
04116     case G_82:
04117       CHK(((settings->motion_mode ISNT G_82) AND (block->p_number IS -1.0)),
04118           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G82);
04119       block->p_number SET_TO
04120         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
04121       CYCLE_MACRO(convert_cycle_g82 (CANON_PLANE_YZ, aa, bb, clear_cc, cc,
04122                                      block->p_number))
04123       settings->cycle_p SET_TO block->p_number;
04124       break;
04125     case G_83:
04126       CHK(((settings->motion_mode ISNT G_83) AND (block->q_number IS -1.0)),
04127           NCE_Q_WORD_MISSING_WITH_G83);
04128       block->q_number SET_TO
04129         block->q_number IS -1.0 ? settings->cycle_q : block->q_number;
04130       CYCLE_MACRO(convert_cycle_g83 (CANON_PLANE_YZ, aa, bb, r, clear_cc, cc,
04131                                      block->q_number))
04132       settings->cycle_q SET_TO block->q_number;
04133       break;
04134     case G_84:
04135       CYCLE_MACRO(convert_cycle_g84 (CANON_PLANE_YZ, aa, bb, clear_cc, cc,
04136                       settings->spindle_turning, settings->speed_feed_mode))
04137       break;
04138     case G_85:
04139       CYCLE_MACRO(convert_cycle_g85 (CANON_PLANE_YZ, aa, bb, clear_cc, cc))
04140       break;
04141     case G_86:
04142       CHK(((settings->motion_mode ISNT G_86) AND (block->p_number IS -1.0)),
04143           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G86);
04144       block->p_number SET_TO
04145         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
04146       CYCLE_MACRO(convert_cycle_g86 (CANON_PLANE_YZ, aa, bb, clear_cc, cc,
04147                             block->p_number, settings->spindle_turning))
04148       settings->cycle_p SET_TO block->p_number;
04149       break;
04150     case G_87:
04151       if (settings->motion_mode ISNT G_87)
04152         {
04153           CHK((block->i_flag IS OFF), NCE_I_WORD_MISSING_WITH_G87);
04154           CHK((block->j_flag IS OFF), NCE_J_WORD_MISSING_WITH_G87);
04155           CHK((block->k_flag IS OFF), NCE_K_WORD_MISSING_WITH_G87);
04156         }
04157       i SET_TO block->i_flag IS ON ? block->i_number : settings->cycle_i;
04158       j SET_TO block->j_flag IS ON ? block->j_number : settings->cycle_j;
04159       k SET_TO block->k_flag IS ON ? block->k_number : settings->cycle_k;
04160       settings->cycle_i SET_TO i;
04161       settings->cycle_j SET_TO j;
04162       settings->cycle_k SET_TO k;
04163       if (settings->distance_mode IS MODE_INCREMENTAL)
04164         {
04165           i SET_TO (cc + i); /* i always absolute in function call below */
04166         }
04167       CYCLE_MACRO(convert_cycle_g87 (CANON_PLANE_YZ, aa, (aa + j), bb,
04168                       (bb + k), r, clear_cc, i, cc, settings->spindle_turning))
04169       break;
04170     case G_88:
04171       CHK(((settings->motion_mode ISNT G_88) AND (block->p_number IS -1.0)),
04172           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G88);
04173       block->p_number SET_TO
04174         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
04175       CYCLE_MACRO(convert_cycle_g88 (CANON_PLANE_YZ, aa, bb, cc,
04176                                 block->p_number, settings->spindle_turning))
04177       settings->cycle_p SET_TO block->p_number;
04178       break;
04179     case G_89:
04180       CHK(((settings->motion_mode ISNT G_89) AND (block->p_number IS -1.0)),
04181           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G89);
04182       block->p_number SET_TO
04183         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
04184       CYCLE_MACRO(convert_cycle_g89 (CANON_PLANE_YZ, aa, bb, clear_cc, cc,
04185                                      block->p_number))
04186       settings->cycle_p SET_TO block->p_number;
04187       break;
04188     default:
04189       ERM(NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
04190     }
04191   settings->current_y SET_TO aa; /* CYCLE_MACRO updates aa and bb */
04192   settings->current_z SET_TO bb;
04193   settings->current_x SET_TO clear_cc;
04194   settings->cycle_cc SET_TO block->x_number;
04195 
04196   if (save_mode ISNT CANON_EXACT_PATH)
04197     SET_MOTION_CONTROL_MODE(save_mode);
04198 
04199   return RS274NGC_OK;
04200 }
04201 
04202 /****************************************************************************/
04203 
04204 /* convert_cycle_zx
04205 
04206 Returned Value: int
04207    If any of the specific functions called returns an error code,
04208    this returns that code.
04209    If any of the following errors occur, this returns the ERROR code shown.
04210    Otherwise, it returns RS274NGC_OK.
04211    1. The y-value is not given the first time this code is called after
04212       some other motion mode has been in effect:
04213       NCE_Y_VALUE_UNSPECIFIED_IN_XZ_PLANE_CANNED_CYCLE
04214    2. The r clearance plane is below the bottom_y:
04215       NCE_R_LESS_THAN_Y_IN_CYCLE_IN_XZ_PLANE
04216    3. the distance mode is neither absolute or incremental:
04217       NCE_BUG_DISTANCE_MODE_NOT_G90_OR_G91
04218    4. G82, G86, G88, or G89 is called when it is not already in effect,
04219       and no p number is in the block:
04220       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G82
04221       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G86
04222       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G88
04223       NCE_DWELL_TIME_P_WORD_MISSING_WITH_G89
04224    5. G83 is called when it is not already in effect,
04225       and no q number is in the block: NCE_Q_WORD_MISSING_WITH_G83
04226    6. G87 is called when it is not already in effect,
04227       and any of the i number, j number, or k number is missing:
04228       NCE_I_WORD_MISSING_WITH_G87
04229       NCE_J_WORD_MISSING_WITH_G87
04230       NCE_K_WORD_MISSING_WITH_G87
04231    7. the G code is not between G_81 and G_89.
04232       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
04233 
04234 Side effects:
04235    A number of moves are made to execute a canned cycle.
04236 
04237 Called by: convert_cycle
04238 
04239 See the documentation of convert_cycle_xy. This function is entirely
04240 similar. In this function aa represents z, bb represents x, and cc
04241 represents y.
04242 
04243 The CYCLE_MACRO is defined just before the convert_cycle_xy function.
04244 
04245 Tool length offsets work only when the tool axis is parallel to the
04246 Z-axis, so if this function is used, tool length offsets should be
04247 turned off, and the NC code written to take tool length into account.
04248 
04249 It is a little distracting that this function uses zx in some places
04250 and xz in others; uniform use of zx would be nice, since that is the
04251 order for a right-handed coordinate system. Also with that usage,
04252 permutation of the symbols x, y, and z would allow for automatically
04253 converting the convert_cycle_xy function (or convert_cycle_yz) into
04254 the convert_cycle_xz function. However, the canonical interface uses
04255 CANON_PLANE_XZ.
04256 
04257 */
04258 
04259 static int convert_cycle_zx(  /* ARGUMENTS                                 */
04260  int motion,             /* a g-code between G_81 and G_89, a canned cycle */
04261  block_pointer block,    /* pointer to a block of RS274 instructions       */
04262  setup_pointer settings) /* pointer to machine settings                    */
04263 {
04264   static char name[] SET_TO "convert_cycle_zx";
04265   double aa;
04266   double aa_increment;
04267   double bb;
04268   double bb_increment;
04269   double cc;
04270   double clear_cc;
04271   double i;
04272   double j;
04273   double k;
04274   double old_cc;
04275   CANON_PLANE plane;
04276   double r;
04277   int repeat;
04278   CANON_MOTION_MODE save_mode;
04279   int status;
04280 
04281   plane SET_TO CANON_PLANE_XZ;
04282   if (settings->motion_mode ISNT motion)
04283     {
04284       CHK((block->y_flag IS OFF),
04285           NCE_Y_VALUE_UNSPECIFIED_IN_XZ_PLANE_CANNED_CYCLE);
04286     }
04287   block->y_number SET_TO
04288     block->y_flag IS ON ? block->y_number : settings->cycle_cc;
04289   old_cc SET_TO settings->current_y;
04290 
04291   if (settings->distance_mode IS MODE_ABSOLUTE)
04292     {
04293       aa_increment SET_TO 0.0;
04294       bb_increment SET_TO 0.0;
04295       r SET_TO block->r_number;
04296       cc SET_TO block->y_number;
04297       aa SET_TO block->z_flag IS ON ? block->z_number : settings->current_z;
04298       bb SET_TO block->x_flag IS ON ? block->x_number : settings->current_x;
04299     }
04300   else if (settings->distance_mode IS MODE_INCREMENTAL)
04301     {
04302       aa_increment SET_TO block->z_number;
04303       bb_increment SET_TO block->x_number;
04304       r SET_TO (block->r_number + old_cc);
04305       cc SET_TO (r + block->y_number); /* [NCMS, page 98] */
04306       aa SET_TO settings->current_z;
04307       bb SET_TO settings->current_x;
04308     }
04309   else
04310     ERM(NCE_BUG_DISTANCE_MODE_NOT_G90_OR_G91);
04311   CHK((r < cc), NCE_R_LESS_THAN_Y_IN_CYCLE_IN_XZ_PLANE);
04312 
04313   if (old_cc < r)
04314     {
04315       STRAIGHT_TRAVERSE(settings->current_x, r, settings->current_z
04316 #ifdef AA
04317 ,           settings->AA_current
04318 #else
04319 #ifdef ALL_AXES
04320 , 0
04321 #endif
04322 #endif
04323 #ifdef BB
04324 ,  settings->BB_current
04325 #else
04326 #ifdef ALL_AXES
04327 , 0
04328 #endif
04329 #endif
04330 #ifdef CC
04331 ,  settings->CC_current
04332 #else
04333 #ifdef ALL_AXES
04334 , 0
04335 #endif
04336 #endif
04337 );
04338       old_cc SET_TO r;
04339     }
04340   clear_cc SET_TO (settings->retract_mode IS R_PLANE) ? r : old_cc;
04341 
04342   save_mode = GET_EXTERNAL_MOTION_CONTROL_MODE();
04343   if (save_mode ISNT CANON_EXACT_PATH)
04344     SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH);
04345 
04346   switch(motion)
04347     {
04348     case G_81:
04349       CYCLE_MACRO(convert_cycle_g81(CANON_PLANE_XZ, aa, bb, clear_cc, cc))
04350       break;
04351     case G_82:
04352       CHK(((settings->motion_mode ISNT G_82) AND (block->p_number IS -1.0)),
04353           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G82);
04354       block->p_number SET_TO
04355         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
04356       CYCLE_MACRO(convert_cycle_g82 (CANON_PLANE_XZ, aa, bb, clear_cc, cc,
04357                                      block->p_number))
04358       settings->cycle_p SET_TO block->p_number;
04359       break;
04360     case G_83:
04361       CHK(((settings->motion_mode ISNT G_83) AND (block->q_number IS -1.0)),
04362           NCE_Q_WORD_MISSING_WITH_G83);
04363       block->q_number SET_TO
04364         block->q_number IS -1.0 ? settings->cycle_q : block->q_number;
04365       CYCLE_MACRO(convert_cycle_g83 (CANON_PLANE_XZ, aa, bb, r, clear_cc, cc,
04366                                      block->q_number))
04367       settings->cycle_q SET_TO block->q_number;
04368       break;
04369     case G_84:
04370       CYCLE_MACRO(convert_cycle_g84 (CANON_PLANE_XZ, aa, bb, clear_cc, cc,
04371                       settings->spindle_turning, settings->speed_feed_mode))
04372       break;
04373     case G_85:
04374       CYCLE_MACRO(convert_cycle_g85 (CANON_PLANE_XZ, aa, bb, clear_cc, cc))
04375       break;
04376     case G_86:
04377       CHK(((settings->motion_mode ISNT G_86) AND (block->p_number IS -1.0)),
04378           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G86);
04379       block->p_number SET_TO
04380         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
04381       CYCLE_MACRO(convert_cycle_g86 (CANON_PLANE_XZ, aa, bb, clear_cc, cc,
04382                             block->p_number, settings->spindle_turning))
04383       settings->cycle_p SET_TO block->p_number;
04384       break;
04385     case G_87:
04386       if (settings->motion_mode ISNT G_87)
04387         {
04388           CHK((block->i_flag IS OFF), NCE_I_WORD_MISSING_WITH_G87);
04389           CHK((block->j_flag IS OFF), NCE_J_WORD_MISSING_WITH_G87);
04390           CHK((block->k_flag IS OFF), NCE_K_WORD_MISSING_WITH_G87);
04391         }
04392       i SET_TO block->i_flag IS ON ? block->i_number : settings->cycle_i;
04393       j SET_TO block->j_flag IS ON ? block->j_number : settings->cycle_j;
04394       k SET_TO block->k_flag IS ON ? block->k_number : settings->cycle_k;
04395       settings->cycle_i SET_TO i;
04396       settings->cycle_j SET_TO j;
04397       settings->cycle_k SET_TO k;
04398       if (settings->distance_mode IS MODE_INCREMENTAL)
04399         {
04400           j SET_TO (cc + j); /* j always absolute in function call below */
04401         }
04402       CYCLE_MACRO(convert_cycle_g87 (CANON_PLANE_XZ, aa, (aa + k), bb,
04403                       (bb + i), r, clear_cc, j, cc, settings->spindle_turning))
04404       break;
04405     case G_88:
04406       CHK(((settings->motion_mode ISNT G_88) AND (block->p_number IS -1.0)),
04407           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G88);
04408       block->p_number SET_TO
04409         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
04410       CYCLE_MACRO(convert_cycle_g88 (CANON_PLANE_XZ, aa, bb, cc,
04411                                 block->p_number, settings->spindle_turning))
04412       settings->cycle_p SET_TO block->p_number;
04413       break;
04414     case G_89:
04415       CHK(((settings->motion_mode ISNT G_89) AND (block->p_number IS -1.0)),
04416           NCE_DWELL_TIME_P_WORD_MISSING_WITH_G89);
04417       block->p_number SET_TO
04418         block->p_number IS -1.0 ? settings->cycle_p : block->p_number;
04419       CYCLE_MACRO(convert_cycle_g89 (CANON_PLANE_XZ, aa, bb, clear_cc, cc,
04420                                      block->p_number))
04421       settings->cycle_p SET_TO block->p_number;
04422       break;
04423     default:
04424       ERM(NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
04425     }
04426   settings->current_z SET_TO aa; /* CYCLE_MACRO updates aa and bb */
04427   settings->current_x SET_TO bb;
04428   settings->current_y SET_TO clear_cc;
04429   settings->cycle_cc SET_TO block->y_number;
04430 
04431   if (save_mode ISNT CANON_EXACT_PATH)
04432     SET_MOTION_CONTROL_MODE(save_mode);
04433 
04434   return RS274NGC_OK;
04435 }
04436 
04437 /****************************************************************************/
04438 
04439 /* convert_distance_mode
04440 
04441 Returned Value: int
04442    If any of the following errors occur, this returns the error shown.
04443    Otherwise, it returns RS274NGC_OK.
04444    1. g_code isn't G_90 or G_91: NCE_BUG_CODE_NOT_G90_OR_G91
04445 
04446 Side effects:
04447    The interpreter switches the machine settings to indicate the current
04448    distance mode (absolute or incremental).
04449 
04450    The canonical machine to which commands are being sent does not have
04451    an incremental mode, so no command setting the distance mode is
04452    generated in this function. A comment function call explaining the
04453    change of mode is made (conditionally), however, if there is a change.
04454 
04455 Called by: convert_g.
04456 
04457 */
04458 
04459 static int convert_distance_mode( /* ARGUMENTS                             */
04460  int g_code,               /* g_code being executed (must be G_90 or G_91) */
04461  setup_pointer settings)   /* pointer to machine settings                  */
04462 {
04463   static char name[] SET_TO "convert_distance_mode";
04464   if (g_code IS G_90)
04465     {
04466       if (settings->distance_mode ISNT MODE_ABSOLUTE)
04467         {
04468 #ifdef DEBUG_EMC
04469           COMMENT("interpreter: distance mode changed to absolute");
04470 #endif
04471           settings->distance_mode SET_TO MODE_ABSOLUTE;
04472         }
04473     }
04474   else if (g_code IS G_91)
04475     {
04476       if (settings->distance_mode ISNT MODE_INCREMENTAL)
04477         {
04478 #ifdef DEBUG_EMC
04479           COMMENT("interpreter: distance mode changed to incremental");
04480 #endif
04481           settings->distance_mode SET_TO MODE_INCREMENTAL;
04482         }
04483     }
04484   else
04485     ERM(NCE_BUG_CODE_NOT_G90_OR_G91);
04486   return RS274NGC_OK;
04487 }
04488 
04489 /****************************************************************************/
04490 
04491 /* convert_dwell
04492 
04493 Returned Value: int (RS274NGC_OK)
04494 
04495 Side effects:
04496    A dwell command is executed.
04497 
04498 Called by: convert_g.
04499 
04500 */
04501 
04502 static int convert_dwell( /* ARGUMENTS                 */
04503  double time)             /* time in seconds to dwell  */
04504 {
04505   DWELL(time);
04506   return RS274NGC_OK;
04507 }
04508 
04509 /****************************************************************************/
04510 
04511 /* convert_feed_mode
04512 
04513 Returned Value: int
04514    If any of the following errors occur, this returns the error code shown.
04515    Otherwise, it returns RS274NGC_OK.
04516    1.  g_code isn't G_93 or G_94: NCE_BUG_CODE_NOT_G93_OR_G94
04517 
04518 Side effects:
04519    The interpreter switches the machine settings to indicate the current
04520    feed mode (UNITS_PER_MINUTE or INVERSE_TIME).
04521 
04522    The canonical machine to which commands are being sent does not have
04523    a feed mode, so no command setting the distance mode is generated in
04524    this function. A comment function call is made (conditionally)
04525    explaining the change in mode, however.
04526 
04527 Called by: execute_block.
04528 
04529 */
04530 
04531 static int convert_feed_mode( /* ARGUMENTS                                 */
04532  int g_code,               /* g_code being executed (must be G_93 or G_94) */
04533  setup_pointer settings)   /* pointer to machine settings                  */
04534 {
04535   static char name[] SET_TO "convert_feed_mode";
04536   if (g_code IS G_93)
04537     {
04538 #ifdef DEBUG_EMC
04539       COMMENT("interpreter: feed mode set to inverse time");
04540 #endif
04541       settings->feed_mode SET_TO INVERSE_TIME;
04542     }
04543   else if (g_code IS G_94)
04544     {
04545 #ifdef DEBUG_EMC
04546       COMMENT("interpreter: feed mode set to units per minute");
04547 #endif
04548       settings->feed_mode SET_TO UNITS_PER_MINUTE;
04549     }
04550   else
04551     ERM(NCE_BUG_CODE_NOT_G93_OR_G94);
04552   return RS274NGC_OK;
04553 }
04554 
04555 /****************************************************************************/
04556 
04557 /* convert_feed_rate
04558 
04559 Returned Value: int (RS274NGC_OK)
04560 
04561 Side effects:
04562    The machine feed_rate is set to the value of f_number in the
04563      block by function call.
04564    The machine model feed_rate is set to that value.
04565 
04566 Called by: execute_block
04567 
04568 This is called only if the feed mode is UNITS_PER_MINUTE.
04569 
04570 */
04571 
04572 static int convert_feed_rate( /* ARGUMENTS                                */
04573  block_pointer block,         /* pointer to a block of RS274 instructions */
04574  setup_pointer settings)      /* pointer to machine settings              */
04575 {
04576   SET_FEED_RATE(block->f_number);
04577   settings->feed_rate SET_TO block->f_number;
04578   return RS274NGC_OK;
04579 }
04580 
04581 /****************************************************************************/
04582 
04583 /* convert_g
04584 
04585 Returned Value: int
04586    If one of the following functions is called and returns an error code,
04587    this returns that code.
04588       convert_control_mode
04589       convert_coordinate_system
04590       convert_cutter_compensation
04591       convert_distance_mode
04592       convert_dwell
04593       convert_length_units
04594       convert_modal_0
04595       convert_motion
04596       convert_retract_mode
04597       convert_set_plane
04598       convert_tool_length_offset
04599    Otherwise, it returns RS274NGC_OK.
04600 
04601 Side effects:
04602    Any g_codes in the block (excluding g93 and 94) and any implicit
04603    motion g_code are executed.
04604 
04605 Called by: execute_block.
04606 
04607 This takes a pointer to a block of RS274/NGC instructions (already
04608 read in) and creates the appropriate output commands corresponding to
04609 any "g" codes in the block.
04610 
04611 Codes g93 and g94, which set the feed mode, are executed earlier by
04612 execute_block before reading the feed rate.
04613 
04614 G codes are are executed in the following order.
04615 1.  mode 0, G4 only - dwell. Left here from earlier versions.
04616 2.  mode 2, one of (G17, G18, G19) - plane selection.
04617 3.  mode 6, one of (G20, G21) - length units.
04618 4.  mode 7, one of (G40, G41, G42) - cutter radius compensation.
04619 5.  mode 8, one of (G43, G49) - tool length offset
04620 6.  mode 12, one of (G54, G55, G56, G57, G58, G59, G59.1, G59.2, G59.3)
04621     - coordinate system selection.
04622 7.  mode 13, one of (G61, G61.1, G64) - control mode
04623 8.  mode 3, one of (G90, G91) - distance mode.
04624 9.  mode 10, one of (G98, G99) - retract mode.
04625 10. mode 0, one of (G10, G28, G30, G92, G92.1, G92.2, G92.3) -
04626     setting coordinate system locations, return to reference point 1,
04627     return to reference point 2, setting or cancelling axis offsets.
04628 11. mode 1, one of (G0, G1, G2, G3, G38.2, G80, G81 to G89) - motion or cancel.
04629     G53 from mode 0 is also handled here, if present.
04630 
04631 Some mode 0 and most mode 1 G codes must be executed after the length units
04632 are set, since they use coordinate values. Mode 1 codes also must wait
04633 until most of the other modes are set.
04634 
04635 */
04636 
04637 static int convert_g(    /* ARGUMENTS                                    */
04638  block_pointer block,    /* pointer to a block of RS274/NGC instructions */
04639  setup_pointer settings) /* pointer to machine settings                  */
04640 {
04641   static char name[] SET_TO "convert_g";
04642   int status;
04643 
04644   if (block->g_modes[0] IS G_4)
04645     {
04646       CHP(convert_dwell(block->p_number));
04647     }
04648   if (block->g_modes[2] ISNT -1)
04649     {
04650       CHP(convert_set_plane(block->g_modes[2], settings));
04651     }
04652   if (block->g_modes[6] ISNT -1)
04653     {
04654       CHP(convert_length_units(block->g_modes[6], settings));
04655     }
04656   if (block->g_modes[7] ISNT -1)
04657     {
04658       CHP(convert_cutter_compensation(block->g_modes[7], block, settings));
04659     }
04660   if (block->g_modes[8] ISNT -1)
04661     {
04662       CHP(convert_tool_length_offset(block->g_modes[8], block, settings));
04663     }
04664   if (block->g_modes[12] ISNT -1)
04665     {
04666       CHP(convert_coordinate_system(block->g_modes[12], settings));
04667     }
04668   if (block->g_modes[13] ISNT -1)
04669     {
04670       CHP(convert_control_mode(block->g_modes[13], settings));
04671     }
04672   if (block->g_modes[3] ISNT -1)
04673     {
04674       CHP(convert_distance_mode(block->g_modes[3], settings));
04675     }
04676   if (block->g_modes[10] ISNT -1)
04677     {
04678       CHP(convert_retract_mode(block->g_modes[10], settings));
04679     }
04680   if (block->g_modes[0] ISNT -1)
04681     {
04682       CHP(convert_modal_0(block->g_modes[0], block, settings));
04683     }
04684   if (block->motion_to_be ISNT -1)
04685     {
04686       CHP(convert_motion(block->motion_to_be, block, settings));
04687     }
04688   return RS274NGC_OK;
04689 }
04690 
04691 /****************************************************************************/
04692 
04693 /* convert_home
04694 
04695 Returned Value: int
04696    If any of the following errors occur, this returns the error code shown.
04697    Otherwise, it returns RS274NGC_OK.
04698    1. cutter radius compensation is on:
04699       NCE_CANNOT_USE_G28_OR_G30_WITH_CUTTER_RADIUS_COMP
04700    2. The code is not G28 or G30: NCE_BUG_CODE_NOT_G28_OR_G30
04701 
04702 Side effects:
04703    This executes a straight traverse to the programmed point, using
04704    the current coordinate system, tool length offset, and motion mode
04705    to interpret the coordinate values. Then it executes a straight
04706    traverse to the location of reference point 1 (if G28) or reference
04707    point 2 (if G30). It also updates the setting of the position of the
04708    tool point to the end point of the move.
04709 
04710 Called by: convert_modal_0.
04711 
04712 During the motion from the intermediate point to the home point, this
04713 function currently makes the A and C axes turn counterclockwise if a
04714 turn is needed.  This is not necessarily the most efficient way to do
04715 it. A check might be made of which direction to turn to have the least
04716 turn to get to the reference position, and the axis would turn that
04717 way.
04718 
04719 */
04720 
04721 static int convert_home( /* ARGUMENTS                                */
04722  int move,               /* G code, must be G_28 or G_30             */
04723  block_pointer block,    /* pointer to a block of RS274 instructions */
04724  setup_pointer settings) /* pointer to machine settings              */
04725 {
04726   static char name[] SET_TO "convert_home";
04727   double end_x;
04728   double end_y;
04729   double end_z;
04730 #ifdef AA
04731   double AA_end;        /*AA*/
04732 #endif
04733 #ifdef AA
04734   double AA_end2;       /*AA*/
04735 #endif
04736 #ifdef BB
04737   double BB_end;        /*BB*/
04738 #endif
04739 #ifdef BB
04740   double BB_end2;       /*BB*/
04741 #endif
04742 #ifdef CC
04743   double CC_end;        /*CC*/
04744 #endif
04745 #ifdef CC
04746   double CC_end2;       /*CC*/
04747 #endif
04748   double * parameters;
04749 
04750   parameters SET_TO settings->parameters;
04751   find_ends(block, settings, &end_x, &end_y,
04752             &end_z
04753 #ifdef AA
04754 , &AA_end
04755 #endif
04756 
04757 #ifdef BB
04758 , &BB_end
04759 #endif
04760 
04761 #ifdef CC
04762 , &CC_end
04763 #endif
04764 );
04765 
04766   CHK((settings->cutter_comp_side ISNT OFF),
04767       NCE_CANNOT_USE_G28_OR_G30_WITH_CUTTER_RADIUS_COMP);
04768   STRAIGHT_TRAVERSE(end_x, end_y, end_z
04769 #ifdef AA
04770 ,                   AA_end
04771 #else
04772 #ifdef ALL_AXES
04773 , 0
04774 #endif
04775 #endif
04776 #ifdef BB
04777 ,  BB_end
04778 #else
04779 #ifdef ALL_AXES
04780 , 0
04781 #endif
04782 #endif
04783 #ifdef CC
04784 ,  CC_end
04785 #else
04786 #ifdef ALL_AXES
04787 , 0
04788 #endif
04789 #endif
04790 );
04791   if (move IS G_28)
04792     {
04793       find_relative
04794         (parameters[5161], parameters[5162], parameters[5163],
04795 #ifdef AA
04796          parameters[5164],  /*AA*/
04797 #endif
04798 #ifdef BB
04799          parameters[5165],  /*BB*/
04800 #endif
04801 #ifdef CC
04802          parameters[5166],  /*CC*/
04803 #endif
04804          &end_x, &end_y, &end_z
04805 #ifdef AA
04806 , &AA_end2
04807 #endif
04808 
04809 #ifdef BB
04810 , &BB_end2
04811 #endif
04812 
04813 #ifdef CC
04814 , &CC_end2
04815 #endif
04816 , settings);
04817     }
04818   else if (move IS G_30)
04819     {
04820       find_relative
04821         (parameters[5181], parameters[5182], parameters[5183],
04822 #ifdef AA
04823          parameters[5184],  /*AA*/
04824 #endif
04825 #ifdef BB
04826          parameters[5185],  /*BB*/
04827 #endif
04828 #ifdef CC
04829          parameters[5186],  /*CC*/
04830 #endif
04831          &end_x, &end_y, &end_z
04832 #ifdef AA
04833 , &AA_end2
04834 #endif
04835 
04836 #ifdef BB
04837 , &BB_end2
04838 #endif
04839 
04840 #ifdef CC
04841 , &CC_end2
04842 #endif
04843 , settings);
04844     }
04845   else
04846     ERM(NCE_BUG_CODE_NOT_G28_OR_G30);
04847   STRAIGHT_TRAVERSE(end_x, end_y, end_z
04848 #ifdef AA
04849 ,                   AA_end
04850 #else
04851 #ifdef ALL_AXES
04852 , 0
04853 #endif
04854 #endif
04855 #ifdef BB
04856 ,  BB_end
04857 #else
04858 #ifdef ALL_AXES
04859 , 0
04860 #endif
04861 #endif
04862 #ifdef CC
04863 ,  CC_end
04864 #else
04865 #ifdef ALL_AXES
04866 , 0
04867 #endif
04868 #endif
04869 );
04870   settings->current_x SET_TO end_x;
04871   settings->current_y SET_TO end_y;
04872   settings->current_z SET_TO end_z;
04873 #ifdef AA
04874   settings->AA_current SET_TO AA_end2;       /*AA*/
04875 #endif
04876 #ifdef BB
04877   settings->BB_current SET_TO BB_end2;       /*BB*/
04878 #endif
04879 #ifdef CC
04880   settings->CC_current SET_TO CC_end2;       /*CC*/
04881 #endif
04882   return RS274NGC_OK;
04883 }
04884 
04885 /****************************************************************************/
04886 
04887 /* convert_length_units
04888 
04889 Returned Value: int
04890    If any of the following errors occur, this returns the error shown.
04891    Otherwise, it returns RS274NGC_OK.
04892    1. The g_code argument isnt G_20 or G_21:
04893       NCE_BUG_CODE_NOT_G20_OR_G21
04894    2. Cutter radius compensation is on:
04895       NCE_CANNOT_CHANGE_UNITS_WITH_CUTTER_RADIUS_COMP
04896 
04897 Side effects:
04898    A command setting the length units is executed. The machine
04899    settings are reset regarding length units and current position.
04900 
04901 Called by: convert_g.
04902 
04903 We are not changing tool length offset values or tool diameter values.
04904 Those values must be given in the table in the correct units. Thus it
04905 will generally not be feasible to switch units in the middle of a
04906 program.
04907 
04908 We are not changing the parameters that represent the positions
04909 of the nine work coordinate systems.
04910 
04911 We are also not changing feed rate values when length units are
04912 changed, so the actual behavior may change.
04913 
04914 Several other distance items in the settings (such as the various
04915 parameters for cycles) are also not reset.
04916 
04917 We are changing origin offset and axis offset values, which are
04918 critical. If this were not done, when length units are set and the new
04919 length units are not the same as the default length units
04920 (millimeters), and any XYZ origin or axis offset is not zero, then any
04921 subsequent change in XYZ origin or axis offset values will be
04922 incorrect.  Also, g53 (motion in absolute coordinates) will not work
04923 correctly.
04924 
04925 */
04926 
04927 static int convert_length_units( /* ARGUMENTS                             */
04928  int g_code,              /* g_code being executed (must be G_20 or G_21) */
04929  setup_pointer settings)  /* pointer to machine settings                  */
04930 {
04931   static char name[] SET_TO "convert_length_units";
04932   CHK((settings->cutter_comp_side ISNT OFF),
04933       NCE_CANNOT_CHANGE_UNITS_WITH_CUTTER_RADIUS_COMP);
04934   if (g_code IS G_20)
04935     {
04936       USE_LENGTH_UNITS(CANON_UNITS_INCHES);
04937       if (settings->length_units ISNT CANON_UNITS_INCHES)
04938         {
04939           settings->length_units SET_TO CANON_UNITS_INCHES;
04940           settings->current_x SET_TO (settings->current_x * INCH_PER_MM);
04941           settings->current_y SET_TO (settings->current_y * INCH_PER_MM);
04942           settings->current_z SET_TO (settings->current_z * INCH_PER_MM);
04943           settings->axis_offset_x SET_TO
04944             (settings->axis_offset_x * INCH_PER_MM);
04945           settings->axis_offset_y SET_TO
04946             (settings->axis_offset_y * INCH_PER_MM);
04947           settings->axis_offset_z SET_TO
04948             (settings->axis_offset_z * INCH_PER_MM);
04949           settings->origin_offset_x SET_TO
04950             (settings->origin_offset_x * INCH_PER_MM);
04951           settings->origin_offset_y SET_TO
04952             (settings->origin_offset_y * INCH_PER_MM);
04953           settings->origin_offset_z SET_TO
04954             (settings->origin_offset_z * INCH_PER_MM);
04955         }
04956     }
04957   else if (g_code IS G_21)
04958     {
04959       USE_LENGTH_UNITS(CANON_UNITS_MM);
04960       if (settings->length_units ISNT CANON_UNITS_MM)
04961         {
04962           settings->length_units SET_TO CANON_UNITS_MM;
04963           settings->current_x SET_TO (settings->current_x * MM_PER_INCH);
04964           settings->current_y SET_TO (settings->current_y * MM_PER_INCH);
04965           settings->current_z SET_TO (settings->current_z * MM_PER_INCH);
04966           settings->axis_offset_x SET_TO
04967             (settings->axis_offset_x * MM_PER_INCH);
04968           settings->axis_offset_y SET_TO
04969             (settings->axis_offset_y * MM_PER_INCH);
04970           settings->axis_offset_z SET_TO
04971             (settings->axis_offset_z * MM_PER_INCH);
04972           settings->origin_offset_x SET_TO
04973             (settings->origin_offset_x * MM_PER_INCH);
04974           settings->origin_offset_y SET_TO
04975             (settings->origin_offset_y * MM_PER_INCH);
04976           settings->origin_offset_z SET_TO
04977             (settings->origin_offset_z * MM_PER_INCH);
04978         }
04979     }
04980   else
04981     ERM(NCE_BUG_CODE_NOT_G20_OR_G21);
04982   return RS274NGC_OK;
04983 }
04984 
04985 /****************************************************************************/
04986 
04987 /* convert_m
04988 
04989 Returned Value: int
04990    If convert_tool_change returns an error code, this returns that code.
04991    Otherwise, it returns RS274NGC_OK.
04992 
04993 Side effects:
04994    m_codes in the block are executed. For each m_code
04995    this consists of making a function call(s) to a canonical machining
04996    function(s) and setting the machine model.
04997 
04998 Called by: execute_block.
04999 
05000 This handles four separate types of activity in order:
05001 1. changing the tool (m6) - which also retracts and stops the spindle.
05002 2. Turning the spindle on or off (m3, m4, and m5)
05003 3. Turning coolant on and off (m7, m8, and m9)
05004 4. turning a-axis clamping on and off (m26, m27) - commented out.
05005 5. enabling or disabling feed and speed overrides (m49, m49).
05006 Within each group, only the first code encountered will be executed.
05007 
05008 This does nothing with m0, m1, m2, m30, or m60 (which are handled in
05009 convert_stop).
05010 
05011 */
05012 
05013 static int convert_m(    /* ARGUMENTS                                    */
05014  block_pointer block,    /* pointer to a block of RS274/NGC instructions */
05015  setup_pointer settings) /* pointer to machine settings                  */
05016 {
05017   static char name[] SET_TO "convert_m";
05018   int status;
05019 
05020   if (block->m_modes[6] ISNT -1)
05021     {
05022       CHP(convert_tool_change(settings));
05023     }
05024 
05025   if (block->m_modes[7] IS 3)
05026     {
05027       START_SPINDLE_CLOCKWISE();
05028       settings->spindle_turning SET_TO CANON_CLOCKWISE;
05029     }
05030   else if (block->m_modes[7] IS 4)
05031     {
05032       START_SPINDLE_COUNTERCLOCKWISE();
05033       settings->spindle_turning SET_TO CANON_COUNTERCLOCKWISE;
05034     }
05035   else if (block->m_modes[7] IS 5)
05036     {
05037       STOP_SPINDLE_TURNING();
05038       settings->spindle_turning SET_TO CANON_STOPPED;
05039     }
05040 
05041   if (block->m_modes[8] IS 7)
05042     {
05043       MIST_ON();
05044       settings->mist SET_TO ON;
05045     }
05046   else if (block->m_modes[8] IS 8)
05047     {
05048       FLOOD_ON();
05049       settings->flood SET_TO ON;
05050     }
05051   else if (block->m_modes[8] IS 9)
05052     {
05053       MIST_OFF();
05054       settings->mist SET_TO OFF;
05055       FLOOD_OFF();
05056       settings->flood SET_TO OFF;
05057     }
05058 
05059 /* No axis clamps in this version
05060   if (block->m_modes[2] IS 26)
05061     {
05062 #ifdef DEBUG_EMC
05063       COMMENT("interpreter: automatic A-axis clamping turned on");
05064 #endif
05065       settings->a_axis_clamping SET_TO ON;
05066     }
05067   else if (block->m_modes[2] IS 27)
05068     {
05069 #ifdef DEBUG_EMC
05070       COMMENT("interpreter: automatic A-axis clamping turned off");
05071 #endif
05072       settings->a_axis_clamping SET_TO OFF;
05073     }
05074 */
05075 
05076   if (block->m_modes[9] IS 48)
05077     {
05078       ENABLE_FEED_OVERRIDE();
05079       ENABLE_SPEED_OVERRIDE();
05080       settings->feed_override SET_TO ON;
05081       settings->speed_override SET_TO ON;
05082     }
05083   else if (block->m_modes[9] IS 49)
05084     {
05085       DISABLE_FEED_OVERRIDE();
05086       DISABLE_SPEED_OVERRIDE();
05087       settings->feed_override SET_TO OFF;
05088       settings->speed_override SET_TO OFF;
05089     }
05090 
05091   return RS274NGC_OK;
05092 }
05093 
05094 /****************************************************************************/
05095 
05096 /* convert_modal_0
05097 
05098 Returned Value: int
05099    If one of the following functions is called and returns an error code,
05100    this returns that code.
05101       convert_axis_offsets
05102       convert_home
05103       convert_setup
05104    If any of the following errors occur, this returns the error code shown.
05105    Otherwise, it returns RS274NGC_OK.
05106    1. code is not G_4, G_10, G_28, G_30, G_53, G92, G_92_1, G_92_2, or G_92_3:
05107       NCE_BUG_CODE_NOT_G4_G10_G28_G30_G53_OR_G92_SERIES
05108 
05109 Side effects: See below
05110 
05111 Called by: convert_g
05112 
05113 If the g_code is g10, g28, g30, g92, g92.1, g92.2, or g92.3 (all are in
05114 modal group 0), it is executed. The other two in modal group 0 (G4 and
05115 G53) are executed elsewhere.
05116 
05117 */
05118 
05119 static int convert_modal_0( /* ARGUMENTS                                    */
05120  int code,                  /* G code, must be from group 0                 */
05121  block_pointer block,       /* pointer to a block of RS274/NGC instructions */
05122  setup_pointer settings)    /* pointer to machine settings                  */
05123 {
05124   static char name[] SET_TO "convert_modal_0";
05125   int status;
05126 
05127   if (code IS G_10)
05128     {
05129       CHP(convert_setup(block, settings));
05130     }
05131   else if ((code IS G_28) OR (code IS G_30))
05132     {
05133       CHP(convert_home(code, block, settings));
05134     }
05135   else if ((code IS G_92)   OR (code IS G_92_1) OR
05136            (code IS G_92_2) OR (code IS G_92_3))
05137     {
05138       CHP(convert_axis_offsets(code, block, settings));
05139     }
05140   else if ((code IS G_4) OR (code IS G_53)); /* handled elsewhere */
05141   else
05142     ERM(NCE_BUG_CODE_NOT_G4_G10_G28_G30_G53_OR_G92_SERIES);
05143   return RS274NGC_OK;
05144 }
05145 
05146 /****************************************************************************/
05147 
05148 /* convert_motion
05149 
05150 Returned Value: int
05151    If one of the following functions is called and returns an error code,
05152    this returns that code.
05153       convert_arc
05154       convert_cycle
05155       convert_probe
05156       convert_straight
05157    If any of the following errors occur, this returns the error shown.
05158    Otherwise, it returns RS274NGC_OK.
05159    1. The motion code is not 0,1,2,3,38.2,80,81,82,83,84,85,86,87, 88, or 89:
05160       NCE_BUG_UNKNOWN_MOTION_CODE
05161 
05162 Side effects:
05163    A g_code from the group causing motion (mode 1) is executed.
05164 
05165 Called by: convert_g.
05166 
05167 */
05168 
05169 static int convert_motion( /* ARGUMENTS                                 */
05170  int motion,               /* g_code for a line, arc, canned cycle      */
05171  block_pointer block,      /* pointer to a block of RS274 instructions  */
05172  setup_pointer settings)   /* pointer to machine settings               */
05173 {
05174   static char name[] SET_TO "convert_motion";
05175   int status;
05176 
05177   if ((motion IS G_0) OR (motion IS G_1))
05178     {
05179       CHP(convert_straight(motion, block, settings));
05180     }
05181   else if ((motion IS G_3) OR (motion IS G_2))
05182     {
05183       CHP(convert_arc(motion, block, settings));
05184     }
05185   else if (motion IS G_38_2)
05186     {
05187       CHP(convert_probe(block, settings));
05188     }
05189   else if (motion IS G_80)
05190     {
05191 #ifdef DEBUG_EMC
05192       COMMENT("interpreter: motion mode set to none");
05193 #endif
05194       settings->motion_mode SET_TO G_80;
05195     }
05196   else if ((motion > G_80) AND (motion < G_90))
05197     {
05198       CHP(convert_cycle(motion, block, settings));
05199     }
05200   else
05201     ERM(NCE_BUG_UNKNOWN_MOTION_CODE);
05202 
05203   return RS274NGC_OK;
05204 }
05205 
05206 /****************************************************************************/
05207 
05208 /* convert_probe
05209 
05210 Returned Value: int
05211    If any of the following errors occur, this returns the error code shown.
05212    Otherwise, it returns RS274NGC_OK.
05213    1. No value is given in the block for any of X, Y, or Z:
05214       NCE_X_Y_AND_Z_WORDS_ALL_MISSING_WITH_G38_2
05215    2. feed mode is inverse time: NCE_CANNOT_PROBE_IN_INVERSE_TIME_FEED_MODE
05216    3. cutter radius comp is on: NCE_CANNOT_PROBE_WITH_CUTTER_RADIUS_COMP_ON
05217    4. Feed rate is zero: NCE_CANNOT_PROBE_WITH_ZERO_FEED_RATE
05218    5. Rotary axis motion is programmed:
05219       NCE_CANNOT_MOVE_ROTARY_AXES_DURING_PROBING
05220    6. The starting point for the probe move is within 0.01 inch or 0.254
05221       millimeters of the point to be probed:
05222       NCE_START_POINT_TOO_CLOSE_TO_PROBE_POINT
05223 
05224 Side effects:
05225    This executes a straight_probe command.
05226    The probe_flag in the settings is set to ON.
05227    The motion mode in the settings is set to G_38_2.
05228 
05229 Called by: convert_motion.
05230 
05231 The approach to operating in incremental distance mode (g91) is to
05232 put the the absolute position values into the block before using the
05233 block to generate a move.
05234 
05235 After probing is performed, the location of the probe cannot be
05236 predicted. This differs from every other command, all of which have
05237 predictable results. The next call to the interpreter (with either
05238 rs274ngc_read or rs274ngc_execute) will result in updating the
05239 current position by calls to get_external_position_x, etc.
05240 
05241 */
05242 
05243 static int convert_probe( /* ARGUMENTS                                */
05244  block_pointer block,     /* pointer to a block of RS274 instructions */
05245  setup_pointer settings)  /* pointer to machine settings              */
05246 {
05247   static char name[] SET_TO "convert_probe";
05248   double distance;
05249   double end_x;
05250   double end_y;
05251   double end_z;
05252 #ifdef AA
05253   double AA_end;        /*AA*/
05254 #endif
05255 #ifdef BB
05256   double BB_end;        /*BB*/
05257 #endif
05258 #ifdef CC
05259   double CC_end;        /*CC*/
05260 #endif
05261 
05262   CHK((((block->x_flag IS OFF) AND (block->y_flag IS OFF)) AND
05263        (block->z_flag IS OFF)), NCE_X_Y_AND_Z_WORDS_ALL_MISSING_WITH_G38_2);
05264   CHK((settings->feed_mode IS INVERSE_TIME),
05265       NCE_CANNOT_PROBE_IN_INVERSE_TIME_FEED_MODE);
05266   CHK((settings->cutter_comp_side ISNT OFF),
05267       NCE_CANNOT_PROBE_WITH_CUTTER_RADIUS_COMP_ON);
05268   CHK((settings->feed_rate IS 0.0), NCE_CANNOT_PROBE_WITH_ZERO_FEED_RATE);
05269   find_ends(block, settings, &end_x, &end_y,
05270             &end_z
05271 #ifdef AA
05272 , &AA_end
05273 #endif
05274 
05275 #ifdef BB
05276 , &BB_end
05277 #endif
05278 
05279 #ifdef CC
05280 , &CC_end
05281 #endif
05282 );
05283   if (0
05284 #ifdef AA
05285       OR (AA_end ISNT settings->AA_current)    /*AA*/
05286 #endif
05287 #ifdef BB
05288       OR (BB_end ISNT settings->BB_current)    /*BB*/
05289 #endif
05290 #ifdef CC
05291       OR (CC_end ISNT settings->CC_current)    /*CC*/
05292 #endif
05293       )
05294     ERM(NCE_CANNOT_MOVE_ROTARY_AXES_DURING_PROBING);
05295   distance SET_TO sqrt(pow((settings->current_x - end_x), 2) +
05296                        pow((settings->current_y - end_y), 2) +
05297                        pow((settings->current_z - end_z), 2));
05298   CHK((distance < ((settings->length_units IS CANON_UNITS_MM) ? 0.254 : 0.01)),
05299       NCE_START_POINT_TOO_CLOSE_TO_PROBE_POINT);
05300   TURN_PROBE_ON();
05301   STRAIGHT_PROBE(end_x, end_y, end_z
05302 #ifdef AA
05303 ,                AA_end
05304 #else
05305 #ifdef ALL_AXES
05306 , 0
05307 #endif
05308 #endif
05309 #ifdef BB
05310 ,  BB_end
05311 #else
05312 #ifdef ALL_AXES
05313 , 0
05314 #endif
05315 #endif
05316 #ifdef CC
05317 ,  CC_end
05318 #else
05319 #ifdef ALL_AXES
05320 , 0
05321 #endif
05322 #endif
05323 );
05324   TURN_PROBE_OFF();
05325   settings->motion_mode SET_TO G_38_2;
05326   settings->probe_flag SET_TO ON;
05327   return RS274NGC_OK;
05328 }
05329 
05330 /****************************************************************************/
05331 
05332 /* convert_retract_mode
05333 
05334 Returned Value: int
05335    If any of the following errors occur, this returns the error code shown.
05336    Otherwise, it returns RS274NGC_OK.
05337    1. g_code isn't G_98 or G_99: NCE_BUG_CODE_NOT_G98_OR_G99
05338 
05339 Side effects:
05340    The interpreter switches the machine settings to indicate the current
05341    retract mode for canned cycles (OLD_Z or R_PLANE).
05342 
05343 Called by: convert_g.
05344 
05345 The canonical machine to which commands are being sent does not have a
05346 retract mode, so no command setting the retract mode is generated in
05347 this function.
05348 
05349 */
05350 
05351 static int convert_retract_mode( /* ARGUMENTS                             */
05352  int g_code,              /* g_code being executed (must be G_98 or G_99) */
05353  setup_pointer settings)  /* pointer to machine settings                  */
05354 {
05355   static char name[] SET_TO "convert_retract_mode";
05356   if (g_code IS G_98)
05357     {
05358 #ifdef DEBUG_EMC
05359       COMMENT("interpreter: retract mode set to old_z");
05360 #endif
05361       settings->retract_mode SET_TO OLD_Z;
05362     }
05363   else if (g_code IS G_99)
05364     {
05365 #ifdef DEBUG_EMC
05366       COMMENT("interpreter: retract mode set to r_plane");
05367 #endif
05368       settings->retract_mode SET_TO R_PLANE;
05369     }
05370   else
05371     ERM(NCE_BUG_CODE_NOT_G98_OR_G99);
05372   return RS274NGC_OK;
05373 }
05374 
05375 /****************************************************************************/
05376 
05377 /* convert_setup
05378 
05379 Returned Value: int (RS274NGC_OK)
05380 
05381 Side effects:
05382    SET_PROGRAM_ORIGIN is called, and the coordinate
05383    values for the program origin are reset.
05384    If the program origin is currently in use, the values of the
05385    the coordinates of the current point are updated.
05386 
05387 Called by: convert_modal_0.
05388 
05389 This is called only if g10 is called. g10 L2 may be used to alter the
05390 location of coordinate systems as described in [NCMS, pages 9 - 10] and
05391 [Fanuc, page 65]. [Fanuc] has only six coordinate systems, while
05392 [NCMS] has nine (the first six of which are the same as the six [Fanuc]
05393 has). All nine are implemented here.
05394 
05395 Being in incremental distance mode has no effect on the action of G10
05396 in this implementation. The manual is not explicit about what is
05397 intended.
05398 
05399 See documentation of convert_coordinate_system for more information.
05400 
05401 */
05402 
05403 static int convert_setup( /* ARGUMENTS                                    */
05404  block_pointer block,     /* pointer to a block of RS274/NGC instructions */
05405  setup_pointer settings)  /* pointer to machine settings                  */
05406 {
05407   static char name[] SET_TO "convert_setup";
05408   double x;
05409   double y;
05410   double z;
05411 #ifdef AA
05412   double a;  /*AA*/
05413 #endif
05414 #ifdef BB
05415   double b;  /*BB*/
05416 #endif
05417 #ifdef CC
05418   double c;  /*CC*/
05419 #endif
05420   double * parameters;
05421   int p_int;
05422 
05423   parameters SET_TO settings->parameters;
05424   p_int SET_TO (int)(block->p_number + 0.0001);
05425 
05426   if (block->x_flag IS ON)
05427     {
05428       x SET_TO block->x_number;
05429       parameters[5201 + (p_int * 20)] SET_TO x;
05430     }
05431   else
05432     x SET_TO parameters[5201 + (p_int * 20)];
05433 
05434   if (block->y_flag IS ON)
05435     {
05436       y SET_TO block->y_number;
05437       parameters[5202 + (p_int * 20)] SET_TO y;
05438     }
05439   else
05440     y SET_TO parameters[5202 + (p_int * 20)];
05441   if (block->z_flag IS ON)
05442     {
05443       z SET_TO block->z_number;
05444       parameters[5203 + (p_int * 20)] SET_TO z;
05445     }
05446   else
05447    z SET_TO parameters[5203 + (p_int * 20)];
05448 
05449 #ifdef AA
05450   if (block->a_flag IS ON)
05451     {
05452       a SET_TO block->a_number;
05453       parameters[5204 + (p_int * 20)] SET_TO a;
05454     }
05455   else
05456     a SET_TO parameters[5204 + (p_int * 20)];
05457 #endif
05458 
05459 #ifdef BB
05460   if (block->b_flag IS ON)
05461     {
05462       b SET_TO block->b_number;
05463       parameters[5205 + (p_int * 20)] SET_TO b;
05464     }
05465   else
05466     b SET_TO parameters[5205 + (p_int * 20)];
05467 #endif
05468 
05469 #ifdef CC
05470   if (block->c_flag IS ON)
05471     {
05472       c SET_TO block->c_number;
05473       parameters[5206 + (p_int * 20)] SET_TO c;
05474     }
05475   else
05476     c SET_TO parameters[5206 + (p_int * 20)];
05477 #endif
05478 
05479 /* axis offsets could be included in the two sets of calculations for
05480    current_x, current_y, etc., but do not need to be because the results
05481    would be the same. They would be added in then subtracted out. */
05482   if (p_int IS settings->origin_index) /* system is currently used */
05483     {
05484       settings->current_x SET_TO
05485         (settings->current_x + settings->origin_offset_x);
05486       settings->current_y SET_TO
05487         (settings->current_y + settings->origin_offset_y);
05488       settings->current_z SET_TO
05489         (settings->current_z + settings->origin_offset_z);
05490 #ifdef AA
05491       settings->AA_current SET_TO                                        /*AA*/
05492 #endif
05493 #ifdef AA
05494         (settings->AA_current + settings->AA_origin_offset);             /*AA*/
05495 #endif
05496 #ifdef BB
05497       settings->BB_current SET_TO                                        /*BB*/
05498 #endif
05499 #ifdef BB
05500         (settings->BB_current + settings->BB_origin_offset);             /*BB*/
05501 #endif
05502 #ifdef CC
05503       settings->CC_current SET_TO                                        /*CC*/
05504 #endif
05505 #ifdef CC
05506         (settings->CC_current + settings->CC_origin_offset);             /*CC*/
05507 #endif
05508 
05509       settings->origin_offset_x SET_TO x;
05510       settings->origin_offset_y SET_TO y;
05511       settings->origin_offset_z SET_TO z;
05512 #ifdef AA
05513       settings->AA_origin_offset SET_TO a;                               /*AA*/
05514 #endif
05515 #ifdef BB
05516       settings->BB_origin_offset SET_TO b;                               /*BB*/
05517 #endif
05518 #ifdef CC
05519       settings->CC_origin_offset SET_TO c;                               /*CC*/
05520 #endif
05521 
05522       settings->current_x SET_TO (settings->current_x - x);
05523       settings->current_y SET_TO (settings->current_y - y);
05524       settings->current_z SET_TO (settings->current_z - z);
05525 #ifdef AA
05526       settings->AA_current SET_TO (settings->AA_current - a);            /*AA*/
05527 #endif
05528 #ifdef BB
05529       settings->BB_current SET_TO (settings->BB_current - b);            /*BB*/
05530 #endif
05531 #ifdef CC
05532       settings->CC_current SET_TO (settings->CC_current - c);            /*CC*/
05533 #endif
05534 
05535       SET_ORIGIN_OFFSETS(x + settings->axis_offset_x,
05536                          y + settings->axis_offset_y,
05537                          z + settings->axis_offset_z
05538 #ifdef AA
05539 ,                        a + settings->AA_axis_offset
05540 #else
05541 #ifdef ALL_AXES
05542 , 0
05543 #endif
05544 #endif
05545 #ifdef BB
05546 ,                        b + settings->BB_axis_offset
05547 #else
05548 #ifdef ALL_AXES
05549 , 0
05550 #endif
05551 #endif
05552 #ifdef CC
05553 ,                        c + settings->CC_axis_offset
05554 #else
05555 #ifdef ALL_AXES
05556 , 0
05557 #endif
05558 #endif
05559 );
05560     }
05561 #ifdef DEBUG_EMC
05562   else
05563     COMMENT("interpreter: setting coordinate system origin");
05564 #endif
05565   return RS274NGC_OK;
05566 }
05567 
05568 /****************************************************************************/
05569 
05570 /* convert_set_plane
05571 
05572 Returned Value: int
05573    If any of the following errors occur, this returns the error code shown.
05574    Otherwise, it returns RS274NGC_OK.
05575    1. G_18 or G_19 is called when cutter radius compensation is on:
05576       NCE_CANNOT_USE_XZ_PLANE_WITH_CUTTER_RADIUS_COMP
05577       NCE_CANNOT_USE_YZ_PLANE_WITH_CUTTER_RADIUS_COMP
05578    2. The g_code is not G_17, G_18, or G_19:
05579       NCE_BUG_CODE_NOT_G17_G18_OR_G19
05580 
05581 Side effects:
05582    A canonical command setting the current plane is executed.
05583 
05584 Called by: convert_g.
05585 
05586 */
05587 
05588 static int convert_set_plane( /* ARGUMENTS                    */
05589  int g_code,                  /* must be G_17, G_18, or G_19  */
05590  setup_pointer settings)      /* pointer to machine settings  */
05591 {
05592   static char name[] SET_TO "convert_set_plane";
05593   if (g_code IS G_17)
05594     {
05595       SELECT_PLANE(CANON_PLANE_XY);
05596       settings->plane SET_TO CANON_PLANE_XY;
05597     }
05598   else if (g_code IS G_18)
05599     {
05600       CHK((settings->cutter_comp_side ISNT OFF),
05601           NCE_CANNOT_USE_XZ_PLANE_WITH_CUTTER_RADIUS_COMP);
05602       SELECT_PLANE(CANON_PLANE_XZ);
05603       settings->plane SET_TO CANON_PLANE_XZ;
05604     }
05605   else if (g_code IS G_19)
05606     {
05607       CHK((settings->cutter_comp_side ISNT OFF),
05608           NCE_CANNOT_USE_YZ_PLANE_WITH_CUTTER_RADIUS_COMP);
05609       SELECT_PLANE(CANON_PLANE_YZ);
05610       settings->plane SET_TO CANON_PLANE_YZ;
05611     }
05612   else
05613     ERM(NCE_BUG_CODE_NOT_G17_G18_OR_G19);
05614   return RS274NGC_OK;
05615 }
05616 
05617 /****************************************************************************/
05618 
05619 /* convert_speed
05620 
05621 Returned Value: int (RS274NGC_OK)
05622 
05623 Side effects:
05624   The machine spindle speed is set to the value of s_number in the
05625   block by a call to SET_SPINDLE_SPEED.
05626   The machine model for spindle speed is set to that value.
05627 
05628 Called by: execute_block.
05629 
05630 */
05631 
05632 static int convert_speed( /* ARGUMENTS                                */
05633  block_pointer block,     /* pointer to a block of RS274 instructions */
05634  setup_pointer settings)  /* pointer to machine settings              */
05635 {
05636   SET_SPINDLE_SPEED(block->s_number);
05637   settings->speed SET_TO block->s_number;
05638   return RS274NGC_OK;
05639 }
05640 
05641 /****************************************************************************/
05642 
05643 /* convert_stop
05644 
05645 Returned Value: int
05646    When an m2 or m30 (program_end) is encountered, this returns RS274NGC_EXIT.
05647    If the code is not m0, m1, m2, m30, or m60, this returns
05648    NCE_BUG_CODE_NOT_M0_M1_M2_M30_M60
05649    Otherwise, it returns RS274NGC_OK.
05650 
05651 Side effects:
05652    An m0, m1, m2, m30, or m60 in the block is executed.
05653 
05654    For m0, m1, and m60, this makes a function call to the PROGRAM_STOP
05655    canonical machining function (which stops program execution).
05656    In addition, m60 calls PALLET_SHUTTLE.
05657 
05658    For m2 and m30, this resets the machine and then calls PROGRAM_END.
05659    In addition, m30 calls PALLET_SHUTTLE.
05660 
05661 Called by: execute_block.
05662 
05663 This handles stopping or ending the program (m0, m1, m2, m30, m60)
05664 
05665 [NCMS] specifies how the following modes should be reset at m2 or
05666 m30. The descriptions are not collected in one place, so this list
05667 may be incomplete.
05668 
05669 G52 offsetting coordinate zero points [NCMS, page 10]
05670 G92 coordinate offset using tool position [NCMS, page 10]
05671 
05672 The following should have reset values, but no description of reset
05673 behavior could be found in [NCMS].
05674 G17, G18, G19 selected plane [NCMS, pages 14, 20]
05675 G90, G91 distance mode [NCMS, page 15]
05676 G93, G94 feed mode [NCMS, pages 35 - 37]
05677 M48, M49 overrides enabled, disabled [NCMS, pages 37 - 38]
05678 M3, M4, M5 spindle turning [NCMS, page 7]
05679 
05680 The following should be set to some value at machine start-up but
05681 not automatically reset by any of the stopping codes.
05682 1. G20, G21 length units [NCMS, page 15]. This is up to the installer.
05683 2. motion_control_mode. This is set in rs274ngc_init but not reset here.
05684    Might add it here.
05685 
05686 The following resets have been added by calling the appropriate
05687 canonical machining command and/or by resetting interpreter
05688 settings. They occur on M2 or M30.
05689 
05690 1. Axis offsets are set to zero (like g92.2) and      - SET_ORIGIN_OFFSETS
05691    origin offsets are set to the default (like G54)
05692 2. Selected plane is set to CANON_PLANE_XY (like G17) - SELECT_PLANE
05693 3. Distance mode is set to MODE_ABSOLUTE (like G90)   - no canonical call
05694 4. Feed mode is set to UNITS_PER_MINUTE (like G94)    - no canonical call
05695 5. Feed and speed overrides are set to ON (like M48)  - ENABLE_FEED_OVERRIDE
05696                                                       - ENABLE_SPEED_OVERRIDE
05697 6. Cutter compensation is turned off (like G40)       - no canonical call
05698 7. The spindle is stopped (like M5)                   - STOP_SPINDLE_TURNING
05699 8. The motion mode is set to G_1 (like G1)            - no canonical call
05700 9. Coolant is turned off (like M9)                    - FLOOD_OFF & MIST_OFF
05701 
05702 */
05703 
05704 static int convert_stop(  /* ARGUMENTS                                    */
05705  block_pointer block,     /* pointer to a block of RS274/NGC instructions */
05706  setup_pointer settings)  /* pointer to machine settings                  */
05707 {
05708   static char name[] SET_TO "convert_stop";
05709   int index;
05710   char * line;
05711   int length;
05712 
05713   if (block->m_modes[4] IS 0)
05714     {
05715       PROGRAM_STOP();
05716     }
05717   else if (block->m_modes[4] IS 60)
05718     {
05719       PALLET_SHUTTLE();
05720       PROGRAM_STOP();
05721     }
05722   else if (block->m_modes[4] IS 1)
05723     {
05724       OPTIONAL_PROGRAM_STOP();
05725     }
05726   else if ((block->m_modes[4] IS 2) OR (block->m_modes[4] IS 30))
05727     { /* reset stuff here */
05728 /*1*/
05729       settings->current_x SET_TO settings->current_x
05730         + settings->origin_offset_x + settings->axis_offset_x;
05731       settings->current_y SET_TO settings->current_y
05732         + settings->origin_offset_y + settings->axis_offset_y;
05733       settings->current_z SET_TO settings->current_z
05734         + settings->origin_offset_z + settings->axis_offset_z;
05735 #ifdef AA
05736       settings->AA_current SET_TO settings->AA_current              /*AA*/
05737 #endif
05738 #ifdef AA
05739         + settings->AA_origin_offset + settings->AA_axis_offset;    /*AA*/
05740 #endif
05741 #ifdef BB
05742       settings->BB_current SET_TO settings->BB_current              /*BB*/
05743 #endif
05744 #ifdef BB
05745         + settings->BB_origin_offset + settings->BB_axis_offset;    /*BB*/
05746 #endif
05747 #ifdef CC
05748       settings->CC_current SET_TO settings->CC_current              /*CC*/
05749 #endif
05750 #ifdef CC
05751         + settings->CC_origin_offset + settings->CC_axis_offset;    /*CC*/
05752 #endif
05753 
05754       settings->origin_index SET_TO 1;
05755       settings->parameters[5220] SET_TO 1.0;
05756       settings->origin_offset_x SET_TO settings->parameters[5221];
05757       settings->origin_offset_y SET_TO settings->parameters[5222];
05758       settings->origin_offset_z SET_TO settings->parameters[5223];
05759 #ifdef AA
05760       settings->AA_origin_offset SET_TO settings->parameters[5224]; /*AA*/
05761 #endif
05762 #ifdef BB
05763       settings->BB_origin_offset SET_TO settings->parameters[5225]; /*BB*/
05764 #endif
05765 #ifdef CC
05766       settings->CC_origin_offset SET_TO settings->parameters[5226]; /*CC*/
05767 #endif
05768 
05769       settings->axis_offset_x SET_TO 0;
05770       settings->axis_offset_x SET_TO 0;
05771       settings->axis_offset_x SET_TO 0;
05772 #ifdef AA
05773       settings->AA_axis_offset SET_TO 0;                            /*AA*/
05774 #endif
05775 #ifdef BB
05776       settings->BB_axis_offset SET_TO 0;                            /*BB*/
05777 #endif
05778 #ifdef CC
05779       settings->CC_axis_offset SET_TO 0;                            /*CC*/
05780 #endif
05781 
05782       settings->current_x SET_TO settings->current_x -
05783         settings->origin_offset_x;
05784       settings->current_y SET_TO settings->current_y -
05785         settings->origin_offset_y;
05786       settings->current_z SET_TO settings->current_z -
05787         settings->origin_offset_z;
05788 #ifdef AA
05789       settings->AA_current SET_TO settings->AA_current -            /*AA*/
05790 #endif
05791 #ifdef AA
05792         settings->AA_origin_offset;                                 /*AA*/
05793 #endif
05794 #ifdef BB
05795       settings->BB_current SET_TO settings->BB_current -            /*BB*/
05796 #endif
05797 #ifdef BB
05798         settings->BB_origin_offset;                                 /*BB*/
05799 #endif
05800 #ifdef CC
05801       settings->CC_current SET_TO settings->CC_current -            /*CC*/
05802 #endif
05803 #ifdef CC
05804         settings->CC_origin_offset;                                 /*CC*/
05805 #endif
05806 
05807       SET_ORIGIN_OFFSETS(settings->origin_offset_x,
05808                          settings->origin_offset_y,
05809                          settings->origin_offset_z
05810 #ifdef AA
05811 ,                        settings->AA_origin_offset
05812 #else
05813 #ifdef ALL_AXES
05814 , 0
05815 #endif
05816 #endif
05817 #ifdef BB
05818 ,                        settings->BB_origin_offset
05819 #else
05820 #ifdef ALL_AXES
05821 , 0
05822 #endif
05823 #endif
05824 #ifdef CC
05825 ,                        settings->CC_origin_offset
05826 #else
05827 #ifdef ALL_AXES
05828 , 0
05829 #endif
05830 #endif
05831 );
05832 
05833 /*2*/ if (settings->plane ISNT CANON_PLANE_XY)
05834         {
05835           SELECT_PLANE(CANON_PLANE_XY);
05836           settings->plane SET_TO CANON_PLANE_XY;
05837         }
05838 
05839 /*3*/ settings->distance_mode SET_TO MODE_ABSOLUTE;
05840 
05841 /*4*/ settings->feed_mode SET_TO UNITS_PER_MINUTE;
05842 
05843 /*5*/ if (settings->feed_override ISNT ON)
05844         {
05845           ENABLE_FEED_OVERRIDE();
05846           settings->feed_override SET_TO ON;
05847         }
05848       if (settings->speed_override ISNT ON)
05849         {
05850           ENABLE_SPEED_OVERRIDE();
05851           settings->speed_override SET_TO ON;
05852         }
05853 
05854 /*6*/ settings->cutter_comp_side SET_TO OFF;
05855       settings->program_x SET_TO UNKNOWN;
05856 
05857 /*7*/ STOP_SPINDLE_TURNING();
05858       settings->spindle_turning SET_TO CANON_STOPPED;
05859 
05860 /*8*/ settings->motion_mode SET_TO G_1;
05861 
05862 /*9*/ if (settings->mist IS ON)
05863         {
05864           MIST_OFF();
05865           settings->mist SET_TO OFF;
05866         }
05867       if (settings->flood IS ON)
05868         {
05869           FLOOD_OFF();
05870           settings->flood SET_TO OFF;
05871         }
05872 
05873       if (block->m_modes[4] IS 30)
05874         PALLET_SHUTTLE();
05875       PROGRAM_END();
05876       if (_setup.percent_flag IS ON)
05877         {
05878           CHK((_setup.file_pointer IS NULL), NCE_UNABLE_TO_OPEN_FILE);
05879           line SET_TO _setup.linetext;
05880           for(; ;) /* check for ending percent sign and comment if missing */
05881             {
05882               if (fgets(line, RS274NGC_TEXT_SIZE, _setup.file_pointer) IS NULL)
05883                 {
05884                   COMMENT
05885                     ("interpreter: percent sign missing from end of file");
05886                   break;
05887                 }
05888               length SET_TO strlen(line);
05889               if (length IS (RS274NGC_TEXT_SIZE - 1))
05890                 { // line is too long. need to finish reading the line
05891                   for(;fgetc(_setup.file_pointer) ISNT '\n';);
05892                   continue;
05893                 }
05894               for(index SET_TO (length -1); // index set on last char
05895                   (index >= 0) AND (isspace(line[index]));
05896                   index--);
05897               if (line[index] IS '%') // found line with % at end
05898                 {
05899                   for(index--; (index >= 0)AND(isspace(line[index])); index--);
05900                   if (index IS -1) // found line with only percent sign
05901                     break;
05902                 }
05903             }
05904         }
05905       return RS274NGC_EXIT;
05906     }
05907   else
05908     ERM(NCE_BUG_CODE_NOT_M0_M1_M2_M30_M60);
05909   return RS274NGC_OK;
05910 }
05911 
05912 /****************************************************************************/
05913 
05914 /* convert_straight
05915 
05916 Returned Value: int
05917    If convert_straight_comp1 or convert_straight_comp2 is called
05918    and returns an error code, this returns that code.
05919    If any of the following errors occur, this returns the error shown.
05920    Otherwise, it returns RS274NGC_OK.
05921    1. x, y, z, a, b, and c are all missing from the block:
05922       NCE_ALL_AXES_MISSING_WITH_G0_OR_G1
05923    2. The value of move is not G_0 or G_1:
05924       NCE_BUG_CODE_NOT_G0_OR_G1
05925    3. A straight feed (g1) move is called with feed rate set to 0:
05926       NCE_CANNOT_DO_G1_WITH_ZERO_FEED_RATE
05927    4. A straight feed (g1) move is called with inverse time feed in effect
05928       but no f word (feed time) is provided:
05929       NCE_F_WORD_MISSING_WITH_INVERSE_TIME_G1_MOVE
05930    5. A move is called with G53 and cutter radius compensation on:
05931       NCE_CANNOT_USE_G53_WITH_CUTTER_RADIUS_COMP
05932 
05933 Side effects:
05934    This executes a STRAIGHT_FEED command at cutting feed rate
05935    (if move is G_1) or a STRAIGHT_TRAVERSE command (if move is G_0).
05936    It also updates the setting of the position of the tool point to the
05937    end point of the move. If cutter radius compensation is on, it may
05938    also generate an arc before the straight move. Also, in INVERSE_TIME
05939    feed mode, SET_FEED_RATE will be called the feed rate setting changed.
05940 
05941 Called by: convert_motion.
05942 
05943 The approach to operating in incremental distance mode (g91) is to
05944 put the the absolute position values into the block before using the
05945 block to generate a move.
05946 
05947 In inverse time feed mode, a lower bound of 0.1 is placed on the feed
05948 rate so that the feed rate is never set to zero. If the destination
05949 point is the same as the current point, the feed rate would be
05950 calculated as zero otherwise.
05951 
05952 */
05953 
05954 static int convert_straight( /* ARGUMENTS                                */
05955  int move,                   /* either G_0 or G_1                        */
05956  block_pointer block,        /* pointer to a block of RS274 instructions */
05957  setup_pointer settings)     /* pointer to machine settings              */
05958 {
05959   static char name[] SET_TO "convert_straight";
05960   double end_x;
05961   double end_y;
05962   double end_z;
05963 #ifdef AA
05964   double AA_end;        /*AA*/
05965 #endif
05966 #ifdef BB
05967   double BB_end;        /*BB*/
05968 #endif
05969 #ifdef CC
05970   double CC_end;        /*CC*/
05971 #endif
05972   int status;
05973 
05974   if (move IS G_1)
05975     {
05976       if (settings->feed_mode IS UNITS_PER_MINUTE)
05977         {
05978           CHK((settings->feed_rate IS 0.0),
05979               NCE_CANNOT_DO_G1_WITH_ZERO_FEED_RATE);
05980         }
05981       else if (settings->feed_mode IS INVERSE_TIME)
05982         {
05983           CHK((block->f_number IS -1.0),
05984               NCE_F_WORD_MISSING_WITH_INVERSE_TIME_G1_MOVE);
05985         }
05986     }
05987 
05988   settings->motion_mode SET_TO move;
05989   find_ends(block, settings, &end_x, &end_y,
05990             &end_z
05991 #ifdef AA
05992 , &AA_end
05993 #endif
05994 
05995 #ifdef BB
05996 , &BB_end
05997 #endif
05998 
05999 #ifdef CC
06000 , &CC_end
06001 #endif
06002 );
06003   if ((settings->cutter_comp_side ISNT OFF) AND /* NOT "IS ON" */
06004       (settings->cutter_comp_radius > 0.0))     /* radius always is >= 0 */
06005     {
06006       CHK((block->g_modes[0] IS G_53),
06007           NCE_CANNOT_USE_G53_WITH_CUTTER_RADIUS_COMP);
06008       if (settings->program_x IS UNKNOWN)
06009         {
06010           status SET_TO
06011             convert_straight_comp1(move, block, settings, end_x, end_y,
06012                                    end_z
06013 #ifdef AA
06014 , AA_end
06015 #endif
06016 
06017 #ifdef BB
06018 , BB_end
06019 #endif
06020 
06021 #ifdef CC
06022 , CC_end
06023 #endif
06024 );
06025           CHP(status);
06026         }
06027       else
06028         {
06029           status SET_TO
06030             convert_straight_comp2 (move, block, settings, end_x, end_y,
06031                                     end_z
06032 #ifdef AA
06033 , AA_end
06034 #endif
06035 
06036 #ifdef BB
06037 , BB_end
06038 #endif
06039 
06040 #ifdef CC
06041 , CC_end
06042 #endif
06043 );
06044           CHP(status);
06045         }
06046     }
06047   else if (move IS G_0)
06048     {
06049       STRAIGHT_TRAVERSE(end_x, end_y, end_z
06050 #ifdef AA
06051 ,                       AA_end
06052 #else
06053 #ifdef ALL_AXES
06054 , 0
06055 #endif
06056 #endif
06057 #ifdef BB
06058 ,  BB_end
06059 #else
06060 #ifdef ALL_AXES
06061 , 0
06062 #endif
06063 #endif
06064 #ifdef CC
06065 ,  CC_end
06066 #else
06067 #ifdef ALL_AXES
06068 , 0
06069 #endif
06070 #endif
06071 );
06072       settings->current_x SET_TO end_x;
06073       settings->current_y SET_TO end_y;
06074     }
06075   else if (move IS G_1)
06076     {
06077       if (settings->feed_mode IS INVERSE_TIME)
06078         inverse_time_rate_straight
06079           (end_x, end_y, end_z
06080 #ifdef AA
06081 , AA_end
06082 #endif
06083 
06084 #ifdef BB
06085 , BB_end
06086 #endif
06087 
06088 #ifdef CC
06089 , CC_end
06090 #endif
06091 , block, settings);
06092       STRAIGHT_FEED(end_x, end_y, end_z
06093 #ifdef AA
06094 ,                   AA_end
06095 #else
06096 #ifdef ALL_AXES
06097 , 0
06098 #endif
06099 #endif
06100 #ifdef BB
06101 ,  BB_end
06102 #else
06103 #ifdef ALL_AXES
06104 , 0
06105 #endif
06106 #endif
06107 #ifdef CC
06108 ,  CC_end
06109 #else
06110 #ifdef ALL_AXES
06111 , 0
06112 #endif
06113 #endif
06114 );
06115       settings->current_x SET_TO end_x;
06116       settings->current_y SET_TO end_y;
06117     }
06118   else
06119     ERM(NCE_BUG_CODE_NOT_G0_OR_G1);
06120 
06121   settings->current_z SET_TO end_z;
06122 #ifdef AA
06123   settings->AA_current SET_TO AA_end;                           /*AA*/
06124 #endif
06125 #ifdef BB
06126   settings->BB_current SET_TO BB_end;                           /*BB*/
06127 #endif
06128 #ifdef CC
06129   settings->CC_current SET_TO CC_end;                           /*CC*/
06130 #endif
06131   return RS274NGC_OK;
06132 }
06133 
06134 /****************************************************************************/
06135 
06136 /* convert_straight_comp1
06137 
06138 Returned Value: int
06139    If any of the following errors occur, this returns the error shown.
06140    Otherwise, it returns RS274NGC_OK.
06141    1. The side is not RIGHT or LEFT:
06142       NCE_BUG_SIDE_NOT_RIGHT_OR_LEFT
06143    2. The destination tangent point is not more than a tool radius
06144       away (indicating gouging): NCE_CUTTER_GOUGING_WITH_CUTTER_RADIUS_COMP
06145    3. The value of move is not G_0 or G_1
06146       NCE_BUG_CODE_NOT_G0_OR_G1
06147 
06148 Side effects:
06149    This executes a STRAIGHT_MOVE command at cutting feed rate
06150    or a STRAIGHT_TRAVERSE command.
06151    It also updates the setting of the position of the tool point
06152    to the end point of the move and updates the programmed point.
06153    If INVERSE_TIME feed rate mode is in effect, it resets the feed rate.
06154 
06155 Called by: convert_straight.
06156 
06157 This is called if cutter radius compensation is on and settings->program_x
06158 is UNKNOWN, indicating that this is the first move after cutter radius
06159 compensation is turned on.
06160 
06161 The algorithm used here for determining the path is to draw a straight
06162 line from the destination point which is tangent to a circle whose
06163 center is at the current point and whose radius is the radius of the
06164 cutter. The destination point of the cutter tip is then found as the
06165 center of a circle of the same radius tangent to the tangent line at
06166 the destination point.
06167 
06168 */
06169 
06170 static int convert_straight_comp1( /* ARGUMENTS                       */
06171  int move,               /* either G_0 or G_1                         */
06172  block_pointer block,    /* pointer to a block of RS274 instructions  */
06173  setup_pointer settings, /* pointer to machine settings               */
06174  double px,              /* X coordinate of end point                 */
06175  double py,              /* Y coordinate of end point                 */
06176  double end_z            /* Z coordinate of end point                 */
06177 #ifdef AA
06178  , double AA_end         /* A coordinate of end point           *//*AA*/
06179 #endif
06180 #ifdef BB
06181  , double BB_end         /* B coordinate of end point           *//*BB*/
06182 #endif
06183 #ifdef CC
06184  , double CC_end         /* C coordinate of end point           *//*CC*/
06185 #endif
06186 )
06187 {
06188   static char name[] SET_TO "convert_straight_comp1";
06189   double alpha;
06190   double cx;        /* first current point x then end point x */
06191   double cy;        /* first current point y then end point y */
06192   double distance;
06193   double radius;
06194   int side;
06195   double theta;
06196 
06197   side SET_TO settings->cutter_comp_side;
06198   cx SET_TO settings->current_x;
06199   cy SET_TO settings->current_y;
06200 
06201   radius SET_TO settings->cutter_comp_radius; /* always will be positive */
06202   distance SET_TO hypot((px - cx), (py -cy));
06203 
06204   CHK(((side ISNT LEFT) AND (side ISNT RIGHT)),NCE_BUG_SIDE_NOT_RIGHT_OR_LEFT);
06205   CHK((distance <= radius), NCE_CUTTER_GOUGING_WITH_CUTTER_RADIUS_COMP);
06206 
06207   theta SET_TO acos(radius/distance);
06208   alpha SET_TO (side IS LEFT) ? (atan2((cy - py), (cx - px)) - theta) :
06209                                 (atan2((cy - py), (cx - px)) + theta);
06210   cx SET_TO (px + (radius * cos(alpha))); /* reset to end location */
06211   cy SET_TO (py + (radius * sin(alpha)));
06212   if (move IS G_0)
06213     STRAIGHT_TRAVERSE(cx, cy, end_z
06214 #ifdef AA
06215 ,                     AA_end
06216 #else
06217 #ifdef ALL_AXES
06218 , 0
06219 #endif
06220 #endif
06221 #ifdef BB
06222 ,  BB_end
06223 #else
06224 #ifdef ALL_AXES
06225 , 0
06226 #endif
06227 #endif
06228 #ifdef CC
06229 ,  CC_end
06230 #else
06231 #ifdef ALL_AXES
06232 , 0
06233 #endif
06234 #endif
06235 );
06236   else if (move IS G_1)
06237     {
06238       if (settings->feed_mode IS INVERSE_TIME)
06239         inverse_time_rate_straight
06240           (cx, cy, end_z
06241 #ifdef AA
06242 , AA_end
06243 #endif
06244 
06245 #ifdef BB
06246 , BB_end
06247 #endif
06248 
06249 #ifdef CC
06250 , CC_end
06251 #endif
06252 , block, settings);
06253       STRAIGHT_FEED(cx, cy, end_z
06254 #ifdef AA
06255 ,                   AA_end
06256 #else
06257 #ifdef ALL_AXES
06258 , 0
06259 #endif
06260 #endif
06261 #ifdef BB
06262 ,  BB_end
06263 #else
06264 #ifdef ALL_AXES
06265 , 0
06266 #endif
06267 #endif
06268 #ifdef CC
06269 ,  CC_end
06270 #else
06271 #ifdef ALL_AXES
06272 , 0
06273 #endif
06274 #endif
06275 );
06276     }
06277   else
06278     ERM(NCE_BUG_CODE_NOT_G0_OR_G1);
06279 
06280   settings->current_x SET_TO cx;
06281   settings->current_y SET_TO cy;
06282   settings->program_x SET_TO px;
06283   settings->program_y SET_TO py;
06284   return RS274NGC_OK;
06285 }
06286 
06287 /****************************************************************************/
06288 
06289 /* convert_straight_comp2
06290 
06291 Returned Value: int
06292    If any of the following errors occur, this returns the error shown.
06293    Otherwise, it returns RS274NGC_OK.
06294    1. The compensation side is not RIGHT or LEFT:
06295       NCE_BUG_SIDE_NOT_RIGHT_OR_LEFT
06296    2. A concave corner is found:
06297       NCE_CONCAVE_CORNER_WITH_CUTTER_RADIUS_COMP
06298 
06299 Side effects:
06300    This executes a STRAIGHT_FEED command at cutting feed rate
06301    or a STRAIGHT_TRAVERSE command.
06302    It also generates an ARC_FEED to go around a corner, if necessary.
06303    It also updates the setting of the position of the tool point to
06304    the end point of the move and updates the programmed point.
06305    If INVERSE_TIME feed mode is in effect, it also calls SET_FEED_RATE
06306    and resets the feed rate in the machine model.
06307 
06308 Called by: convert_straight.
06309 
06310 This is called if cutter radius compensation is on and
06311 settings->program_x is not UNKNOWN, indicating that this is not the
06312 first move after cutter radius compensation is turned on.
06313 
06314 The algorithm used here is:
06315 1. Determine the direction of the last motion. This is done by finding
06316    the direction of the line from the last programmed point to the
06317    current tool tip location. This line is a radius of the tool and is
06318    perpendicular to the direction of motion since the cutter is tangent
06319    to that direction.
06320 2. Determine the direction of the programmed motion.
06321 3. If there is a convex corner, insert an arc to go around the corner.
06322 4. Find the destination point for the tool tip. The tool will be
06323    tangent to the line from the last programmed point to the present
06324    programmed point at the present programmed point.
06325 5. Go in a straight line from the current tool tip location to the
06326    destination tool tip location.
06327 
06328 This uses an angle tolerance of TOLERANCE_CONCAVE_CORNER (0.01 radian)
06329 to determine if:
06330 1) an illegal concave corner exists (tool will not fit into corner),
06331 2) no arc is required to go around the corner (i.e. the current line
06332    is in the same direction as the end of the previous move), or
06333 3) an arc is required to go around a convex corner and start off in
06334    a new direction.
06335 
06336 If a rotary axis is moved in this block and an extra arc is required
06337 to go around a sharp corner, all the rotary axis motion occurs on the
06338 arc.  An alternative might be to distribute the rotary axis motion
06339 over the arc and the straight move in proportion to their lengths.
06340 
06341 If the Z-axis is moved in this block and an extra arc is required to
06342 go around a sharp corner, all the Z-axis motion occurs on the straight
06343 line and none on the extra arc.  An alternative might be to distribute
06344 the Z-axis motion over the extra arc and the straight line in
06345 proportion to their lengths.
06346 
06347 This handles inverse time feed rates by computing the length of the
06348 compensated path.
06349 
06350 This handles the case of there being no XY motion.
06351 
06352 This handles G0 moves. Where an arc is inserted to round a corner in a
06353 G1 move, no arc is inserted for a G0 move; a STRAIGHT_TRAVERSE is made
06354 from the current point to the end point. The end point for a G0
06355 move is the same as the end point for a G1 move, however.
06356 
06357 */
06358 
06359 static int convert_straight_comp2( /* ARGUMENTS                       */
06360  int move,               /* either G_0 or G_1                         */
06361  block_pointer block,    /* pointer to a block of RS274 instructions  */
06362  setup_pointer settings, /* pointer to machine settings               */
06363  double px,              /* X coordinate of programmed end point      */
06364  double py,              /* Y coordinate of programmed end point      */
06365  double end_z            /* Z coordinate of end point                 */
06366 #ifdef AA
06367  , double AA_end         /* A coordinate of end point           *//*AA*/
06368 #endif
06369 #ifdef BB
06370  , double BB_end         /* B coordinate of end point           *//*BB*/
06371 #endif
06372 #ifdef CC
06373  , double CC_end         /* C coordinate of end point           *//*CC*/
06374 #endif
06375 )
06376 {
06377   static char name[] SET_TO "convert_straight_comp2";
06378   double alpha;
06379   double beta;
06380   double end_x; /* x-coordinate of actual end point */
06381   double end_y; /* y-coordinate of actual end point */
06382   double gamma;
06383   double mid_x; /* x-coordinate of end of added arc, if needed */
06384   double mid_y; /* y-coordinate of end of added arc, if needed */
06385   double radius;
06386   int side;
06387   double small SET_TO TOLERANCE_CONCAVE_CORNER; /* radians, testing corners */
06388   double start_x, start_y; /* programmed beginning point */
06389   double theta;
06390 
06391   start_x SET_TO settings->program_x;
06392   start_y SET_TO settings->program_y;
06393   if ((py IS start_y) AND (px IS start_x)) /* no XY motion */
06394     {
06395       end_x SET_TO settings->current_x;
06396       end_y SET_TO settings->current_y;
06397       if (move IS G_0)
06398         STRAIGHT_TRAVERSE(end_x, end_y, end_z
06399 #ifdef AA
06400 ,                         AA_end
06401 #else
06402 #ifdef ALL_AXES
06403 , 0
06404 #endif
06405 #endif
06406 #ifdef BB
06407 ,  BB_end
06408 #else
06409 #ifdef ALL_AXES
06410 , 0
06411 #endif
06412 #endif
06413 #ifdef CC
06414 ,  CC_end
06415 #else
06416 #ifdef ALL_AXES
06417 , 0
06418 #endif
06419 #endif
06420 );
06421       else if (move IS G_1)
06422         {
06423           if (settings->feed_mode IS INVERSE_TIME)
06424             inverse_time_rate_straight
06425               (end_x, end_y, end_z
06426 #ifdef AA
06427 , AA_end
06428 #endif
06429 
06430 #ifdef BB
06431 , BB_end
06432 #endif
06433 
06434 #ifdef CC
06435 , CC_end
06436 #endif
06437 , block, settings);
06438           STRAIGHT_FEED(end_x, end_y, end_z
06439 #ifdef AA
06440 ,                       AA_end
06441 #else
06442 #ifdef ALL_AXES
06443 , 0
06444 #endif
06445 #endif
06446 #ifdef BB
06447 ,  BB_end
06448 #else
06449 #ifdef ALL_AXES
06450 , 0
06451 #endif
06452 #endif
06453 #ifdef CC
06454 ,  CC_end
06455 #else
06456 #ifdef ALL_AXES
06457 , 0
06458 #endif
06459 #endif
06460 );
06461         }
06462       else
06463         ERM(NCE_BUG_CODE_NOT_G0_OR_G1);
06464     }
06465   else
06466     {
06467       side SET_TO settings->cutter_comp_side;
06468       radius SET_TO settings->cutter_comp_radius; /* will always be positive */
06469       theta SET_TO atan2(settings->current_y - start_y,
06470                          settings->current_x - start_x);
06471       alpha SET_TO atan2(py - start_y, px - start_x);
06472 
06473       if (side IS LEFT)
06474         {
06475           if (theta < alpha)
06476             theta SET_TO (theta + TWO_PI);
06477           beta SET_TO ((theta - alpha) - PI2);
06478           gamma SET_TO PI2;
06479         }
06480       else if (side IS RIGHT)
06481         {
06482           if (alpha < theta)
06483             alpha SET_TO (alpha + TWO_PI);
06484           beta SET_TO ((alpha - theta) - PI2);
06485           gamma SET_TO -PI2;
06486         }
06487       else
06488         ERM(NCE_BUG_SIDE_NOT_RIGHT_OR_LEFT);
06489       end_x SET_TO (px + (radius * cos(alpha + gamma)));
06490       end_y SET_TO (py + (radius * sin(alpha + gamma)));
06491       mid_x SET_TO (start_x + (radius * cos(alpha + gamma)));
06492       mid_y SET_TO (start_y + (radius * sin(alpha + gamma)));
06493 
06494       CHK(((beta < -small) OR (beta > (PI + small))),
06495           NCE_CONCAVE_CORNER_WITH_CUTTER_RADIUS_COMP);
06496       if (move IS G_0)
06497         STRAIGHT_TRAVERSE(end_x, end_y, end_z
06498 #ifdef AA
06499 ,                         AA_end
06500 #else
06501 #ifdef ALL_AXES
06502 , 0
06503 #endif
06504 #endif
06505 #ifdef BB
06506 ,  BB_end
06507 #else
06508 #ifdef ALL_AXES
06509 , 0
06510 #endif
06511 #endif
06512 #ifdef CC
06513 ,  CC_end
06514 #else
06515 #ifdef ALL_AXES
06516 , 0
06517 #endif
06518 #endif
06519 );
06520       else if (move IS G_1)
06521         {
06522           if (beta > small) /* ARC NEEDED */
06523             {
06524               if (settings->feed_mode IS INVERSE_TIME)
06525                 inverse_time_rate_as(start_x, start_y, (side IS LEFT) ? -1 : 1,
06526                                      mid_x, mid_y, end_x, end_y,
06527                                      end_z
06528 #ifdef AA
06529 , AA_end
06530 #endif
06531 
06532 #ifdef BB
06533 , BB_end
06534 #endif
06535 
06536 #ifdef CC
06537 , CC_end
06538 #endif
06539 ,
06540                                      block, settings);
06541               ARC_FEED(mid_x,mid_y,start_x, start_y,((side IS LEFT) ? -1 : 1),
06542                        settings->current_z
06543 #ifdef AA
06544 , AA_end
06545 #else
06546 #ifdef ALL_AXES
06547 , 0
06548 #endif
06549 #endif
06550 #ifdef BB
06551 , BB_end
06552 #else
06553 #ifdef ALL_AXES
06554 , 0
06555 #endif
06556 #endif
06557 #ifdef CC
06558 , CC_end
06559 #else
06560 #ifdef ALL_AXES
06561 , 0
06562 #endif
06563 #endif
06564 );
06565               STRAIGHT_FEED(end_x, end_y, end_z
06566 #ifdef AA
06567 ,                           AA_end
06568 #else
06569 #ifdef ALL_AXES
06570 , 0
06571 #endif
06572 #endif
06573 #ifdef BB
06574 ,  BB_end
06575 #else
06576 #ifdef ALL_AXES
06577 , 0
06578 #endif
06579 #endif
06580 #ifdef CC
06581 ,  CC_end
06582 #else
06583 #ifdef ALL_AXES
06584 , 0
06585 #endif
06586 #endif
06587 );
06588             }
06589           else
06590             {
06591               if (settings->feed_mode IS INVERSE_TIME)
06592                 inverse_time_rate_straight
06593                   (end_x,end_y,end_z
06594 #ifdef AA
06595 , AA_end
06596 #endif
06597 
06598 #ifdef BB
06599 , BB_end
06600 #endif
06601 
06602 #ifdef CC
06603 , CC_end
06604 #endif
06605 , block, settings);
06606               STRAIGHT_FEED(end_x, end_y, end_z
06607 #ifdef AA
06608 ,                           AA_end
06609 #else
06610 #ifdef ALL_AXES
06611 , 0
06612 #endif
06613 #endif
06614 #ifdef BB
06615 ,  BB_end
06616 #else
06617 #ifdef ALL_AXES
06618 , 0
06619 #endif
06620 #endif
06621 #ifdef CC
06622 ,  CC_end
06623 #else
06624 #ifdef ALL_AXES
06625 , 0
06626 #endif
06627 #endif
06628 );
06629             }
06630         }
06631       else
06632         ERM(NCE_BUG_CODE_NOT_G0_OR_G1);
06633     }
06634 
06635   settings->current_x SET_TO end_x;
06636   settings->current_y SET_TO end_y;
06637   settings->program_x SET_TO px;
06638   settings->program_y SET_TO py;
06639   return RS274NGC_OK;
06640 }
06641 
06642 /****************************************************************************/
06643 
06644 /* convert_tool_change
06645 
06646 Returned Value: int (RS274NGC_OK)
06647 
06648 Side effects:
06649    This makes function calls to canonical machining functions, and sets
06650    the machine model as described below.
06651 
06652 Called by: convert_m
06653 
06654 This function carries out an m6 command, which changes the tool in the
06655 spindle. The only function call this makes is to the CHANGE_TOOL
06656 function. The semantics of this function call is that when it is
06657 completely carried out, the tool that was selected is in the spindle,
06658 the tool that was in the spindle (if any) is returned to its changer
06659 slot, the spindle will be stopped (but the spindle speed setting will
06660 not have changed) and the x, y, z, a, b, and c positions will be the same
06661 as they were before (although they may have moved around during the
06662 change).
06663 
06664 It would be nice to add more flexibility to this function by allowing
06665 more changes to occur (position changes, for example) as a result of
06666 the tool change. There are at least two ways of doing this:
06667 
06668 1. Require that certain machine settings always have a given fixed
06669 value after a tool change (which may be different from what the value
06670 was before the change), and record the fixed values somewhere (in the
06671 world model that is read at initialization, perhaps) so that this
06672 function can retrieve them and reset any settings that have changed.
06673 Fixed values could even be hard coded in this function.
06674 
06675 2. Allow the executor of the CHANGE_TOOL function to change the state
06676 of the world however it pleases, and have the interpreter read the
06677 executor's world model after the CHANGE_TOOL function is carried out.
06678 Implementing this would require a change in other parts of the EMC
06679 system, since calls to the interpreter would then have to be
06680 interleaved with execution of the function calls output by the
06681 interpreter.
06682 
06683 There may be other commands in the block that includes the tool change.
06684 They will be executed in the order described in execute_block.
06685 
06686 This implements the "Next tool in T word" approach to tool selection.
06687 The tool is selected when the T word is read (and the carousel may
06688 move at that time) but is changed when M6 is read.
06689 
06690 Note that if a different tool is put into the spindle, the current_z
06691 location setting may be incorrect for a time. It is assumed the
06692 program will contain an appropriate USE_TOOL_LENGTH_OFFSET command
06693 near the CHANGE_TOOL command, so that the incorrect setting is only
06694 temporary.
06695 
06696 In [NCMS, page 73, 74] there are three other legal approaches in addition
06697 to this one.
06698 
06699 */
06700 
06701 static int convert_tool_change( /* ARGUMENTS                   */
06702  setup_pointer settings)        /* pointer to machine settings */
06703 {
06704   static char name[] SET_TO "convert_tool_change";
06705 
06706   CHANGE_TOOL(settings->selected_tool_slot);
06707   settings->current_slot SET_TO settings->selected_tool_slot;
06708   settings->spindle_turning SET_TO CANON_STOPPED;
06709 
06710   return RS274NGC_OK;
06711 }
06712 
06713 /****************************************************************************/
06714 
06715 /* convert_tool_length_offset
06716 
06717 Returned Value: int
06718    If any of the following errors occur, this returns the error code shown.
06719    Otherwise, it returns RS274NGC_OK.
06720    1. The block has no offset index (h number): NCE_OFFSET_INDEX_MISSING
06721    2. The g_code argument is not G_43 or G_49:
06722       NCE_BUG_CODE_NOT_G43_OR_G49
06723 
06724 Side effects:
06725    A USE_TOOL_LENGTH_OFFSET function call is made. Current_z,
06726    tool_length_offset, and length_offset_index are reset.
06727 
06728 Called by: convert_g
06729 
06730 This is called to execute g43 or g49.
06731 
06732 The g49 RS274/NGC command translates into a USE_TOOL_LENGTH_OFFSET(0.0)
06733 function call.
06734 
06735 The g43 RS274/NGC command translates into a USE_TOOL_LENGTH_OFFSET(length)
06736 function call, where length is the value of the entry in the tool length
06737 offset table whose index is the H number in the block.
06738 
06739 The H number in the block (if present) was checked for being a non-negative
06740 integer when it was read, so that check does not need to be repeated.
06741 
06742 */
06743 
06744 static int convert_tool_length_offset( /* ARGUMENTS                      */
06745  int g_code,             /* g_code being executed (must be G_43 or G_49) */
06746  block_pointer block,    /* pointer to a block of RS274/NGC instructions */
06747  setup_pointer settings) /* pointer to machine settings                  */
06748 {
06749   static char name[] SET_TO "convert_tool_length_offset";
06750   int index;
06751   double offset;
06752 
06753   if (g_code IS G_49)
06754     {
06755       USE_TOOL_LENGTH_OFFSET(0.0);
06756       settings->current_z SET_TO (settings->current_z +
06757                                   settings->tool_length_offset);
06758       settings->tool_length_offset SET_TO 0.0;
06759       settings->length_offset_index SET_TO 0;
06760     }
06761   else if (g_code IS G_43)
06762     {
06763       index SET_TO block->h_number;
06764       CHK((index IS -1), NCE_OFFSET_INDEX_MISSING);
06765       offset SET_TO settings->tool_table[index].length;
06766       USE_TOOL_LENGTH_OFFSET(offset);
06767       settings->current_z SET_TO
06768         (settings->current_z + settings->tool_length_offset - offset);
06769       settings->tool_length_offset SET_TO offset;
06770       settings->length_offset_index SET_TO index;
06771     }
06772   else
06773     ERM(NCE_BUG_CODE_NOT_G43_OR_G49);
06774   return RS274NGC_OK;
06775 }
06776 
06777 /****************************************************************************/
06778 
06779 /* convert_tool_select
06780 
06781 Returned Value: int
06782    If the tool slot given in the block is larger than allowed,
06783    this returns NCE_SELECTED_TOOL_SLOT_NUMBER_TOO_LARGE.
06784    Otherwise, it returns RS274NGC_OK.
06785 
06786 Side effects: See below
06787 
06788 Called by: execute_block
06789 
06790 A select tool command is given, which causes the changer chain to move
06791 so that the slot with the t_number given in the block is next to the
06792 tool changer, ready for a tool change.  The
06793 settings->selected_tool_slot is set to the given slot.
06794 
06795 An alternative in this function is to select by tool id. This was used
06796 in the K&T and VGER interpreters. It is easy to code.
06797 
06798 A check that the t_number is not negative has already been made in read_t.
06799 A zero t_number is allowed and means no tool should be selected.
06800 
06801 */
06802 
06803 static int convert_tool_select( /* ARGUMENTS                                */
06804  block_pointer block,           /* pointer to a block of RS274 instructions */
06805  setup_pointer settings)        /* pointer to machine settings              */
06806 {
06807   static char name[] SET_TO "convert_tool_select";
06808 
06809   CHK((block->t_number > settings->tool_max),
06810       NCE_SELECTED_TOOL_SLOT_NUMBER_TOO_LARGE);
06811   SELECT_TOOL(block->t_number);
06812   settings->selected_tool_slot SET_TO block->t_number;
06813   return RS274NGC_OK;
06814 }
06815 
06816 /****************************************************************************/
06817 
06818 /* cycle_feed
06819 
06820 Returned Value: int (RS274NGC_OK)
06821 
06822 Side effects:
06823   STRAIGHT_FEED is called.
06824 
06825 Called by:
06826   convert_cycle_g81
06827   convert_cycle_g82
06828   convert_cycle_g83
06829   convert_cycle_g84
06830   convert_cycle_g85
06831   convert_cycle_g86
06832   convert_cycle_g87
06833   convert_cycle_g88
06834   convert_cycle_g89
06835 
06836 This writes a STRAIGHT_FEED command appropriate for a cycle move with
06837 respect to the given plane. No rotary axis motion takes place.
06838 
06839 */
06840 
06841 static int cycle_feed( /* ARGUMENTS                  */
06842  CANON_PLANE plane,    /* currently selected plane   */
06843  double end1,          /* first coordinate value     */
06844  double end2,          /* second coordinate value    */
06845  double end3)          /* third coordinate value     */
06846 {
06847   static char name[] SET_TO "cycle_feed";
06848 
06849   if (plane IS CANON_PLANE_XY)
06850     STRAIGHT_FEED(end1, end2, end3
06851 #ifdef AA
06852 ,                 _setup.AA_current
06853 #else
06854 #ifdef ALL_AXES
06855 , 0
06856 #endif
06857 #endif
06858 #ifdef BB
06859 ,  _setup.BB_current
06860 #else
06861 #ifdef ALL_AXES
06862 , 0
06863 #endif
06864 #endif
06865 #ifdef CC
06866 ,  _setup.CC_current
06867 #else
06868 #ifdef ALL_AXES
06869 , 0
06870 #endif
06871 #endif
06872 );
06873   else if (plane IS CANON_PLANE_YZ)
06874     STRAIGHT_FEED(end3, end1, end2
06875 #ifdef AA
06876 ,                 _setup.AA_current
06877 #else
06878 #ifdef ALL_AXES
06879 , 0
06880 #endif
06881 #endif
06882 #ifdef BB
06883 ,  _setup.BB_current
06884 #else
06885 #ifdef ALL_AXES
06886 , 0
06887 #endif
06888 #endif
06889 #ifdef CC
06890 ,  _setup.CC_current
06891 #else
06892 #ifdef ALL_AXES
06893 , 0
06894 #endif
06895 #endif
06896 );
06897   else /* if (plane IS CANON_PLANE_XZ) */
06898     STRAIGHT_FEED(end2, end3, end1
06899 #ifdef AA
06900 ,                 _setup.AA_current
06901 #else
06902 #ifdef ALL_AXES
06903 , 0
06904 #endif
06905 #endif
06906 #ifdef BB
06907 ,  _setup.BB_current
06908 #else
06909 #ifdef ALL_AXES
06910 , 0
06911 #endif
06912 #endif
06913 #ifdef CC
06914 ,  _setup.CC_current
06915 #else
06916 #ifdef ALL_AXES
06917 , 0
06918 #endif
06919 #endif
06920 );
06921 
06922   return RS274NGC_OK;
06923 }
06924 
06925 /****************************************************************************/
06926 
06927 /* cycle_traverse
06928 
06929 Returned Value: int (RS274NGC_OK)
06930 
06931 Side effects:
06932   STRAIGHT_TRAVERSE is called.
06933 
06934 Called by:
06935   convert_cycle
06936   convert_cycle_g81
06937   convert_cycle_g82
06938   convert_cycle_g83
06939   convert_cycle_g86
06940   convert_cycle_g87
06941   convert_cycle_xy (via CYCLE_MACRO)
06942   convert_cycle_yz (via CYCLE_MACRO)
06943   convert_cycle_zx (via CYCLE_MACRO)
06944 
06945 This writes a STRAIGHT_TRAVERSE command appropriate for a cycle
06946 move with respect to the given plane. No rotary axis motion takes place.
06947 
06948 */
06949 
06950 static int cycle_traverse( /* ARGUMENTS                 */
06951  CANON_PLANE plane,        /* currently selected plane  */
06952  double end1,              /* first coordinate value    */
06953  double end2,              /* second coordinate value   */
06954  double end3)              /* third coordinate value    */
06955 {
06956   static char name[] SET_TO "cycle_traverse";
06957   if (plane IS CANON_PLANE_XY)
06958     STRAIGHT_TRAVERSE(end1, end2, end3
06959 #ifdef AA
06960 ,                     _setup.AA_current
06961 #else
06962 #ifdef ALL_AXES
06963 , 0
06964 #endif
06965 #endif
06966 #ifdef BB
06967 ,  _setup.BB_current
06968 #else
06969 #ifdef ALL_AXES
06970 , 0
06971 #endif
06972 #endif
06973 #ifdef CC
06974 ,  _setup.CC_current
06975 #else
06976 #ifdef ALL_AXES
06977 , 0
06978 #endif
06979 #endif
06980 );
06981   else if (plane IS CANON_PLANE_YZ)
06982     STRAIGHT_TRAVERSE(end3, end1, end2
06983 #ifdef AA
06984 ,                     _setup.AA_current
06985 #else
06986 #ifdef ALL_AXES
06987 , 0
06988 #endif
06989 #endif
06990 #ifdef BB
06991 ,  _setup.BB_current
06992 #else
06993 #ifdef ALL_AXES
06994 , 0
06995 #endif
06996 #endif
06997 #ifdef CC
06998 ,  _setup.CC_current
06999 #else
07000 #ifdef ALL_AXES
07001 , 0
07002 #endif
07003 #endif
07004 );
07005   else /* if (plane IS CANON_PLANE_XZ) */
07006     STRAIGHT_TRAVERSE(end2, end3, end1
07007 #ifdef AA
07008 ,                     _setup.AA_current
07009 #else
07010 #ifdef ALL_AXES
07011 , 0
07012 #endif
07013 #endif
07014 #ifdef BB
07015 ,  _setup.BB_current
07016 #else
07017 #ifdef ALL_AXES
07018 , 0
07019 #endif
07020 #endif
07021 #ifdef CC
07022 ,  _setup.CC_current
07023 #else
07024 #ifdef ALL_AXES
07025 , 0
07026 #endif
07027 #endif
07028 );
07029   return RS274NGC_OK;
07030 }
07031 
07032 /****************************************************************************/
07033 
07034 /* enhance_block
07035 
07036 Returned Value:
07037    If any of the following errors occur, this returns the error shown.
07038    Otherwise, it returns RS274NGC_OK.
07039    1. A g80 is in the block, no modal group 0 code that uses axes
07040       is in the block, and one or more axis values is given:
07041       NCE_CANNOT_USE_AXIS_VALUES_WITH_G80
07042    2. A g92 is in the block and no axis value is given:
07043       NCE_ALL_AXES_MISSING_WITH_G92
07044    3. One g-code from group 1 and one from group 0, both of which can use
07045       axis values, are in the block:
07046       NCE_CANNOT_USE_TWO_G_CODES_THAT_BOTH_USE_AXIS_VALUES
07047    4. A g-code from group 1 which can use axis values is in the block,
07048       but no axis value is given: NCE_ALL_AXES_MISSING_WITH_MOTION_CODE
07049    5. Axis values are given, but there is neither a g-code in the block
07050       nor an active previously given modal g-code that uses axis values:
07051       NCE_CANNOT_USE_AXIS_VALUES_WITHOUT_A_G_CODE_THAT_USES_THEM
07052 
07053 Side effects:
07054    The value of motion_to_be in the block is set.
07055 
07056 Called by: parse_line
07057 
07058 If there is a g-code for motion in the block (in g_modes[1]),
07059 set motion_to_be to that. Otherwise, if there is an axis value in the
07060 block and no g-code to use it (any such would be from group 0 in
07061 g_modes[0]), set motion_to_be to be the last motion saved (in
07062 settings->motion mode).
07063 
07064 This also make the checks described above.
07065 
07066 */
07067 
07068 static int enhance_block( /* ARGUMENTS                         */
07069  block_pointer block,     /* pointer to a block to be checked  */
07070  setup_pointer settings)  /* pointer to machine settings       */
07071 {
07072   static char name[] SET_TO "enhance_block";
07073   int axis_flag;
07074   int mode_zero_covets_axes;
07075 
07076   axis_flag SET_TO ((block->x_flag IS ON) OR
07077                     (block->y_flag IS ON) OR
07078 #ifdef AA
07079                     (block->a_flag IS ON) OR /*AA*/
07080 #endif
07081 #ifdef BB
07082                     (block->b_flag IS ON) OR /*BB*/
07083 #endif
07084 #ifdef CC
07085                     (block->c_flag IS ON) OR /*CC*/
07086 #endif
07087                     (block->z_flag IS ON));
07088   mode_zero_covets_axes SET_TO ((block->g_modes[0] IS G_10) OR
07089                                 (block->g_modes[0] IS G_28) OR
07090                                 (block->g_modes[0] IS G_30) OR
07091                                 (block->g_modes[0] IS G_92));
07092 
07093   if (block->g_modes[1] ISNT -1)
07094     {
07095       if (block->g_modes[1] IS G_80)
07096         {
07097           CHK((axis_flag AND (NOT mode_zero_covets_axes)),
07098               NCE_CANNOT_USE_AXIS_VALUES_WITH_G80);
07099           CHK(((NOT axis_flag) AND (block->g_modes[0] IS G_92)),
07100               NCE_ALL_AXES_MISSING_WITH_G92);
07101         }
07102       else
07103         {
07104           CHK(mode_zero_covets_axes,
07105               NCE_CANNOT_USE_TWO_G_CODES_THAT_BOTH_USE_AXIS_VALUES);
07106           CHK((NOT axis_flag), NCE_ALL_AXES_MISSING_WITH_MOTION_CODE);
07107         }
07108       block->motion_to_be SET_TO block->g_modes[1];
07109     }
07110   else if (mode_zero_covets_axes)
07111     { /* other 3 can get by without axes but not G92 */
07112       CHK(((NOT axis_flag) AND (block->g_modes[0] IS G_92)),
07113           NCE_ALL_AXES_MISSING_WITH_G92);
07114     }
07115   else if (axis_flag)
07116     {
07117       CHK(((settings->motion_mode IS -1) OR (settings->motion_mode IS G_80)),
07118           NCE_CANNOT_USE_AXIS_VALUES_WITHOUT_A_G_CODE_THAT_USES_THEM);
07119       block->motion_to_be SET_TO settings->motion_mode;
07120     }
07121   return RS274NGC_OK;
07122 }
07123 
07124 /****************************************************************************/
07125 
07126 /* execute binary
07127 
07128 Returned value: int
07129    If execute_binary1 or execute_binary2 returns an error code, this
07130    returns that code.
07131    Otherwise, it returns RS274NGC_OK.
07132 
07133 Side effects: The value of left is set to the result of applying
07134   the operation to left and right.
07135 
07136 Called by: read_real_expression
07137 
07138 This just calls either execute_binary1 or execute_binary2.
07139 
07140 */
07141 
07142 static int execute_binary(
07143  double * left,
07144  int operation,
07145  double * right)
07146 {
07147   static char name[] SET_TO "execute_binary";
07148   int status;
07149 
07150   if (operation < AND2)
07151     CHP(execute_binary1(left, operation, right));
07152   else
07153     CHP(execute_binary2(left, operation, right));
07154   return RS274NGC_OK;
07155 }
07156 
07157 /****************************************************************************/
07158 
07159 /* execute_binary1
07160 
07161 Returned Value: int
07162    If any of the following errors occur, this returns the error shown.
07163    Otherwise, it returns RS274NGC_OK.
07164    1. operation is unknown: NCE_BUG_UNKNOWN_OPERATION
07165    2. An attempt is made to divide by zero: NCE_ATTEMPT_TO_DIVIDE_BY_ZERO
07166    3. An attempt is made to raise a negative number to a non-integer power:
07167       NCE_ATTEMPT_TO_RAISE_NEGATIVE_TO_NON_INTEGER_POWER
07168 
07169 Side effects:
07170    The result from performing the operation is put into what left points at.
07171 
07172 Called by: read_real_expression.
07173 
07174 This executes the operations: DIVIDED_BY, MODULO, POWER, TIMES.
07175 
07176 */
07177 
07178 static int execute_binary1( /* ARGUMENTS                       */
07179  double * left,             /* pointer to the left operand     */
07180  int operation,             /* integer code for the operation  */
07181  double * right)            /* pointer to the right operand    */
07182 {
07183   static char name[] SET_TO "execute_binary1";
07184   switch (operation)
07185     {
07186     case DIVIDED_BY:
07187       CHK((*right IS 0.0), NCE_ATTEMPT_TO_DIVIDE_BY_ZERO);
07188       *left SET_TO (*left / *right);
07189       break;
07190     case MODULO: /* always calculates a positive answer */
07191       *left SET_TO fmod(*left, *right);
07192       if (*left < 0.0)
07193         {
07194           *left SET_TO (*left + fabs(*right));
07195         }
07196       break;
07197     case POWER:
07198       CHK(((*left < 0.0) AND (floor(*right) ISNT *right)),
07199           NCE_ATTEMPT_TO_RAISE_NEGATIVE_TO_NON_INTEGER_POWER);
07200       *left SET_TO pow(*left, *right);
07201       break;
07202     case TIMES:
07203       *left SET_TO (*left * *right);
07204       break;
07205     default:
07206       ERM(NCE_BUG_UNKNOWN_OPERATION);
07207     }
07208   return RS274NGC_OK;
07209 }
07210 
07211 /****************************************************************************/
07212 
07213 /* execute_binary2
07214 
07215 Returned Value: int
07216    If any of the following errors occur, this returns the error code shown.
07217    Otherwise, it returns RS274NGC_OK.
07218    1. operation is unknown: NCE_BUG_UNKNOWN_OPERATION
07219 
07220 Side effects:
07221    The result from performing the operation is put into what left points at.
07222 
07223 Called by: read_real_expression.
07224 
07225 This executes the operations: AND2, EXCLUSIVE_OR, MINUS,
07226 NON_EXCLUSIVE_OR, PLUS. The RS274/NGC manual [NCMS] does not say what
07227 the calculated value of the three logical operations should be. This
07228 function calculates either 1.0 (meaning true) or 0.0 (meaning false).
07229 Any non-zero input value is taken as meaning true, and only 0.0 means
07230 false.
07231 
07232 
07233 */
07234 
07235 static int execute_binary2( /* ARGUMENTS                       */
07236  double * left,             /* pointer to the left operand     */
07237  int operation,             /* integer code for the operation  */
07238  double * right)            /* pointer to the right operand    */
07239 {
07240   static char name[] SET_TO "execute_binary2";
07241   switch (operation)
07242     {
07243     case AND2:
07244       *left SET_TO ((*left IS 0.0) OR (*right IS 0.0)) ? 0.0 : 1.0;
07245       break;
07246     case EXCLUSIVE_OR:
07247       *left SET_TO (((*left IS 0.0) AND (*right ISNT 0.0)) OR
07248                     ((*left ISNT 0.0) AND (*right IS 0.0))) ? 1.0 : 0.0;
07249       break;
07250     case MINUS:
07251       *left SET_TO (*left - *right);
07252       break;
07253     case NON_EXCLUSIVE_OR:
07254       *left SET_TO ((*left ISNT 0.0) OR (*right ISNT 0.0)) ? 1.0 : 0.0;
07255       break;
07256     case PLUS:
07257       *left SET_TO (*left + *right);
07258       break;
07259     default:
07260       ERM(NCE_BUG_UNKNOWN_OPERATION);
07261     }
07262   return RS274NGC_OK;
07263 }
07264 
07265 /****************************************************************************/
07266 
07267 /* execute_block
07268 
07269 Returned Value: int
07270    If convert_stop returns RS274NGC_EXIT, this returns RS274NGC_EXIT.
07271    If any of the following functions is called and returns an error code,
07272    this returns that code.
07273      convert_comment
07274      convert_feed_mode
07275      convert_feed_rate
07276      convert_g
07277      convert_m
07278      convert_speed
07279      convert_stop
07280      convert_tool_select
07281    Otherwise, if the probe_flag in the settings is ON, this returns
07282       RS274NGC_EXECUTE_FINISH.
07283    Otherwise, it returns RS274NGC_OK.
07284 
07285 Side effects:
07286    One block of RS274/NGC instructions is executed.
07287 
07288 Called by:
07289    rs274ngc_execute
07290 
07291 This converts a block to zero to many actions. The order of execution
07292 of items in a block is critical to safe and effective machine operation,
07293 but is not specified clearly in the RS274/NGC documentation.
07294 
07295 Actions are executed in the following order:
07296 1. any comment.
07297 2. a feed mode setting (g93, g94)
07298 3. a feed rate (f) setting if in units_per_minute feed mode.
07299 4. a spindle speed (s) setting.
07300 5. a tool selection (t).
07301 6. "m" commands as described in convert_m (includes tool change).
07302 7. any g_codes (except g93, g94) as described in convert_g.
07303 8. stopping commands (m0, m1, m2, m30, or m60).
07304 
07305 In inverse time feed mode, the explicit and implicit g code executions
07306 include feed rate setting with g1, g2, and g3. Also in inverse time
07307 feed mode, attempting a canned cycle cycle (g81 to g89) or setting a
07308 feed rate with g0 is illegal and will be detected and result in an
07309 error message.
07310 
07311 */
07312 
07313 static int execute_block(  /* ARGUMENTS                                    */
07314  block_pointer block,      /* pointer to a block of RS274/NGC instructions */
07315  setup_pointer settings)   /* pointer to machine settings                  */
07316 {
07317   static char name[] SET_TO "execute_block";
07318   int status;
07319 
07320   if (block->comment[0] ISNT 0)
07321     {
07322       CHP(convert_comment(block->comment));
07323     }
07324   if (block->g_modes[5] ISNT -1)
07325     {
07326       CHP(convert_feed_mode(block->g_modes[5], settings));
07327     }
07328   if (block->f_number > -1.0)
07329     {
07330       if (settings->feed_mode IS INVERSE_TIME); /* handle elsewhere */
07331       else
07332         {
07333           CHP(convert_feed_rate(block, settings));
07334         }
07335     }
07336   if (block->s_number > -1.0)
07337     {
07338       CHP(convert_speed(block, settings));
07339     }
07340   if (block->t_number ISNT -1)
07341     {
07342       CHP(convert_tool_select(block, settings));
07343     }
07344   CHP(convert_m(block, settings));
07345   CHP(convert_g(block, settings));
07346   if (block->m_modes[4] ISNT -1) /* converts m0, m1, m2, m30, or m60 */
07347     {
07348       status SET_TO convert_stop(block, settings);
07349       if (status IS RS274NGC_EXIT)
07350         return RS274NGC_EXIT;
07351       else if (status ISNT RS274NGC_OK)
07352         ERP(status);
07353     }
07354   return ((settings->probe_flag IS ON) ? RS274NGC_EXECUTE_FINISH: RS274NGC_OK);
07355 }
07356 
07357 /****************************************************************************/
07358 
07359 /* execute_unary
07360 
07361 Returned Value: int
07362    If any of the following errors occur, this returns the error code shown.
07363    Otherwise, it returns RS274NGC_OK.
07364    1. the operation is unknown: NCE_BUG_UNKNOWN_OPERATION
07365    2. the argument to acos is not between minus and plus one:
07366       NCE_ARGUMENT_TO_ACOS_OUT_RANGE
07367    3. the argument to asin is not between minus and plus one:
07368       NCE_ARGUMENT_TO_ASIN_OUT_RANGE
07369    4. the argument to the natural logarithm is not positive:
07370       NCE_ZERO_OR_NEGATIVE_ARGUMENT_TO_LN
07371    5. the argument to square root is negative:
07372       NCE_NEGATIVE_ARGUMENT_TO_SQRT
07373 
07374 Side effects:
07375    The result from performing the operation on the value in double_ptr
07376    is put into what double_ptr points at.
07377 
07378 Called by: read_unary.
07379 
07380 This executes the operations: ABS, ACOS, ASIN, COS, EXP, FIX, FUP, LN
07381 ROUND, SIN, SQRT, TAN
07382 
07383 All angle measures in the input or output are in degrees.
07384 
07385 */
07386 
07387 static int execute_unary( /* ARGUMENTS                       */
07388  double * double_ptr,     /* pointer to the operand          */
07389  int operation)           /* integer code for the operation  */
07390 {
07391   static char name[] SET_TO "execute_unary";
07392   switch (operation)
07393     {
07394     case ABS:
07395       if (*double_ptr < 0.0)
07396         *double_ptr SET_TO (-1.0 * *double_ptr);
07397       break;
07398     case ACOS:
07399       CHK(((*double_ptr < -1.0) OR (*double_ptr > 1.0)),
07400           NCE_ARGUMENT_TO_ACOS_OUT_OF_RANGE);
07401       *double_ptr SET_TO acos(*double_ptr);
07402       *double_ptr SET_TO ((*double_ptr * 180.0)/ PI);
07403       break;
07404     case ASIN:
07405       CHK(((*double_ptr < -1.0) OR (*double_ptr > 1.0)),
07406           NCE_ARGUMENT_TO_ASIN_OUT_OF_RANGE);
07407       *double_ptr SET_TO asin(*double_ptr);
07408       *double_ptr SET_TO ((*double_ptr * 180.0)/ PI);
07409       break;
07410     case COS:
07411       *double_ptr SET_TO cos((*double_ptr * PI)/180.0);
07412       break;
07413     case EXP:
07414       *double_ptr SET_TO exp(*double_ptr);
07415       break;
07416     case FIX:
07417       *double_ptr SET_TO floor(*double_ptr);
07418       break;
07419     case FUP:
07420       *double_ptr SET_TO ceil(*double_ptr);
07421       break;
07422     case LN:
07423       CHK((*double_ptr <= 0.0), NCE_ZERO_OR_NEGATIVE_ARGUMENT_TO_LN);
07424       *double_ptr SET_TO log(*double_ptr);
07425       break;
07426     case ROUND:
07427       *double_ptr SET_TO (double)
07428         ((int) (*double_ptr + ((*double_ptr < 0.0) ? -0.5 : 0.5)));
07429       break;
07430     case SIN:
07431       *double_ptr SET_TO sin((*double_ptr * PI)/180.0);
07432       break;
07433     case SQRT:
07434       CHK((*double_ptr < 0.0), NCE_NEGATIVE_ARGUMENT_TO_SQRT);
07435       *double_ptr SET_TO sqrt(*double_ptr);
07436       break;
07437     case TAN:
07438       *double_ptr SET_TO tan((*double_ptr * PI)/180.0);
07439       break;
07440     default:
07441       ERM(NCE_BUG_UNKNOWN_OPERATION);
07442     }
07443   return RS274NGC_OK;
07444 }
07445 
07446 /****************************************************************************/
07447 
07448 /* find_arc_length
07449 
07450 Returned Value: double (length of path between start and end points)
07451 
07452 Side effects: none
07453 
07454 Called by:
07455    inverse_time_rate_arc
07456    inverse_time_rate_arc2
07457    inverse_time_rate_as
07458 
07459 This calculates the length of the path that will be made relative to
07460 the XYZ axes for a motion in which the X,Y,Z, motion is a circular or
07461 helical arc with its axis parallel to the Z-axis. If tool length
07462 compensation is on, this is the path of the tool tip; if off, the
07463 length of the path of the spindle tip. Any rotary axis motion is
07464 ignored.
07465 
07466 If the arc is helical, it is coincident with the hypotenuse of a right
07467 triangle wrapped around a cylinder. If the triangle is unwrapped, its
07468 base is [the radius of the cylinder times the number of radians in the
07469 helix] and its height is [z2 - z1], and the path length can be found
07470 by the Pythagorean theorem.
07471 
07472 This is written as though it is only for arcs whose axis is parallel to
07473 the Z-axis, but it will serve also for arcs whose axis is parallel
07474 to the X-axis or Y-axis, with suitable permutation of the arguments.
07475 
07476 This works correctly when turn is zero (find_turn returns 0 in that
07477 case).
07478 
07479 */
07480 
07481 static double find_arc_length( /* ARGUMENTS                          */
07482  double x1,                    /* X-coordinate of start point        */
07483  double y1,                    /* Y-coordinate of start point        */
07484  double z1,                    /* Z-coordinate of start point        */
07485  double center_x,              /* X-coordinate of arc center         */
07486  double center_y,              /* Y-coordinate of arc center         */
07487  int turn,                     /* no. of full or partial circles CCW */
07488  double x2,                    /* X-coordinate of end point          */
07489  double y2,                    /* Y-coordinate of end point          */
07490  double z2)                    /* Z-coordinate of end point          */
07491 {
07492   double radius;
07493   double theta;  /* amount of turn of arc in radians */
07494 
07495   radius SET_TO hypot((center_x - x1), (center_y - y1));
07496   theta SET_TO find_turn(x1, y1, center_x, center_y, turn, x2, y2);
07497   if (z2 IS z1)
07498     return (radius * fabs(theta));
07499   else
07500     return hypot((radius * theta), (z2 - z1));
07501 }
07502 
07503 /****************************************************************************/
07504 
07505 /* find_ends
07506 
07507 Returned Value: int (RS274NGC_OK)
07508 
07509 Side effects:
07510    The values of px, py, pz, aa_p, bb_p, and cc_p are set
07511 
07512 Called by:
07513    convert_arc
07514    convert_home
07515    convert_probe
07516    convert_straight
07517 
07518 This finds the coordinates of a point, "end", in the currently
07519 active coordinate system, and sets the values of the pointers to the
07520 coordinates (which are the arguments to the function).
07521 
07522 In all cases, if no value for the coodinate is given in the block, the
07523 current value for the coordinate is used. When cutter radius
07524 compensation is on, this function is called before compensation
07525 calculations are performed, so the current value of the programmed
07526 point is used, not the current value of the actual current_point.
07527 
07528 There are three cases for when the coordinate is included in the block:
07529 
07530 1. G_53 is active. This means to interpret the coordinates as machine
07531 coordinates. That is accomplished by adding the two offsets to the
07532 coordinate given in the block.
07533 
07534 2. Absolute coordinate mode is in effect. The coordinate in the block
07535 is used.
07536 
07537 3. Incremental coordinate mode is in effect. The coordinate in the
07538 block plus either (i) the programmed current position - when cutter
07539 radius compensation is in progress, or (2) the actual current position.
07540 
07541 */
07542 
07543 static int find_ends(    /* ARGUMENTS                                    */
07544  block_pointer block,    /* pointer to a block of RS274/NGC instructions */
07545  setup_pointer settings, /* pointer to machine settings                  */
07546  double * px,            /* pointer to end_x                             */
07547  double * py,            /* pointer to end_y                             */
07548  double * pz             /* pointer to end_z                             */
07549 #ifdef AA
07550  , double * AA_p         /* pointer to end_a                       *//*AA*/
07551 #endif
07552 #ifdef BB
07553  , double * BB_p         /* pointer to end_b                       *//*BB*/
07554 #endif
07555 #ifdef CC
07556  , double * CC_p         /* pointer to end_c                       *//*CC*/
07557 #endif
07558 )
07559 {
07560   int mode;
07561   int middle;
07562   int comp;
07563 
07564   mode SET_TO settings->distance_mode;
07565   middle SET_TO (settings->program_x ISNT UNKNOWN);
07566   comp SET_TO (settings->cutter_comp_side ISNT OFF);
07567 
07568   if (block->g_modes[0] IS G_53) /* distance mode is absolute in this case */
07569     {
07570 #ifdef DEBUG_EMC
07571       COMMENT("interpreter: offsets temporarily suspended");
07572 #endif
07573       *px SET_TO (block->x_flag IS ON) ? (block->x_number -
07574                    (settings->origin_offset_x + settings->axis_offset_x)) :
07575                      settings->current_x;
07576       *py SET_TO (block->y_flag IS ON) ? (block->y_number -
07577                    (settings->origin_offset_y + settings->axis_offset_y)) :
07578                      settings->current_y;
07579       *pz SET_TO (block->z_flag IS ON) ? (block->z_number -
07580                    (settings->tool_length_offset + settings->origin_offset_z
07581                     + settings->axis_offset_z)) : settings->current_z;
07582 #ifdef AA
07583       *AA_p SET_TO (block->a_flag IS ON) ? (block->a_number -            /*AA*/
07584 #endif
07585 #ifdef AA
07586               (settings->AA_origin_offset + settings->AA_axis_offset)) : /*AA*/
07587 #endif
07588 #ifdef AA
07589                    settings->AA_current;                                 /*AA*/
07590 #endif
07591 #ifdef BB
07592       *BB_p SET_TO (block->b_flag IS ON) ? (block->b_number -            /*BB*/
07593 #endif
07594 #ifdef BB
07595               (settings->BB_origin_offset + settings->BB_axis_offset)) : /*BB*/
07596 #endif
07597 #ifdef BB
07598                    settings->BB_current;                                 /*BB*/
07599 #endif
07600 #ifdef CC
07601       *CC_p SET_TO (block->c_flag IS ON) ? (block->c_number -            /*CC*/
07602 #endif
07603 #ifdef CC
07604               (settings->tool_length_offset + settings->CC_origin_offset /*CC*/
07605 #endif
07606 #ifdef CC
07607                 + settings->CC_axis_offset)) : settings->CC_current;     /*CC*/
07608 #endif
07609     }
07610   else if (mode IS MODE_ABSOLUTE)
07611     {
07612       *px SET_TO (block->x_flag IS ON) ? block->x_number     :
07613                  (comp AND middle)     ? settings->program_x :
07614                                          settings->current_x ;
07615 
07616       *py SET_TO (block->y_flag IS ON) ? block->y_number     :
07617                  (comp AND middle)     ? settings->program_y :
07618                                          settings->current_y ;
07619 
07620       *pz SET_TO (block->z_flag IS ON) ? block->z_number     :
07621                                          settings->current_z ;
07622 #ifdef AA
07623       *AA_p SET_TO (block->a_flag IS ON) ? block->a_number     :       /*AA*/
07624 #endif
07625 #ifdef AA
07626                                           settings->AA_current ;       /*AA*/
07627 #endif
07628 #ifdef BB
07629       *BB_p SET_TO (block->b_flag IS ON) ? block->b_number     :       /*BB*/
07630 #endif
07631 #ifdef BB
07632                                           settings->BB_current ;       /*BB*/
07633 #endif
07634 #ifdef CC
07635       *CC_p SET_TO (block->c_flag IS ON) ? block->c_number     :       /*CC*/
07636 #endif
07637 #ifdef CC
07638                                           settings->CC_current ;       /*CC*/
07639 #endif
07640     }
07641   else /* mode is MODE_INCREMENTAL */
07642     {
07643       *px SET_TO (block->x_flag IS ON)
07644         ? ((comp AND middle) ? (block->x_number + settings->program_x)
07645                              : (block->x_number + settings->current_x))
07646         : ((comp AND middle) ? settings->program_x
07647                              : settings->current_x);
07648 
07649       *py SET_TO (block->y_flag IS ON)
07650         ? ((comp AND middle) ? (block->y_number + settings->program_y)
07651                              : (block->y_number + settings->current_y))
07652         : ((comp AND middle) ? settings->program_y
07653                              : settings->current_y);
07654 
07655       *pz SET_TO (block->z_flag IS ON) ?
07656         (settings->current_z + block->z_number) : settings->current_z;
07657 #ifdef AA
07658       *AA_p SET_TO (block->a_flag IS ON) ?                               /*AA*/
07659 #endif
07660 #ifdef AA
07661         (settings->AA_current + block->a_number) : settings->AA_current; /*AA*/
07662 #endif
07663 #ifdef BB
07664       *BB_p SET_TO (block->b_flag IS ON) ?                               /*BB*/
07665 #endif
07666 #ifdef BB
07667         (settings->BB_current + block->b_number) : settings->BB_current; /*BB*/
07668 #endif
07669 #ifdef CC
07670       *CC_p SET_TO (block->c_flag IS ON) ?                               /*CC*/
07671 #endif
07672 #ifdef CC
07673         (settings->CC_current + block->c_number) : settings->CC_current; /*CC*/
07674 #endif
07675     }
07676   return RS274NGC_OK;
07677 }
07678 
07679 /****************************************************************************/
07680 
07681 /* find_relative
07682 
07683 Returned Value: int (RS274NGC_OK)
07684 
07685 Side effects:
07686    The values of x2, y2, z2, aa_2, bb_2, and cc_2 are set.
07687    (NOTE: aa_2 etc. are written with lower case letters in this
07688     documentation because upper case would confuse the pre-preprocessor.)
07689 
07690 Called by:
07691    convert_home
07692 
07693 This finds the coordinates in the current system, under the current
07694 tool length offset, of a point (x1, y1, z1, aa_1, bb_1, cc_1) whose absolute
07695 coordinates are known.
07696 
07697 Don't confuse this with the inverse operation.
07698 
07699 */
07700 
07701 static int find_relative( /* ARGUMENTS                   */
07702  double x1,               /* absolute x position         */
07703  double y1,               /* absolute y position         */
07704  double z1,               /* absolute z position         */
07705 #ifdef AA
07706  double AA_1,             /* absolute a position         */ /*AA*/
07707 #endif
07708 #ifdef BB
07709  double BB_1,             /* absolute b position         */ /*BB*/
07710 #endif
07711 #ifdef CC
07712  double CC_1,             /* absolute c position         */ /*CC*/
07713 #endif
07714  double * x2,             /* pointer to relative x       */
07715  double * y2,             /* pointer to relative y       */
07716  double * z2,             /* pointer to relative z       */
07717 #ifdef AA
07718  double * AA_2,           /* pointer to relative a       */ /*AA*/
07719 #endif
07720 #ifdef BB
07721  double * BB_2,           /* pointer to relative b       */ /*BB*/
07722 #endif
07723 #ifdef CC
07724  double * CC_2,           /* pointer to relative c       */ /*CC*/
07725 #endif
07726  setup_pointer settings)  /* pointer to machine settings */
07727 {
07728   *x2 SET_TO (x1 - (settings->origin_offset_x + settings->axis_offset_x));
07729   *y2 SET_TO (y1 - (settings->origin_offset_y + settings->axis_offset_y));
07730   *z2 SET_TO (z1 - (settings->tool_length_offset +
07731                     settings->origin_offset_z + settings->axis_offset_z));
07732 #ifdef AA
07733   *AA_2 SET_TO (AA_1 - (settings->AA_origin_offset +    /*AA*/
07734 #endif
07735 #ifdef AA
07736                         settings->AA_axis_offset));     /*AA*/
07737 #endif
07738 #ifdef BB
07739   *BB_2 SET_TO (BB_1 - (settings->BB_origin_offset +    /*BB*/
07740 #endif
07741 #ifdef BB
07742                         settings->BB_axis_offset));     /*BB*/
07743 #endif
07744 #ifdef CC
07745   *CC_2 SET_TO (CC_1 - (settings->CC_origin_offset +    /*CC*/
07746 #endif
07747 #ifdef CC
07748                         settings->CC_axis_offset));     /*CC*/
07749 #endif
07750   return RS274NGC_OK;
07751 }
07752 
07753 /****************************************************************************/
07754 
07755 /* find_straight_length
07756 
07757 Returned Value: double (length of path between start and end points)
07758 
07759 Side effects: none
07760 
07761 Called by:
07762   inverse_time_rate_straight
07763   inverse_time_rate_as
07764 
07765 This calculates a number to use in feed rate calculations when inverse
07766 time feed mode is used, for a motion in which X,Y,Z,A,B, and C each change
07767 linearly or not at all from their initial value to their end value.
07768 
07769 This is used when the feed_reference mode is CANON_XYZ, which is
07770 always in rs274NGC.
07771 
07772 If any of the X, Y, or Z axes move or the A-axis, B-axis, and C-axis
07773 do not move, this is the length of the path relative to the XYZ axes
07774 from the first point to the second, and any rotary axis motion is
07775 ignored. The length is the simple Euclidean distance.
07776 
07777 The formula for the Euclidean distance "length" of a move involving
07778 only the A, B and C axes is based on a conversation with Jim Frohardt at
07779 Boeing, who says that the Fanuc controller on their 5-axis machine
07780 interprets the feed rate this way. Note that if only one rotary axis
07781 moves, this formula returns the absolute value of that axis move,
07782 which is what is desired.
07783 
07784 */
07785 
07786 static double find_straight_length( /* ARGUMENTS   */
07787  double x2,        /* X-coordinate of end point    */
07788  double y2,        /* Y-coordinate of end point    */
07789  double z2,        /* Z-coordinate of end point    */
07790 #ifdef AA
07791  double AA_2,      /* A-coordinate of end point    */ /*AA*/
07792 #endif
07793 #ifdef BB
07794  double BB_2,      /* B-coordinate of end point    */ /*BB*/
07795 #endif
07796 #ifdef CC
07797  double CC_2,      /* C-coordinate of end point    */ /*CC*/
07798 #endif
07799  double x1,        /* X-coordinate of start point  */
07800  double y1,        /* Y-coordinate of start point  */
07801  double z1         /* Z-coordinate of start point  */
07802 #ifdef AA
07803  , double AA_1     /* A-coordinate of start point  */ /*AA*/
07804 #endif
07805 #ifdef BB
07806  , double BB_1     /* B-coordinate of start point  */ /*BB*/
07807 #endif
07808 #ifdef CC
07809  , double CC_1     /* C-coordinate of start point  */ /*CC*/
07810 #endif
07811 )
07812 {
07813   if ((x1 ISNT x2) OR (y1 ISNT y2) OR (z1 ISNT z2) OR
07814       (1
07815 #ifdef AA
07816        AND (AA_2 IS AA_1)   /*AA*/
07817 #endif
07818 #ifdef BB
07819        AND (BB_2 IS BB_1)   /*BB*/
07820 #endif
07821 #ifdef CC
07822        AND (CC_2 IS CC_1)   /*CC*/
07823 #endif
07824        )) /* straight line */
07825     return sqrt(pow((x2 - x1),2) + pow((y2 - y1),2) + pow((z2 - z1),2));
07826   else
07827     return sqrt(0 +
07828 #ifdef AA
07829                 pow((AA_2 - AA_1), 2) +  /*AA*/
07830 #endif
07831 #ifdef BB
07832                 pow((BB_2 - BB_1), 2) +  /*BB*/
07833 #endif
07834 #ifdef CC
07835                 pow((CC_2 - CC_1), 2) +  /*CC*/
07836 #endif
07837                 0);
07838 }
07839 
07840 /****************************************************************************/
07841 
07842 /* find_turn
07843 
07844 Returned Value: double (angle in radians between two radii of a circle)
07845 
07846 Side effects: none
07847 
07848 Called by: find_arc_length
07849 
07850 All angles are in radians.
07851 
07852 */
07853 
07854 static double find_turn( /* ARGUMENTS                          */
07855  double x1,              /* X-coordinate of start point        */
07856  double y1,              /* Y-coordinate of start point        */
07857  double center_x,        /* X-coordinate of arc center         */
07858  double center_y,        /* Y-coordinate of arc center         */
07859  int turn,               /* no. of full or partial circles CCW */
07860  double x2,              /* X-coordinate of end point          */
07861  double y2)              /* Y-coordinate of end point          */
07862 {
07863   double alpha;  /* angle of first radius                      */
07864   double beta;   /* angle of second radius                     */
07865   double theta;  /* amount of turn of arc CCW - negative if CW */
07866 
07867   if (turn IS 0)
07868     return 0.0;
07869   alpha SET_TO atan2((y1 - center_y), (x1 - center_x));
07870   beta SET_TO atan2((y2 - center_y), (x2 - center_x));
07871   if (turn > 0)
07872     {
07873       if (beta <= alpha)
07874         beta SET_TO (beta + TWO_PI);
07875       theta SET_TO ((beta - alpha) + ((turn - 1) * TWO_PI));
07876     }
07877   else /* turn < 0 */
07878     {
07879       if (alpha <= beta)
07880         alpha SET_TO (alpha + TWO_PI);
07881       theta SET_TO ((beta - alpha) + ((turn + 1) * TWO_PI));
07882     }
07883   return (theta);
07884 }
07885 
07886 /****************************************************************************/
07887 
07888 /* init_block
07889 
07890 Returned Value: int (RS274NGC_OK)
07891 
07892 Side effects:
07893    Values in the block are reset as described below.
07894 
07895 Called by: parse_line
07896 
07897 This system reuses the same block over and over, rather than building
07898 a new one for each line of NC code. The block is re-initialized before
07899 each new line of NC code is read.
07900 
07901 The block contains many slots for values which may or may not be present
07902 on a line of NC code. For some of these slots, there is a flag which
07903 is turned on (at the time time value of the slot is read) if the item
07904 is present.  For slots whose values are to be read which do not have a
07905 flag, there is always some excluded range of values. Setting the
07906 initial value of these slot to some number in the excluded range
07907 serves to show that a value for that slot has not been read.
07908 
07909 The rules for the indicators for slots whose values may be read are:
07910 1. If the value may be an arbitrary real number (which is always stored
07911    internally as a double), a flag is needed to indicate if a value has
07912    been read. All such flags are initialized to OFF.
07913    Note that the value itself is not initialized; there is no point in it.
07914 2. If the value must be a non-negative real number (which is always stored
07915    internally as a double), a value of -1.0 indicates the item is not present.
07916 3. If the value must be an unsigned integer (which is always stored
07917    internally as an int), a value of -1 indicates the item is not present.
07918    (RS274/NGC does not use any negative integers.)
07919 4. If the value is a character string (only the comment slot is one), the
07920    first character is set to 0 (NULL).
07921 
07922 */
07923 
07924 static int init_block( /* ARGUMENTS                                     */
07925  block_pointer block)  /* pointer to a block to be initialized or reset */
07926 {
07927   int n;
07928 #ifdef AA
07929   block->a_flag SET_TO OFF;  /*AA*/
07930 #endif
07931 #ifdef BB
07932   block->b_flag SET_TO OFF;  /*BB*/
07933 #endif
07934 #ifdef CC
07935   block->c_flag SET_TO OFF;  /*CC*/
07936 #endif
07937   block->comment[0] SET_TO 0;
07938   block->d_number SET_TO -1;
07939   block->f_number SET_TO -1.0;
07940   for (n SET_TO 0; n < 14; n++)
07941     {
07942       block->g_modes[n] SET_TO -1;
07943     }
07944   block->h_number SET_TO -1;
07945   block->i_flag SET_TO OFF;
07946   block->j_flag SET_TO OFF;
07947   block->k_flag SET_TO OFF;
07948   block->l_number SET_TO -1;
07949   block->line_number SET_TO -1;
07950   block->motion_to_be SET_TO -1;
07951   block->m_count SET_TO 0;
07952   for (n SET_TO 0; n < 10; n++)
07953     {
07954       block->m_modes[n] SET_TO -1;
07955     }
07956   block->p_number SET_TO -1.0;
07957   block->q_number SET_TO -1.0;
07958   block->r_flag SET_TO OFF;
07959   block->s_number SET_TO -1.0;
07960   block->t_number SET_TO -1;
07961   block->x_flag SET_TO OFF;
07962   block->y_flag SET_TO OFF;
07963   block->z_flag SET_TO OFF;
07964 
07965   return RS274NGC_OK;
07966 }
07967 
07968 /****************************************************************************/
07969 
07970 /* inverse_time_rate_arc
07971 
07972 Returned Value: int (RS274NGC_OK)
07973 
07974 Side effects: a call is made to SET_FEED_RATE and _setup.feed_rate is set.
07975 
07976 Called by:
07977   convert_arc2
07978   convert_arc_comp1
07979   convert_arc_comp2
07980 
07981 This finds the feed rate needed by an inverse time move. The move
07982 consists of an a single arc. Most of the work here is in finding the
07983 length of the arc.
07984 
07985 */
07986 
07987 static int inverse_time_rate_arc( /* ARGUMENTS                       */
07988  double x1,              /* x coord of start point of arc            */
07989  double y1,              /* y coord of start point of arc            */
07990  double z1,              /* z coord of start point of arc            */
07991  double cx,              /* x coord of center of arc                 */
07992  double cy,              /* y coord of center of arc                 */
07993  int turn,               /* turn of arc                              */
07994  double x2,              /* x coord of end point of arc              */
07995  double y2,              /* y coord of end point of arc              */
07996  double z2,              /* z coord of end point of arc              */
07997  block_pointer block,    /* pointer to a block of RS274 instructions */
07998  setup_pointer settings) /* pointer to machine settings              */
07999 {
08000   double length;
08001   double rate;
08002 
08003   length SET_TO find_arc_length (x1, y1, z1, cx, cy, turn, x2, y2, z2);
08004   rate SET_TO MAX(0.1, (length * block->f_number));
08005   SET_FEED_RATE (rate);
08006   settings->feed_rate SET_TO rate;
08007 
08008   return RS274NGC_OK;
08009 }
08010 
08011 /****************************************************************************/
08012 
08013 /* inverse_time_rate_arc2
08014 
08015 Returned Value: int (RS274NGC_OK)
08016 
08017 Side effects: a call is made to SET_FEED_RATE and _setup.feed_rate is set.
08018 
08019 Called by: convert_arc_comp2
08020 
08021 This finds the feed rate needed by an inverse time move in
08022 convert_arc_comp2. The move consists of an extra arc and a main
08023 arc. Most of the work here is in finding the lengths of the two arcs.
08024 
08025 All rotary motion is assumed to occur on the extra arc, as done by
08026 convert_arc_comp2.
08027 
08028 All z motion is assumed to occur on the main arc, as done by
08029 convert_arc_comp2.
08030 
08031 
08032 */
08033 
08034 static int inverse_time_rate_arc2( /* ARGUMENTS */
08035  double start_x,        /* x coord of last program point, extra arc center x */
08036  double start_y,        /* y coord of last program point, extra arc center y */
08037  int turn1,             /* turn of extra arc                                 */
08038  double mid_x,          /* x coord of end point of extra arc                 */
08039  double mid_y,          /* y coord of end point of extra arc                 */
08040  double cx,             /* x coord of center of main arc                     */
08041  double cy,             /* y coord of center of main arc                     */
08042  int turn2,             /* turn of main arc                                  */
08043  double end_x,          /* x coord of end point of main arc                  */
08044  double end_y,          /* y coord of end point of main arc                  */
08045  double end_z,          /* z coord of end point of main arc                  */
08046  block_pointer block,   /* pointer to a block of RS274 instructions          */
08047  setup_pointer settings)/* pointer to machine settings                       */
08048 {
08049   double length;
08050   double rate;
08051 
08052   length SET_TO (find_arc_length (settings->current_x, settings->current_y,
08053                                   settings->current_z, start_x, start_y,
08054                                   turn1, mid_x, mid_y, settings->current_z) +
08055                  find_arc_length(mid_x, mid_y, settings->current_z,
08056                                  cx, cy, turn2, end_x, end_y, end_z));
08057   rate SET_TO MAX(0.1, (length * block->f_number));
08058   SET_FEED_RATE (rate);
08059   settings->feed_rate SET_TO rate;
08060 
08061   return RS274NGC_OK;
08062 }
08063 
08064 /****************************************************************************/
08065 
08066 /* inverse_time_rate_as
08067 
08068 Returned Value: int (RS274NGC_OK)
08069 
08070 Side effects: a call is made to SET_FEED_RATE and _setup.feed_rate is set.
08071 
08072 Called by: convert_straight_comp2
08073 
08074 This finds the feed rate needed by an inverse time move in
08075 convert_straight_comp2. The move consists of an extra arc and a straight
08076 line. Most of the work here is in finding the lengths of the arc and
08077 the line.
08078 
08079 All rotary motion is assumed to occur on the arc, as done by
08080 convert_straight_comp2.
08081 
08082 All z motion is assumed to occur on the line, as done by
08083 convert_straight_comp2.
08084 
08085 */
08086 
08087 static int inverse_time_rate_as( /* ARGUMENTS */
08088  double start_x,        /* x coord of last program point, extra arc center x */
08089  double start_y,        /* y coord of last program point, extra arc center y */
08090  int turn,              /* turn of extra arc                                 */
08091  double mid_x,          /* x coord of end point of extra arc                 */
08092  double mid_y,          /* y coord of end point of extra arc                 */
08093  double end_x,          /* x coord of end point of straight line             */
08094  double end_y,          /* y coord of end point of straight line             */
08095  double end_z,          /* z coord of end point of straight line             */
08096 #ifdef AA
08097  double AA_end,         /* A coord of end point of straight line       *//*AA*/
08098 #endif
08099 #ifdef BB
08100  double BB_end,         /* B coord of end point of straight line       *//*BB*/
08101 #endif
08102 #ifdef CC
08103  double CC_end,         /* C coord of end point of straight line       *//*CC*/
08104 #endif
08105  block_pointer block,   /* pointer to a block of RS274 instructions          */
08106  setup_pointer settings)/* pointer to machine settings                       */
08107 {
08108   double length;
08109   double rate;
08110 
08111   length SET_TO (find_arc_length (settings->current_x, settings->current_y,
08112                                   settings->current_z, start_x, start_y,
08113                                   turn, mid_x, mid_y, settings->current_z) +
08114                  find_straight_length(end_x, end_y,
08115                                 end_z
08116 #ifdef AA
08117 , AA_end
08118 #endif
08119 
08120 #ifdef BB
08121 , BB_end
08122 #endif
08123 
08124 #ifdef CC
08125 , CC_end
08126 #endif
08127 , mid_x, mid_y,
08128                                 settings->current_z
08129 #ifdef AA
08130 , AA_end
08131 #endif
08132 
08133 #ifdef BB
08134 , BB_end
08135 #endif
08136 
08137 #ifdef CC
08138 , CC_end
08139 #endif
08140 ));
08141   rate SET_TO MAX(0.1, (length * block->f_number));
08142   SET_FEED_RATE (rate);
08143   settings->feed_rate SET_TO rate;
08144 
08145   return RS274NGC_OK;
08146 }
08147 
08148 /****************************************************************************/
08149 
08150 /* inverse_time_rate_straight
08151 
08152 Returned Value: int (RS274NGC_OK)
08153 
08154 Side effects: a call is made to SET_FEED_RATE and _setup.feed_rate is set.
08155 
08156 Called by:
08157   convert_straight
08158   convert_straight_comp1
08159   convert_straight_comp2
08160 
08161 This finds the feed rate needed by an inverse time straight move. Most
08162 of the work here is in finding the length of the line.
08163 
08164 */
08165 
08166 static int inverse_time_rate_straight( /* ARGUMENTS                    */
08167  double end_x,           /* x coordinate of end point of straight line */
08168  double end_y,           /* y coordinate of end point of straight line */
08169  double end_z,           /* z coordinate of end point of straight line */
08170 #ifdef AA
08171  double AA_end,          /* A coordinate of end point of straight line *//*AA*/
08172 #endif
08173 #ifdef BB
08174  double BB_end,          /* B coordinate of end point of straight line *//*BB*/
08175 #endif
08176 #ifdef CC
08177  double CC_end,          /* C coordinate of end point of straight line *//*CC*/
08178 #endif
08179  block_pointer block,    /* pointer to a block of RS274 instructions   */
08180  setup_pointer settings) /* pointer to machine settings                */
08181 {
08182   static char name[] SET_TO "inverse_time_rate_straight";
08183   double length;
08184   double rate;
08185 
08186   length SET_TO find_straight_length
08187     (end_x, end_y, end_z
08188 #ifdef AA
08189 , AA_end
08190 #endif
08191 
08192 #ifdef BB
08193 , BB_end
08194 #endif
08195 
08196 #ifdef CC
08197 , CC_end
08198 #endif
08199 , settings->current_x,
08200      settings->current_y, settings->current_z
08201 
08202 #ifdef AA
08203 , settings->AA_current
08204 #endif
08205 
08206 #ifdef BB
08207 , settings->BB_current
08208 #endif
08209 
08210 #ifdef CC
08211 , settings->CC_current
08212 #endif
08213 );
08214   rate SET_TO MAX(0.1, (length * block->f_number));
08215   SET_FEED_RATE (rate);
08216   settings->feed_rate SET_TO rate;
08217 
08218   return RS274NGC_OK;
08219 }
08220 
08221 /****************************************************************************/
08222 
08223 /* parse_line
08224 
08225 Returned Value: int
08226    If any of the following functions returns an error code,
08227    this returns that code.
08228      init_block
08229      read_items
08230      enhance_block
08231      check_items
08232    Otherwise, it returns RS274NGC_OK.
08233 
08234 Side effects:
08235    One RS274 line is read into a block and the block is checked for
08236    errors. System parameters may be reset.
08237 
08238 Called by:  rs274ngc_read
08239 
08240 */
08241 
08242 static int parse_line(   /* ARGUMENTS                            */
08243  char * line,            /* array holding a line of RS274 code   */
08244  block_pointer block,    /* pointer to a block to be filled      */
08245  setup_pointer settings) /* pointer to machine settings          */
08246 {
08247   static char name[] SET_TO "parse_line";
08248   int status;
08249 
08250   CHP(init_block (block));
08251   CHP(read_items(block, line, settings->parameters));
08252   CHP(enhance_block(block, settings));
08253   CHP(check_items (block, settings));
08254   return RS274NGC_OK;
08255 }
08256 
08257 /****************************************************************************/
08258 
08259 /* precedence
08260 
08261 Returned Value: int
08262   This returns an integer representing the precedence level of an_operator
08263 
08264 Side Effects: None
08265 
08266 Called by: read_real_expression
08267 
08268 To add additional levels of operator precedence, edit this function.
08269 
08270 */
08271 
08272 
08273 static int precedence( /* ARGUMENTS  */
08274  int an_operator)
08275 {
08276   if (an_operator IS RIGHT_BRACKET)
08277     return 1;
08278   else if (an_operator IS POWER)
08279     return 4;
08280   else if (an_operator >= AND2)
08281     return 2;
08282   else
08283     return 3;
08284 }
08285 
08286 /****************************************************************************/
08287 
08288 /* read_a
08289 
08290 Returned Value: int
08291    If read_real_value returns an error code, this returns that code.
08292    If any of the following errors occur, this returns the error code shown.
08293    Otherwise, it returns RS274NGC_OK.
08294    1. The first character read is not a:
08295       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
08296    2. An a_coordinate has already been inserted in the block:
08297       NCE_MULTIPLE_A_WORDS_ON_ONE_LINE.
08298    3. A values are not allowed: NCE_CANNOT_USE_A_WORD.
08299 
08300 Side effects:
08301    counter is reset.
08302    The a_flag in the block is turned on.
08303    An a_number is inserted in the block.
08304 
08305 Called by: read_one_item
08306 
08307 When this function is called, counter is pointing at an item on the
08308 line that starts with the character 'a', indicating an a_coordinate
08309 setting. The function reads characters which tell how to set the
08310 coordinate, up to the start of the next item or the end of the line.
08311 The counter is then set to point to the character following.
08312 
08313 The value may be a real number or something that evaluates to a
08314 real number, so read_real_value is used to read it. Parameters
08315 may be involved.
08316 
08317 If the AA compiler flag is defined, the a_flag in the block is turned
08318 on and the a_number in the block is set to the value read. If the
08319 AA flag is not defined, (i) if the AXIS_ERROR flag is defined, that means
08320 A values are not allowed, and an error value is returned, (ii) if the
08321 AXIS_ERROR flag is not defined, nothing is done.
08322 
08323 */
08324 
08325 static int read_a(    /* ARGUMENTS                                      */
08326  char * line,         /* string: line of RS274/NGC code being processed */
08327  int * counter,       /* pointer to a counter for position on the line  */
08328  block_pointer block, /* pointer to a block being filled from the line  */
08329  double * parameters) /* array of system parameters                     */
08330 {
08331   static char name[] SET_TO "read_a";
08332   double value;
08333   int status;
08334 
08335   CHK((line[*counter] ISNT 'a'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
08336   *counter SET_TO (*counter + 1);
08337 #ifdef AA
08338   CHK((block->a_flag ISNT OFF), NCE_MULTIPLE_A_WORDS_ON_ONE_LINE); /*AA*/
08339 #endif
08340   CHP(read_real_value(line, counter, &value, parameters));
08341 #ifdef AA
08342   block->a_flag SET_TO ON;
08343   block->a_number SET_TO value;
08344 #else
08345 #ifdef AXIS_ERROR
08346   ERM(NCE_CANNOT_USE_A_WORD);
08347 #endif /* ifdef AXIS_ERROR */
08348 #endif /* ifdef AA */
08349   return RS274NGC_OK;
08350 }
08351 
08352 
08353 /****************************************************************************/
08354 
08355 /* read_atan
08356 
08357 Returned Value: int
08358    If read_real_expression returns an error code, this returns that code.
08359    If any of the following errors occur, this returns the error code shown.
08360    Otherwise, it returns RS274NGC_OK.
08361    1. The first character to read is not a slash:
08362       NCE_SLASH_MISSING_AFTER_FIRST_ATAN_ARGUMENT
08363    2. The second character to read is not a left bracket:
08364       NCE_LEFT_BRACKET_MISSING_AFTER_SLASH_WITH_ATAN
08365 
08366 Side effects:
08367    The computed value is put into what double_ptr points at.
08368    The counter is reset to point to the first character after the
08369    characters which make up the value.
08370 
08371 Called by:
08372    read_unary
08373 
08374 When this function is called, the characters "atan" and the first
08375 argument have already been read, and the value of the first argument
08376 is stored in double_ptr.  This function attempts to read a slash and
08377 the second argument to the atan function, starting at the index given
08378 by the counter and then to compute the value of the atan operation
08379 applied to the two arguments.  The computed value is inserted into
08380 what double_ptr points at.
08381 
08382 The computed value is in the range from -180 degrees to +180 degrees.
08383 The range is not specified in the RS274/NGC manual [NCMS, page 51],
08384 although using degrees (not radians) is specified.
08385 
08386 */
08387 
08388 static int read_atan( /* ARGUMENTS                                      */
08389  char * line,         /* string: line of RS274/NGC code being processed */
08390  int * counter,       /* pointer to a counter for position on line      */
08391  double * double_ptr, /* pointer to double to be read                   */
08392  double * parameters) /* array of system parameters                     */
08393 {
08394   static char name[] SET_TO "read_atan";
08395   double argument2;
08396   int status;
08397 
08398   CHK((line [*counter] ISNT '/'), NCE_SLASH_MISSING_AFTER_FIRST_ATAN_ARGUMENT);
08399   *counter SET_TO (*counter + 1);
08400   CHK((line[*counter] ISNT '['),
08401       NCE_LEFT_BRACKET_MISSING_AFTER_SLASH_WITH_ATAN);
08402   CHP(read_real_expression (line, counter, &argument2, parameters));
08403   *double_ptr SET_TO atan2(*double_ptr, argument2); /* value in radians */
08404   *double_ptr SET_TO ((*double_ptr * 180.0)/PI);    /* convert to degrees */
08405   return RS274NGC_OK;
08406 }
08407 
08408 /****************************************************************************/
08409 
08410 /* read_b
08411 
08412 Returned Value: int
08413    If read_real_value returns an error code, this returns that code.
08414    If any of the following errors occur, this returns the error code shown.
08415    Otherwise, it returns RS274NGC_OK.
08416    1. The first character read is not b:
08417       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
08418    2. A b_coordinate has already been inserted in the block:
08419       NCE_MULTIPLE_B_WORDS_ON_ONE_LINE.
08420    3. B values are not allowed: NCE_CANNOT_USE_B_WORD
08421 
08422 Side effects:
08423    counter is reset.
08424    The b_flag in the block is turned on.
08425    A b_number is inserted in the block.
08426 
08427 Called by: read_one_item
08428 
08429 When this function is called, counter is pointing at an item on the
08430 line that starts with the character 'b', indicating a b_coordinate
08431 setting. The function reads characters which tell how to set the
08432 coordinate, up to the start of the next item or the end of the line.
08433 The counter is then set to point to the character following.
08434 
08435 The value may be a real number or something that evaluates to a
08436 real number, so read_real_value is used to read it. Parameters
08437 may be involved.
08438 
08439 If the BB compiler flag is defined, the b_flag in the block is turned
08440 on and the b_number in the block is set to the value read. If the
08441 BB flag is not defined, (i) if the AXIS_ERROR flag is defined, that means
08442 B values are not allowed, and an error value is returned, (ii) if the
08443 AXIS_ERROR flag is not defined, nothing is done.
08444 
08445 */
08446 
08447 static int read_b(    /* ARGUMENTS                                      */
08448  char * line,         /* string: line of RS274/NGC code being processed */
08449  int * counter,       /* pointer to a counter for position on the line  */
08450  block_pointer block, /* pointer to a block being filled from the line  */
08451  double * parameters) /* array of system parameters                     */
08452 {
08453   static char name[] SET_TO "read_b";
08454   double value;
08455   int status;
08456 
08457   CHK((line[*counter] ISNT 'b'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
08458   *counter SET_TO (*counter + 1);
08459 #ifdef BB
08460   CHK((block->b_flag ISNT OFF), NCE_MULTIPLE_B_WORDS_ON_ONE_LINE); /*BB*/
08461 #endif
08462   CHP(read_real_value(line, counter, &value, parameters));
08463 #ifdef BB
08464   block->b_flag SET_TO ON;
08465   block->b_number SET_TO value;
08466 #else
08467 #ifdef AXIS_ERROR
08468   ERM(NCE_CANNOT_USE_B_WORD);
08469 #endif /* ifdef AXIS_ERROR */
08470 #endif /* ifdef BB */
08471   return RS274NGC_OK;
08472 }
08473 
08474 /****************************************************************************/
08475 
08476 /* read_c
08477 
08478 Returned Value: int
08479    If read_real_value returns an error code, this returns that code.
08480    If any of the following errors occur, this returns the error code shown.
08481    Otherwise, it returns RS274NGC_OK.
08482    1. The first character read is not c:
08483       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
08484    2. An c_coordinate has already been inserted in the block:
08485       NCE_MULTIPLE_C_WORDS_ON_ONE_LINE
08486    3. C values are not allowed: NCE_CANNOT_USE_C_WORD
08487 
08488 Side effects:
08489    counter is reset.
08490    The c_flag in the block is turned on.
08491    A c_number is inserted in the block.
08492 
08493 Called by: read_one_item
08494 
08495 When this function is called, counter is pointing at an item on the
08496 line that starts with the character 'c', indicating an c_coordinate
08497 setting. The function reads characters which tell how to set the
08498 coordinate, up to the start of the next item or the end of the line.
08499 The counter is then set to point to the character following.
08500 
08501 The value may be a real number or something that evaluates to a
08502 real number, so read_real_value is used to read it. Parameters
08503 may be involved.
08504 
08505 If the CC compiler flag is defined, the c_flag in the block is turned
08506 on and the c_number in the block is set to the value read. If the
08507 CC flag is not defined, (i) if the AXIS_ERROR flag is defined, that means
08508 C values are not allowed, and an error value is returned, (ii) if the
08509 AXIS_ERROR flag is not defined, nothing is done.
08510 
08511 */
08512 
08513 static int read_c(    /* ARGUMENTS                                      */
08514  char * line,         /* string: line of RS274/NGC code being processed */
08515  int * counter,       /* pointer to a counter for position on the line  */
08516  block_pointer block, /* pointer to a block being filled from the line  */
08517  double * parameters) /* array of system parameters                     */
08518 {
08519   static char name[] SET_TO "read_c";
08520   double value;
08521   int status;
08522 
08523   CHK((line[*counter] ISNT 'c'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
08524   *counter SET_TO (*counter + 1);
08525 #ifdef CC
08526   CHK((block->c_flag ISNT OFF), NCE_MULTIPLE_C_WORDS_ON_ONE_LINE); /*CC*/
08527 #endif
08528   CHP(read_real_value(line, counter, &value, parameters));
08529 #ifdef CC
08530   block->c_flag SET_TO ON;
08531   block->c_number SET_TO value;
08532 #else
08533 #ifdef AXIS_ERROR
08534   ERM(NCE_CANNOT_USE_C_WORD);
08535 #endif /* ifdef AXIS_ERROR */
08536 #endif /* ifdef CC */
08537   return RS274NGC_OK;
08538 }
08539 
08540 /****************************************************************************/
08541 
08542 /* read_comment
08543 
08544 Returned Value: int
08545   If any of the following errors occur, this returns the error code shown.
08546    Otherwise, it returns RS274NGC_OK.
08547    1. The first character read is not '(' ,
08548       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
08549 
08550 Side effects:
08551    The counter is reset to point to the character following the comment.
08552    The comment string, without parentheses, is copied into the comment
08553    area of the block.
08554 
08555 Called by: read_one_item
08556 
08557 When this function is called, counter is pointing at an item on the
08558 line that starts with the character '(', indicating a comment is
08559 beginning. The function reads characters of the comment, up to and
08560 including the comment closer ')'.
08561 
08562 It is expected that the format of a comment will have been checked (by
08563 read_text or read_keyboard_line) and bad format comments will
08564 have prevented the system from getting this far, so that this function
08565 can assume a close parenthesis will be found when an open parenthesis
08566 has been found, and that comments are not nested.
08567 
08568 The "parameters" argument is not used in this function. That argument is
08569 present only so that this will have the same argument list as the other
08570 "read_XXX" functions called using a function pointer by read_one_item.
08571 
08572 */
08573 
08574 static int read_comment( /* ARGUMENTS                                     */
08575  char * line,            /* string: line of RS274 code being processed    */
08576  int * counter,          /* pointer to a counter for position on the line */
08577  block_pointer block,    /* pointer to a block being filled from the line */
08578  double * parameters)    /* array of system parameters                    */
08579 {
08580   static char name[] SET_TO "read_comment";
08581   int n;
08582 
08583   CHK((line[*counter] ISNT '('), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
08584   (*counter)++;
08585   for (n SET_TO 0; line[*counter] ISNT ')' ; (*counter)++, n++)
08586     {
08587       block->comment[n] SET_TO line[*counter];
08588     }
08589   block->comment[n] SET_TO 0;
08590   (*counter)++;
08591   return RS274NGC_OK;
08592 }
08593 
08594 /****************************************************************************/
08595 
08596 /* read_d
08597 
08598 Returned Value: int
08599    If read_integer_value returns an error code, this returns that code.
08600    If any of the following errors occur, this returns the error code shown.
08601    Otherwise, it returns RS274NGC_OK.
08602    1. The first character read is not d:
08603       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
08604    2. A d_number has already been inserted in the block:
08605       NCE_MULTIPLE_D_WORDS_ON_ONE_LINE
08606    3. The d_number is negative: NCE_NEGATIVE_D_WORD_TOOL_RADIUS_INDEX_USED
08607    4. The d_number is more than _setup.tool_max: NCE_TOOL_RADIUS_INDEX_TOO_BIG
08608 
08609 Side effects:
08610    counter is reset to the character following the tool number.
08611    A d_number is inserted in the block.
08612 
08613 Called by: read_one_item
08614 
08615 When this function is called, counter is pointing at an item on the
08616 line that starts with the character 'd', indicating an index into a
08617 table of tool diameters.  The function reads characters which give the
08618 (integer) value of the index. The value may not be more than
08619 _setup.tool_max and may not be negative, but it may be zero. The range
08620 is checked here.
08621 
08622 read_integer_value allows a minus sign, so a check for a negative value
08623 is made here, and the parameters argument is also needed.
08624 
08625 */
08626 
08627 static int read_d(    /* ARGUMENTS                                     */
08628  char * line,         /* string: line of RS274 code being processed    */
08629  int * counter,       /* pointer to a counter for position on the line */
08630  block_pointer block, /* pointer to a block being filled from the line */
08631  double * parameters) /* array of system parameters                    */
08632 {
08633   static char name[] SET_TO "read_d";
08634   int value;
08635   int status;
08636 
08637   CHK((line[*counter] ISNT 'd'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
08638   *counter SET_TO (*counter + 1);
08639   CHK((block->d_number > -1), NCE_MULTIPLE_D_WORDS_ON_ONE_LINE);
08640   CHP(read_integer_value(line, counter, &value, parameters));
08641   CHK((value < 0), NCE_NEGATIVE_D_WORD_TOOL_RADIUS_INDEX_USED);
08642   CHK((value > _setup.tool_max), NCE_TOOL_RADIUS_INDEX_TOO_BIG);
08643   block->d_number SET_TO value;
08644   return RS274NGC_OK;
08645 }
08646 
08647 /****************************************************************************/
08648 
08649 /* read_f
08650 
08651 Returned Value: int
08652    If read_real_value returns an error code, this returns that code.
08653    If any of the following errors occur, this returns the error code shown.
08654    Otherwise, it returns RS274NGC_OK.
08655    1. The first character read is not f:
08656       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
08657    2. An f_number has already been inserted in the block:
08658       NCE_MULTIPLE_F_WORDS_ON_ONE_LINE
08659    3. The f_number is negative: NCE_NEGATIVE_F_WORD_USED
08660 
08661 Side effects:
08662    counter is reset to point to the first character following the f_number.
08663    The f_number is inserted in block.
08664 
08665 Called by: read_one_item
08666 
08667 When this function is called, counter is pointing at an item on the
08668 line that starts with the character 'f'. The function reads characters
08669 which tell how to set the f_number, up to the start of the next item
08670 or the end of the line. This information is inserted in the block.
08671 
08672 The value may be a real number or something that evaluates to a real
08673 number, so read_real_value is used to read it. Parameters may be
08674 involved, so the parameters argument is required. The value is always
08675 a feed rate.
08676 
08677 */
08678 
08679 static int read_f(    /* ARGUMENTS                                     */
08680  char * line,         /* string: line of RS274 code being processed    */
08681  int * counter,       /* pointer to a counter for position on the line */
08682  block_pointer block, /* pointer to a block being filled from the line */
08683  double * parameters) /* array of system parameters                    */
08684 {
08685   static char name[] SET_TO "read_f";
08686   double value;
08687   int status;
08688 
08689   CHK((line[*counter] ISNT 'f'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
08690   *counter SET_TO (*counter + 1);
08691   CHK((block->f_number > -1.0), NCE_MULTIPLE_F_WORDS_ON_ONE_LINE);
08692   CHP(read_real_value(line, counter, &value, parameters));
08693   CHK((value < 0.0), NCE_NEGATIVE_F_WORD_USED);
08694   block->f_number SET_TO value;
08695   return RS274NGC_OK;
08696 }
08697 
08698 /****************************************************************************/
08699 
08700 /* read_g
08701 
08702 Returned Value: int
08703    If read_real_value returns an error code, this returns that code.
08704    If any of the following errors occur, this returns the error code shown.
08705    Otherwise, it returns RS274NGC_OK.
08706    1. The first character read is not g:
08707       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
08708    2. The value is negative: NCE_NEGATIVE_G_CODE_USED
08709    3. The value differs from a number ending in an even tenth by more
08710       than 0.0001: NCE_G_CODE_OUT_OF_RANGE
08711    4. The value is greater than 99.9: NCE_G_CODE_OUT_OF_RANGE
08712    5. The value is not the number of a valid g code: NCE_UNKNOWN_G_CODE_USED
08713    6. Another g code from the same modal group has already been
08714       inserted in the block: NCE_TWO_G_CODES_USED_FROM_SAME_MODAL_GROUP
08715 
08716 Side effects:
08717    counter is reset to the character following the end of the g_code.
08718    A g code is inserted as the value of the appropriate mode in the
08719    g_modes array in the block.
08720    The g code counter in the block is increased by 1.
08721 
08722 Called by: read_one_item
08723 
08724 When this function is called, counter is pointing at an item on the
08725 line that starts with the character 'g', indicating a g_code.  The
08726 function reads characters which tell how to set the g_code.
08727 
08728 The RS274/NGC manual [NCMS, page 51] allows g_codes to be represented
08729 by expressions and provide [NCMS, 71 - 73] that a g_code must evaluate
08730 to to a number of the form XX.X (59.1, for example). The manual does not
08731 say how close an expression must come to one of the allowed values for
08732 it to be legitimate. Is 59.099999 allowed to mean 59.1, for example?
08733 In the interpreter, we adopt the convention that the evaluated number
08734 for the g_code must be within 0.0001 of a value of the form XX.X
08735 
08736 To simplify the handling of g_codes, we convert them to integers by
08737 multiplying by 10 and rounding down or up if within 0.001 of an
08738 integer. Other functions that deal with g_codes handle them
08739 symbolically, however. The symbols are defined in rs274NGC.hh
08740 where G_1 is 10, G_83 is 830, etc.
08741 
08742 This allows any number of g_codes on one line, provided that no two
08743 are in the same modal group.
08744 
08745 */
08746 
08747 static int read_g(    /* ARGUMENTS                                      */
08748  char * line,         /* string: line of RS274/NGC code being processed */
08749  int * counter,       /* pointer to a counter for position on the line  */
08750  block_pointer block, /* pointer to a block being filled from the line  */
08751  double * parameters) /* array of system parameters                     */
08752 {
08753   static char name[] SET_TO "read_g";
08754   double value_read;
08755   int value;
08756   int mode;
08757   int status;
08758 
08759   CHK((line[*counter] ISNT 'g'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
08760   *counter SET_TO (*counter + 1);
08761   CHP(read_real_value(line, counter, &value_read, parameters));
08762   value_read SET_TO (10.0 * value_read);
08763   value SET_TO (int)floor(value_read);
08764 
08765   if ((value_read - value) > 0.999)
08766     value SET_TO (int)ceil(value_read);
08767   else if ((value_read - value) > 0.001)
08768     ERM(NCE_G_CODE_OUT_OF_RANGE);
08769 
08770   CHK((value > 999), NCE_G_CODE_OUT_OF_RANGE);
08771   CHK((value < 0), NCE_NEGATIVE_G_CODE_USED);
08772   mode SET_TO _gees[value];
08773   CHK((mode IS -1), NCE_UNKNOWN_G_CODE_USED);
08774   CHK((block->g_modes[mode] ISNT -1),
08775       NCE_TWO_G_CODES_USED_FROM_SAME_MODAL_GROUP);
08776   block->g_modes[mode] SET_TO value;
08777   return RS274NGC_OK;
08778 }
08779 
08780 /****************************************************************************/
08781 
08782 /* read_h
08783 
08784 Returned Value: int
08785    If read_integer_value returns an error code, this returns that code.
08786    If any of the following errors occur, this returns the error code shown.
08787    Otherwise, it returns RS274NGC_OK.
08788    1. The first character read is not h:
08789       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
08790    2. An h_number has already been inserted in the block:
08791       NCE_MULTIPLE_H_WORDS_ON_ONE_LINE
08792    3. The value is negative: NCE_NEGATIVE_H_WORD_TOOL_LENGTH_OFFSET_INDEX_USED
08793    4. The value is greater than _setup.tool_max:
08794       NCE_TOOL_LENGTH_OFFSET_INDEX_TOO_BIG
08795 
08796 Side effects:
08797    counter is reset to the character following the h_number.
08798    An h_number is inserted in the block.
08799 
08800 Called by: read_one_item
08801 
08802 When this function is called, counter is pointing at an item on the
08803 line that starts with the character 'h', indicating a tool length
08804 offset index.  The function reads characters which give the (integer)
08805 value of the tool length offset index (not the actual distance of the
08806 offset).
08807 
08808 */
08809 
08810 static int read_h(    /* ARGUMENTS                                      */
08811  char * line,         /* string: line of RS274/NGC code being processed */
08812  int * counter,       /* pointer to a counter for position on the line  */
08813  block_pointer block, /* pointer to a block being filled from the line  */
08814  double * parameters) /* array of system parameters                     */
08815 {
08816   static char name[] SET_TO "read_h";
08817   int value;
08818   int status;
08819 
08820   CHK((line[*counter] ISNT 'h'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
08821   *counter SET_TO (*counter + 1);
08822   CHK((block->h_number > -1), NCE_MULTIPLE_H_WORDS_ON_ONE_LINE);
08823   CHP(read_integer_value(line, counter, &value, parameters));
08824   CHK((value < 0), NCE_NEGATIVE_H_WORD_TOOL_LENGTH_OFFSET_INDEX_USED);
08825   CHK((value > _setup.tool_max), NCE_TOOL_LENGTH_OFFSET_INDEX_TOO_BIG);
08826   block->h_number SET_TO value;
08827   return RS274NGC_OK;
08828 }
08829 
08830 /****************************************************************************/
08831 
08832 /* read_i
08833 
08834 Returned Value: int
08835    If read_real_value returns an error code, this returns that code.
08836    If any of the following errors occur, this returns the error code shown.
08837    Otherwise, it returns RS274NGC_OK.
08838    1. The first character read is not i:
08839       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
08840    2. An i_coordinate has already been inserted in the block:
08841       NCE_MULTIPLE_I_WORDS_ON_ONE_LINE
08842 
08843 Side effects:
08844    counter is reset.
08845    The i_flag in the block is turned on.
08846    An i_coordinate setting is inserted in the block.
08847 
08848 Called by: read_one_item
08849 
08850 When this function is called, counter is pointing at an item on the
08851 line that starts with the character 'i', indicating a i_coordinate
08852 setting. The function reads characters which tell how to set the
08853 coordinate, up to the start of the next item or the end of the line.
08854 This information is inserted in the block. The counter is then set to
08855 point to the character following.
08856 
08857 The value may be a real number or something that evaluates to a
08858 real number, so read_real_value is used to read it. Parameters
08859 may be involved.
08860 
08861 */
08862 
08863 static int read_i(    /* ARGUMENTS                                      */
08864  char * line,         /* string: line of RS274 code being processed     */
08865  int * counter,       /* pointer to a counter for position on the line  */
08866  block_pointer block, /* pointer to a block being filled from the line  */
08867  double * parameters) /* array of system parameters                     */
08868 {
08869   static char name[] SET_TO "read_i";
08870   double value;
08871   int status;
08872 
08873   CHK((line[*counter] ISNT 'i'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
08874   *counter SET_TO (*counter + 1);
08875   CHK((block->i_flag ISNT OFF), NCE_MULTIPLE_I_WORDS_ON_ONE_LINE);
08876   CHP(read_real_value(line, counter, &value, parameters));
08877   block->i_flag SET_TO ON;
08878   block->i_number SET_TO value;
08879   return RS274NGC_OK;
08880 }
08881 
08882 /****************************************************************************/
08883 
08884 /* read_integer_unsigned
08885 
08886 Returned Value: int
08887    If any of the following errors occur, this returns the error shown.
08888    Otherwise, RS274NGC_OK is returned.
08889    1. The first character is not a digit: NCE_BAD_FORMAT_UNSIGNED_INTEGER
08890    2. sscanf fails: NCE_SSCANF_FAILED
08891 
08892 Side effects:
08893    The number read from the line is put into what integer_ptr points at.
08894 
08895 Called by: read_line_number
08896 
08897 This reads an explicit unsigned (positive) integer from a string,
08898 starting from the position given by *counter. It expects to find one
08899 or more digits. Any character other than a digit terminates reading
08900 the integer. Note that if the first character is a sign (+ or -),
08901 an error will be reported (since a sign is not a digit).
08902 
08903 */
08904 
08905 static int read_integer_unsigned(   /* ARGUMENTS                       */
08906  char * line,         /* string: line of RS274 code being processed    */
08907  int * counter,       /* pointer to a counter for position on the line */
08908  int * integer_ptr)   /* pointer to the value being read               */
08909 {
08910   static char name[] SET_TO "read_integer_unsigned";
08911   int n;
08912   char c;
08913 
08914   for (n SET_TO *counter; ; n++)
08915     {
08916       c SET_TO line[n];
08917       if ((c < 48) OR (c > 57))
08918         break;
08919     }
08920   CHK((n IS *counter), NCE_BAD_FORMAT_UNSIGNED_INTEGER);
08921   if (sscanf(line + *counter, "%d", integer_ptr) IS 0)
08922     ERM(NCE_SSCANF_FAILED);
08923   *counter SET_TO n;
08924   return RS274NGC_OK;
08925 }
08926 
08927 /****************************************************************************/
08928 
08929 /* read_integer_value
08930 
08931 Returned Value: int
08932    If read_real_value returns an error code, this returns that code.
08933    If any of the following errors occur, this returns the error code shown.
08934    Otherwise, it returns RS274NGC_OK.
08935    1. The returned value is not close to an integer:
08936       NCE_NON_INTEGER_VALUE_FOR_INTEGER
08937 
08938 Side effects:
08939    The number read from the line is put into what integer_ptr points at.
08940 
08941 Called by:
08942    read_d
08943    read_l
08944    read_h
08945    read_m
08946    read_parameter
08947    read_parameter_setting
08948    read_t
08949 
08950 This reads an integer (positive, negative or zero) from a string,
08951 starting from the position given by *counter. The value being
08952 read may be written with a decimal point or it may be an expression
08953 involving non-integers, as long as the result comes out within 0.0001
08954 of an integer.
08955 
08956 This proceeds by calling read_real_value and checking that it is
08957 close to an integer, then returning the integer it is close to.
08958 
08959 */
08960 
08961 static int read_integer_value( /* ARGUMENTS                                 */
08962  char * line,             /* string: line of RS274/NGC code being processed */
08963  int * counter,           /* pointer to a counter for position on the line  */
08964  int * integer_ptr,       /* pointer to the value being read                */
08965  double * parameters)     /* array of system parameters                     */
08966 {
08967   static char name[] SET_TO "read_integer_value";
08968   double float_value;
08969   int status;
08970 
08971   CHP(read_real_value(line, counter, &float_value, parameters));
08972   *integer_ptr SET_TO (int)floor(float_value);
08973   if ((float_value - *integer_ptr) > 0.9999)
08974     {
08975       *integer_ptr SET_TO (int)ceil(float_value);
08976     }
08977   else if ((float_value - *integer_ptr) > 0.0001)
08978     ERM(NCE_NON_INTEGER_VALUE_FOR_INTEGER);
08979   return RS274NGC_OK;
08980 }
08981 
08982 /****************************************************************************/
08983 
08984 /* read_items
08985 
08986 Returned Value: int
08987    If read_line_number or read_one_item returns an error code,
08988    this returns that code.
08989    Otherwise, it returns RS274NGC_OK.
08990 
08991 Side effects:
08992    One line of RS274 code is read and data inserted into a block.
08993    The counter which is passed around among the readers is initialized.
08994    System parameters may be reset.
08995 
08996 Called by: parse_line
08997 
08998 */
08999 
09000 static int read_items( /* ARGUMENTS                                      */
09001  block_pointer block,  /* pointer to a block being filled from the line  */
09002  char * line,          /* string: line of RS274/NGC code being processed */
09003  double * parameters)  /* array of system parameters                     */
09004 {
09005   static char name[] SET_TO "read_items";
09006   int counter;
09007   int length;
09008   int status;
09009 
09010   length SET_TO strlen(line);
09011   counter SET_TO 0;
09012 
09013   if (line[counter] IS '/') /* skip the slash character if first */
09014     counter++;
09015   if (line[counter] IS 'n')
09016     {
09017       CHP(read_line_number(line, &counter, block));
09018     }
09019   for ( ; counter < length; )
09020     {
09021       CHP(read_one_item (line, &counter, block, parameters));
09022     }
09023   return RS274NGC_OK;
09024 }
09025 
09026 /****************************************************************************/
09027 
09028 /* read_j
09029 
09030 Returned Value: int
09031    If read_real_value returns an error code, this returns that code.
09032    If any of the following errors occur, this returns the error code shown.
09033    Otherwise, it returns RS274NGC_OK.
09034    1. The first character read is not j:
09035       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09036    2. A j_coordinate has already been inserted in the block.
09037       NCE_MULTIPLE_J_WORDS_ON_ONE_LINE
09038 
09039 Side effects:
09040    counter is reset.
09041    The j_flag in the block is turned on.
09042    A j_coordinate setting is inserted in the block.
09043 
09044 Called by: read_one_item
09045 
09046 When this function is called, counter is pointing at an item on the
09047 line that starts with the character 'j', indicating a j_coordinate
09048 setting. The function reads characters which tell how to set the
09049 coordinate, up to the start of the next item or the end of the line.
09050 This information is inserted in the block. The counter is then set to
09051 point to the character following.
09052 
09053 The value may be a real number or something that evaluates to a real
09054 number, so read_real_value is used to read it. Parameters may be
09055 involved.
09056 
09057 */
09058 
09059 static int read_j(    /* ARGUMENTS                                      */
09060  char * line,         /* string: line of RS274 code being processed     */
09061  int * counter,       /* pointer to a counter for position on the line  */
09062  block_pointer block, /* pointer to a block being filled from the line  */
09063  double * parameters) /* array of system parameters                     */
09064 {
09065   static char name[] SET_TO "read_j";
09066   double value;
09067   int status;
09068 
09069   CHK((line[*counter] ISNT 'j'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
09070   *counter SET_TO (*counter + 1);
09071   CHK((block->j_flag ISNT OFF), NCE_MULTIPLE_J_WORDS_ON_ONE_LINE);
09072   CHP(read_real_value(line, counter, &value, parameters));
09073   block->j_flag SET_TO ON;
09074   block->j_number SET_TO value;
09075   return RS274NGC_OK;
09076 }
09077 
09078 /****************************************************************************/
09079 
09080 /* read_k
09081 
09082 Returned Value: int
09083    If read_real_value returns an error code, this returns that code.
09084    If any of the following errors occur, this returns the error code shown.
09085    Otherwise, it returns RS274NGC_OK.
09086    1. The first character read is not k:
09087       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09088    2. A k_coordinate has already been inserted in the block:
09089       NCE_MULTIPLE_K_WORDS_ON_ONE_LINE
09090 
09091 Side effects:
09092    counter is reset.
09093    The k_flag in the block is turned on.
09094    A k_coordinate setting is inserted in the block.
09095 
09096 Called by: read_one_item
09097 
09098 When this function is called, counter is pointing at an item on the
09099 line that starts with the character 'k', indicating a k_coordinate
09100 setting. The function reads characters which tell how to set the
09101 coordinate, up to the start of the next item or the end of the line.
09102 This information is inserted in the block. The counter is then set to
09103 point to the character following.
09104 
09105 The value may be a real number or something that evaluates to a real
09106 number, so read_real_value is used to read it. Parameters may be
09107 involved.
09108 
09109 */
09110 
09111 static int read_k(    /* ARGUMENTS                                      */
09112  char * line,         /* string: line of RS274 code being processed     */
09113  int * counter,       /* pointer to a counter for position on the line  */
09114  block_pointer block, /* pointer to a block being filled from the line  */
09115  double * parameters) /* array of system parameters                     */
09116 {
09117   static char name[] SET_TO "read_k";
09118   double value;
09119   int status;
09120 
09121   CHK((line[*counter] ISNT 'k'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
09122   *counter SET_TO (*counter + 1);
09123   CHK((block->k_flag ISNT OFF), NCE_MULTIPLE_K_WORDS_ON_ONE_LINE);
09124   CHP(read_real_value(line, counter, &value, parameters));
09125   block->k_flag SET_TO ON;
09126   block->k_number SET_TO value;
09127   return RS274NGC_OK;
09128 }
09129 
09130 /****************************************************************************/
09131 
09132 /* read_l
09133 
09134 Returned Value: int
09135    If read_integer_value returns an error code, this returns that code.
09136    If any of the following errors occur, this returns the error code shown.
09137    Otherwise, it returns RS274NGC_OK.
09138    1. The first character read is not l:
09139       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09140    2. An l_number has already been inserted in the block:
09141       NCE_MULTIPLE_L_WORDS_ON_ONE_LINE
09142    3. the l_number is negative: NCE_NEGATIVE_L_WORD_USED
09143 
09144 Side effects:
09145    counter is reset to the character following the l number.
09146    An l code is inserted in the block as the value of l.
09147 
09148 Called by: read_one_item
09149 
09150 When this function is called, counter is pointing at an item on the
09151 line that starts with the character 'l', indicating an L code.
09152 The function reads characters which give the (integer) value of the
09153 L code.
09154 
09155 L codes are used for:
09156 1. the number of times a canned cycle should be repeated.
09157 2. a key with G10.
09158 
09159 */
09160 
09161 static int read_l(    /* ARGUMENTS                                      */
09162  char * line,         /* string: line of RS274/NGC code being processed */
09163  int * counter,       /* pointer to a counter for position on the line  */
09164  block_pointer block, /* pointer to a block being filled from the line  */
09165  double * parameters) /* array of system parameters                     */
09166 {
09167   static char name[] SET_TO "read_l";
09168   int value;
09169   int status;
09170 
09171   CHK((line[*counter] ISNT 'l'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
09172   *counter SET_TO (*counter + 1);
09173   CHK((block->l_number > -1), NCE_MULTIPLE_L_WORDS_ON_ONE_LINE);
09174   CHP(read_integer_value(line, counter, &value, parameters));
09175   CHK((value < 0), NCE_NEGATIVE_L_WORD_USED);
09176   block->l_number SET_TO value;
09177   return RS274NGC_OK;
09178 }
09179 
09180 /****************************************************************************/
09181 
09182 /* read_line_number
09183 
09184 Returned Value: int
09185    If read_integer_unsigned returns an error code, this returns that code.
09186    If any of the following errors occur, this returns the error code shown.
09187    Otherwise, it returns RS274NGC_OK.
09188    1. The first character read is not n:
09189       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09190    2. The line number is too large (more than 99999):
09191       NCE_LINE_NUMBER_GREATER_THAN_99999
09192 
09193 Side effects:
09194    counter is reset to the character following the line number.
09195    A line number is inserted in the block.
09196 
09197 Called by: read_items
09198 
09199 When this function is called, counter is pointing at an item on the
09200 line that starts with the character 'n', indicating a line number.
09201 The function reads characters which give the (integer) value of the
09202 line number.
09203 
09204 Note that extra initial zeros in a line number will not cause the
09205 line number to be too large.
09206 
09207 */
09208 
09209 static int read_line_number( /* ARGUMENTS                               */
09210  char * line,         /* string: line of RS274    code being processed  */
09211  int * counter,       /* pointer to a counter for position on the line  */
09212  block_pointer block) /* pointer to a block being filled from the line  */
09213 {
09214   static char name[] SET_TO "read_line_number";
09215   int value;
09216   int status;
09217 
09218   CHK((line[*counter] ISNT 'n'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
09219   *counter SET_TO (*counter + 1);
09220   CHP(read_integer_unsigned(line, counter, &value));
09221   CHK((value > 99999), NCE_LINE_NUMBER_GREATER_THAN_99999);
09222   block->line_number SET_TO value;
09223   return RS274NGC_OK;
09224 }
09225 
09226 /****************************************************************************/
09227 
09228 /* read_m
09229 
09230 Returned Value:
09231    If read_integer_value returns an error code, this returns that code.
09232    If any of the following errors occur, this returns the error code shown.
09233    Otherwise, it returns RS274NGC_OK.
09234    1. The first character read is not m:
09235       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09236    2. The value is negative: NCE_NEGATIVE_M_CODE_USED
09237    3. The value is greater than 99: NCE_M_CODE_GREATER_THAN_99
09238    4. The m code is not known to the system: NCE_UNKNOWN_M_CODE_USED
09239    5. Another m code in the same modal group has already been read:
09240       NCE_TWO_M_CODES_USED_FROM_SAME_MODAL_GROUP
09241 
09242 Side effects:
09243    counter is reset to the character following the m number.
09244    An m code is inserted as the value of the appropriate mode in the
09245    m_modes array in the block.
09246    The m code counter in the block is increased by 1.
09247 
09248 Called by: read_one_item
09249 
09250 When this function is called, counter is pointing at an item on the
09251 line that starts with the character 'm', indicating an m code.
09252 The function reads characters which give the (integer) value of the
09253 m code.
09254 
09255 read_integer_value allows a minus sign, so a check for a negative value
09256 is needed here, and the parameters argument is also needed.
09257 
09258 */
09259 
09260 static int read_m(    /* ARGUMENTS                                     */
09261  char * line,         /* string: line of RS274 code being processed    */
09262  int * counter,       /* pointer to a counter for position on the line */
09263  block_pointer block, /* pointer to a block being filled from the line */
09264  double * parameters) /* array of system parameters                    */
09265 {
09266   static char name[] SET_TO "read_m";
09267   int value;
09268   int mode;
09269   int status;
09270 
09271   CHK((line[*counter] ISNT 'm'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
09272   *counter SET_TO (*counter + 1);
09273   CHP(read_integer_value(line, counter, &value, parameters));
09274   CHK((value < 0), NCE_NEGATIVE_M_CODE_USED);
09275   CHK((value > 99), NCE_M_CODE_GREATER_THAN_99);
09276   mode SET_TO _ems[value];
09277   CHK((mode IS -1), NCE_UNKNOWN_M_CODE_USED);
09278   CHK((block->m_modes[mode] ISNT -1),
09279       NCE_TWO_M_CODES_USED_FROM_SAME_MODAL_GROUP);
09280   block->m_modes[mode] SET_TO value;
09281   block->m_count++;
09282   return RS274NGC_OK;
09283 }
09284 
09285 /****************************************************************************/
09286 
09287 /* read_one_item
09288 
09289 Returned Value: int
09290    If a reader function which is called returns an error code, that
09291    error code is returned.
09292    If any of the following errors occur, this returns the error code shown.
09293    Otherwise, it returns RS274NGC_OK.
09294    1. the first character read is not a known character for starting a
09295    word: NCE_BAD_CHARACTER_USED
09296 
09297 Side effects:
09298    This function reads one item from a line of RS274/NGC code and inserts
09299    the information in a block. System parameters may be reset.
09300 
09301 Called by: read_items.
09302 
09303 When this function is called, the counter is set so that the position
09304 being considered is the first position of a word. The character at
09305 that position must be one known to the system.  In this version those
09306 characters are: a,b,c,d,f,g,h,i,j,k,l,m,n,p,q,r,s,t,x,y,z,(,#.
09307 However, read_items calls read_line_number directly if the first word
09308 begins with n, so no read function is included in the "_readers" array
09309 for the letter n. Thus, if an n word is encountered in the middle of
09310 a line, this function reports NCE_BAD_CHARACTER_USED.
09311 
09312 The function looks for a letter or special character and calls a
09313 selected function according to what the letter or character is.  The
09314 selected function will be responsible to consider all the characters
09315 that comprise the remainder of the item, and reset the pointer so that
09316 it points to the next character after the end of the item (which may be
09317 the end of the line or the first character of another item).
09318 
09319 After an item is read, the counter is set at the index of the
09320 next unread character. The item data is stored in the block.
09321 
09322 It is expected that the format of a comment will have been checked;
09323 this is being done by close_and_downcase. Bad format comments will
09324 have prevented the system from getting this far, so that this function
09325 can assume a close parenthesis will be found when an open parenthesis
09326 has been found, and that comments are not nested.
09327 
09328 */
09329 
09330 static int read_one_item( /* ARGUMENTS                                      */
09331  char * line,             /* string: line of RS274/NGC code being processed */
09332  int * counter,           /* pointer to a counter for position on the line  */
09333  block_pointer block,     /* pointer to a block being filled from the line  */
09334  double * parameters)     /* array of system parameters                     */
09335 {
09336   static char name[] SET_TO "read_one_item";
09337   int status;
09338   read_function_pointer function_pointer;
09339   char letter;
09340 
09341   letter SET_TO line[*counter];  /* check if in array range */
09342   CHK(((letter < 0) OR (letter > 'z')), NCE_BAD_CHARACTER_USED);
09343   function_pointer SET_TO _readers[letter];
09344   CHK((function_pointer IS 0), NCE_BAD_CHARACTER_USED);
09345   CHP(function_pointer(line, counter, block, parameters));
09346   return RS274NGC_OK;
09347 }
09348 
09349 /****************************************************************************/
09350 
09351 /* read_operation
09352 
09353 Returned Value: int
09354    If any of the following errors occur, this returns the error code shown.
09355    Otherwise, it returns RS274NGC_OK.
09356    1. The operation is unknown:
09357       NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_A
09358       NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_M
09359       NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_O
09360       NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_X
09361       NCE_UNKNOWN_OPERATION
09362    2. The line ends without closing the expression: NCE_UNCLOSED_EXPRESSION
09363 
09364 Side effects:
09365    An integer representing the operation is put into what operation points
09366    at.  The counter is reset to point to the first character after the
09367    operation.
09368 
09369 Called by: read_real_expression
09370 
09371 This expects to be reading a binary operation (+, -, /, *, **, and,
09372 mod, or, xor) or a right bracket (]). If one of these is found, the
09373 value of operation is set to the symbolic value for that operation.
09374 If not, an error is reported as described above.
09375 
09376 */
09377 
09378 static int read_operation( /* ARGUMENTS                                      */
09379  char * line,              /* string: line of RS274/NGC code being processed */
09380  int * counter,            /* pointer to a counter for position on the line  */
09381  int * operation)          /* pointer to operation to be read                */
09382 {
09383   static char name[] SET_TO "read_operation";
09384   char c;
09385 
09386   c SET_TO line[*counter];
09387   *counter SET_TO (*counter + 1);
09388   switch(c)
09389     {
09390     case '+':
09391       *operation SET_TO PLUS;
09392       break;
09393     case '-':
09394       *operation SET_TO MINUS;
09395       break;
09396     case '/':
09397       *operation SET_TO DIVIDED_BY;
09398       break;
09399     case '*':
09400       if(line[*counter] IS '*')
09401         {
09402           *operation SET_TO POWER;
09403           *counter SET_TO (*counter + 1);
09404         }
09405       else
09406         *operation SET_TO TIMES;
09407       break;
09408     case ']':
09409       *operation SET_TO RIGHT_BRACKET;
09410       break;
09411     case 'a':
09412       if((line[*counter] IS 'n') AND (line[(*counter)+1] IS 'd'))
09413         {
09414           *operation SET_TO AND2;
09415           *counter SET_TO (*counter + 2);
09416         }
09417       else
09418         ERM(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_A);
09419       break;
09420     case 'm':
09421       if((line[*counter] IS 'o') AND (line[(*counter)+1] IS 'd'))
09422         {
09423           *operation SET_TO MODULO;
09424           *counter SET_TO (*counter + 2);
09425         }
09426       else
09427         ERM(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_M);
09428       break;
09429     case 'o':
09430       if(line[*counter] IS 'r')
09431         {
09432           *operation SET_TO NON_EXCLUSIVE_OR;
09433           *counter SET_TO (*counter + 1);
09434         }
09435       else
09436         ERM(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_O);
09437       break;
09438     case 'x':
09439       if((line[*counter] IS 'o') AND (line[(*counter)+1] IS 'r'))
09440         {
09441           *operation SET_TO EXCLUSIVE_OR;
09442           *counter SET_TO (*counter + 2);
09443         }
09444       else
09445         ERM(NCE_UNKNOWN_OPERATION_NAME_STARTING_WITH_X);
09446       break;
09447     case 0:
09448       ERM(NCE_UNCLOSED_EXPRESSION);
09449     default:
09450       ERM(NCE_UNKNOWN_OPERATION);
09451     }
09452   return RS274NGC_OK;
09453 }
09454 
09455 /****************************************************************************/
09456 
09457 /* read_operation_unary
09458 
09459 Returned Value: int
09460    If the operation is not a known unary operation, this returns one of
09461    the following error codes:
09462    NCE_UNKNOWN_WORD_STARTING_WITH_A
09463    NCE_UNKNOWN_WORD_STARTING_WITH_C
09464    NCE_UNKNOWN_WORD_STARTING_WITH_E
09465    NCE_UNKNOWN_WORD_STARTING_WITH_F
09466    NCE_UNKNOWN_WORD_STARTING_WITH_L
09467    NCE_UNKNOWN_WORD_STARTING_WITH_R
09468    NCE_UNKNOWN_WORD_STARTING_WITH_S
09469    NCE_UNKNOWN_WORD_STARTING_WITH_T
09470    NCE_UNKNOWN_WORD_WHERE_UNARY_OPERATION_COULD_BE
09471    Otherwise, this returns RS274NGC_OK.
09472 
09473 Side effects:
09474    An integer code for the name of the operation read from the
09475    line is put into what operation points at.
09476    The counter is reset to point to the first character after the
09477    characters which make up the operation name.
09478 
09479 Called by:
09480    read_unary
09481 
09482 This attempts to read the name of a unary operation out of the line,
09483 starting at the index given by the counter. Known operations are:
09484 abs, acos, asin, atan, cos, exp, fix, fup, ln, round, sin, sqrt, tan.
09485 
09486 */
09487 
09488 static int read_operation_unary( /* ARGUMENTS                               */
09489  char * line,             /* string: line of RS274/NGC code being processed */
09490  int * counter,           /* pointer to a counter for position on the line  */
09491  int * operation)         /* pointer to operation to be read                */
09492 {
09493   static char name[] SET_TO "read_operation_unary";
09494   char c;
09495 
09496   c SET_TO line[*counter];
09497   *counter SET_TO (*counter + 1);
09498   switch (c)
09499     {
09500     case 'a':
09501       if((line[*counter] IS 'b') AND (line[(*counter)+1] IS 's'))
09502         {
09503           *operation SET_TO ABS;
09504           *counter SET_TO (*counter + 2);
09505         }
09506       else if(strncmp((line + *counter), "cos", 3) IS 0)
09507         {
09508           *operation SET_TO ACOS;
09509           *counter SET_TO (*counter + 3);
09510         }
09511       else if(strncmp((line + *counter), "sin", 3) IS 0)
09512         {
09513           *operation SET_TO ASIN;
09514           *counter SET_TO (*counter + 3);
09515         }
09516       else if(strncmp((line + *counter), "tan", 3) IS 0)
09517         {
09518           *operation SET_TO ATAN;
09519           *counter SET_TO (*counter + 3);
09520         }
09521       else
09522         ERM(NCE_UNKNOWN_WORD_STARTING_WITH_A);
09523       break;
09524     case 'c':
09525       if((line[*counter] IS 'o') AND (line[(*counter)+1] IS 's'))
09526         {
09527           *operation SET_TO COS;
09528           *counter SET_TO (*counter + 2);
09529         }
09530       else
09531         ERM(NCE_UNKNOWN_WORD_STARTING_WITH_C);
09532       break;
09533     case 'e':
09534       if((line[*counter] IS 'x') AND (line[(*counter)+1] IS 'p'))
09535         {
09536           *operation SET_TO EXP;
09537           *counter SET_TO (*counter + 2);
09538         }
09539       else
09540         ERM(NCE_UNKNOWN_WORD_STARTING_WITH_E);
09541       break;
09542     case 'f':
09543       if((line[*counter] IS 'i') AND (line[(*counter)+1] IS 'x'))
09544         {
09545           *operation SET_TO FIX;
09546           *counter SET_TO (*counter + 2);
09547         }
09548       else if((line[*counter] IS 'u') AND (line[(*counter)+1] IS 'p'))
09549         {
09550           *operation SET_TO FUP;
09551           *counter SET_TO (*counter + 2);
09552         }
09553       else
09554         ERM(NCE_UNKNOWN_WORD_STARTING_WITH_F);
09555       break;
09556     case 'l':
09557       if(line[*counter] IS 'n')
09558         {
09559           *operation SET_TO LN;
09560           *counter SET_TO (*counter + 1);
09561         }
09562       else
09563         ERM(NCE_UNKNOWN_WORD_STARTING_WITH_L);
09564       break;
09565     case 'r':
09566       if(strncmp((line + *counter), "ound", 4) IS 0)
09567         {
09568           *operation SET_TO ROUND;
09569           *counter SET_TO (*counter + 4);
09570         }
09571       else
09572         ERM(NCE_UNKNOWN_WORD_STARTING_WITH_R);
09573       break;
09574     case 's':
09575       if((line[*counter] IS 'i') AND (line[(*counter)+1] IS 'n'))
09576         {
09577           *operation SET_TO SIN;
09578           *counter SET_TO (*counter + 2);
09579         }
09580       else if(strncmp((line + *counter), "qrt", 3) IS 0)
09581         {
09582           *operation SET_TO SQRT;
09583           *counter SET_TO (*counter + 3);
09584         }
09585       else
09586         ERM(NCE_UNKNOWN_WORD_STARTING_WITH_S);
09587       break;
09588     case 't':
09589       if((line[*counter] IS 'a') AND (line[(*counter)+1] IS 'n'))
09590         {
09591           *operation SET_TO TAN;
09592           *counter SET_TO (*counter + 2);
09593         }
09594       else
09595         ERM(NCE_UNKNOWN_WORD_STARTING_WITH_T);
09596       break;
09597     default:
09598       ERM(NCE_UNKNOWN_WORD_WHERE_UNARY_OPERATION_COULD_BE);
09599     }
09600   return RS274NGC_OK;
09601 }
09602 
09603 /****************************************************************************/
09604 
09605 /* read_p
09606 
09607 Returned Value: int
09608    If read_real_value returns an error code, this returns that code.
09609    If any of the following errors occur, this returns the error code shown.
09610    Otherwise, it returns RS274NGC_OK.
09611    1. The first character read is not p:
09612       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09613    2. A p value has already been inserted in the block:
09614       NCE_MULTIPLE_P_WORDS_ON_ONE_LINE
09615    3. The p value is negative: NCE_NEGATIVE_P_WORD_USED
09616 
09617 Side effects:
09618    counter is reset to point to the first character following the p value.
09619    The p value setting is inserted in block.
09620 
09621 Called by: read_one_item
09622 
09623 When this function is called, counter is pointing at an item on the
09624 line that starts with the character 'p', indicating a p value
09625 setting. The function reads characters which tell how to set the p
09626 value, up to the start of the next item or the end of the line. This
09627 information is inserted in the block.
09628 
09629 P codes are used for:
09630 1. Dwell time in canned cycles g82, G86, G88, G89 [NCMS pages 98 - 100].
09631 2. A key with G10 [NCMS, pages 9, 10].
09632 
09633 */
09634 
09635 static int read_p(    /* ARGUMENTS                                      */
09636  char * line,         /* string: line of RS274/NGC code being processed */
09637  int * counter,       /* pointer to a counter for position on the line  */
09638  block_pointer block, /* pointer to a block being filled from the line  */
09639  double * parameters) /* array of system parameters                     */
09640 {
09641   static char name[] SET_TO "read_p";
09642   double value;
09643   int status;
09644 
09645   CHK((line[*counter] ISNT 'p'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
09646   *counter SET_TO (*counter + 1);
09647   CHK((block->p_number > -1.0), NCE_MULTIPLE_P_WORDS_ON_ONE_LINE);
09648   CHP(read_real_value(line, counter, &value, parameters));
09649   CHK((value < 0.0), NCE_NEGATIVE_P_WORD_USED);
09650   block->p_number SET_TO value;
09651   return RS274NGC_OK;
09652 }
09653 
09654 /****************************************************************************/
09655 
09656 /* read_parameter
09657 
09658 Returned Value: int
09659    If read_integer_value returns an error code, this returns that code.
09660    If any of the following errors occur, this returns the error code shown.
09661    Otherwise, this returns RS274NGC_OK.
09662    1. The first character read is not # :
09663       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09664    2. The parameter number is out of bounds:
09665       NCE_PARAMETER_NUMBER_OUT_OF_RANGE
09666 
09667 Side effects:
09668    The value of the given parameter is put into what double_ptr points at.
09669    The counter is reset to point to the first character after the
09670    characters which make up the value.
09671 
09672 Called by:  read_real_value
09673 
09674 This attempts to read the value of a parameter out of the line,
09675 starting at the index given by the counter.
09676 
09677 According to the RS274/NGC manual [NCMS, p. 62], the characters following
09678 # may be any "parameter expression". Thus, the following are legal
09679 and mean the same thing (the value of the parameter whose number is
09680 stored in parameter 2):
09681   ##2
09682   #[#2]
09683 
09684 Parameter setting is done in parallel, not sequentially. For example
09685 if #1 is 5 before the line "#1=10 #2=#1" is read, then after the line
09686 is is executed, #1 is 10 and #2 is 5. If parameter setting were done
09687 sequentially, the value of #2 would be 10 after the line was executed.
09688 
09689 */
09690 
09691 static int read_parameter( /* ARGUMENTS                                      */
09692  char * line,              /* string: line of RS274/NGC code being processed */
09693  int * counter,            /* pointer to a counter for position on the line  */
09694  double * double_ptr,      /* pointer to double to be read                   */
09695  double * parameters)      /* array of system parameters                     */
09696 {
09697   static char name[] SET_TO "read_parameter";
09698   int index;
09699   int status;
09700 
09701   CHK((line[*counter] ISNT '#'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
09702   *counter SET_TO (*counter + 1);
09703   CHP(read_integer_value(line, counter, &index, parameters));
09704   CHK(((index < 1) OR (index >= RS274NGC_MAX_PARAMETERS)),
09705       NCE_PARAMETER_NUMBER_OUT_OF_RANGE);
09706   *double_ptr SET_TO parameters[index];
09707   return RS274NGC_OK;
09708 }
09709 
09710 /****************************************************************************/
09711 
09712 /* read_parameter_setting
09713 
09714 Returned Value: int
09715    If read_real_value or read_integer_value returns an error code,
09716    this returns that code.
09717    If any of the following errors occur, this returns the error code shown.
09718    Otherwise, it returns RS274NGC_OK.
09719    1. The first character read is not # :
09720       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09721    2. The parameter index is out of range: PARAMETER_NUMBER_OUT_OF_RANGE
09722    3. An equal sign does not follow the parameter expression:
09723       NCE_EQUAL_SIGN_MISSING_IN_PARAMETER_SETTING
09724 
09725 Side effects:
09726    counter is reset to the character following the end of the parameter
09727    setting. The parameter whose index follows "#" is set to the
09728    real value following "=".
09729 
09730 Called by: read_one_item
09731 
09732 When this function is called, counter is pointing at an item on the
09733 line that starts with the character '#', indicating a parameter
09734 setting when found by read_one_item.  The function reads characters
09735 which tell how to set the parameter.
09736 
09737 Any number of parameters may be set on a line. If parameters set early
09738 on the line are used in expressions farther down the line, the
09739 parameters have their old values, not their new values. This is
09740 usually called setting parameters in parallel.
09741 
09742 Parameter setting is not clearly described in [NCMS, pp. 51 - 62]: it is
09743 not clear if more than one parameter setting per line is allowed (any
09744 number is OK in this implementation). The characters immediately following
09745 the "#" must constitute a "parameter expression", but it is not clear
09746 what that is. Here we allow any expression as long as it evaluates to
09747 an integer.
09748 
09749 Parameters are handled in the interpreter by having a parameter table
09750 and a parameter buffer as part of the machine settings. The parameter
09751 table is passed to the reading functions which need it. The parameter
09752 buffer is used directly by functions that need it. Reading functions
09753 may set parameter values in the parameter buffer. Reading functions
09754 may obtain parameter values; these come from parameter table.
09755 
09756 The parameter buffer has three parts: (i) a counter for how many
09757 parameters have been set while reading the current line (ii) an array
09758 of the indexes of parameters that have been set while reading the
09759 current line, and (iii) an array of the values for the parameters that
09760 have been set while reading the current line; the nth value
09761 corresponds to the nth index. Any given index will appear once in the
09762 index number array for each time the parameter with that index is set
09763 on a line. There is no point in setting the same parameter more than
09764 one on a line because only the last setting of that parameter will
09765 take effect.
09766 
09767 The syntax recognized by this this function is # followed by an
09768 integer expression (explicit integer or expression evaluating to an
09769 integer) followed by = followed by a real value (number or
09770 expression).
09771 
09772 Note that # also starts a bunch of characters which represent a parameter
09773 to be evaluated. That situation is handled by read_parameter.
09774 
09775 */
09776 
09777 static int read_parameter_setting(  /* ARGUMENTS                        */
09778  char * line,         /* string: line of RS274/NGC code being processed */
09779  int * counter,       /* pointer to a counter for position on the line  */
09780  block_pointer block, /* pointer to a block being filled from the line  */
09781  double * parameters) /* array of system parameters                     */
09782 {
09783   static char name[] SET_TO "read_parameter_setting";
09784   int index;
09785   double value;
09786   int status;
09787 
09788   CHK((line[*counter] ISNT '#'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
09789   *counter SET_TO (*counter + 1);
09790   CHP(read_integer_value(line, counter, &index, parameters));
09791   CHK(((index < 1) OR (index >= RS274NGC_MAX_PARAMETERS)),
09792       NCE_PARAMETER_NUMBER_OUT_OF_RANGE);
09793   CHK((line[*counter] ISNT '='), NCE_EQUAL_SIGN_MISSING_IN_PARAMETER_SETTING);
09794   *counter SET_TO (*counter + 1);
09795   CHP(read_real_value(line, counter, &value, parameters));
09796   _setup.parameter_numbers[_setup.parameter_occurrence] SET_TO index;
09797   _setup.parameter_values[_setup.parameter_occurrence] SET_TO value;
09798   _setup.parameter_occurrence++;
09799   return RS274NGC_OK;
09800 }
09801 
09802 /****************************************************************************/
09803 
09804 /* read_q
09805 
09806 Returned Value: int
09807    If read_real_value returns an error code, this returns that code.
09808    If any of the following errors occur, this returns the error code shown.
09809    Otherwise, it returns RS274NGC_OK.
09810    1. The first character read is not q:
09811       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09812    2. A q value has already been inserted in the block:
09813       NCE_MULTIPLE_Q_WORDS_ON_ONE_LINE
09814    3. The q value is negative or zero: NCE_NEGATIVE_OR_ZERO_Q_VALUE_USED
09815 
09816 Side effects:
09817    counter is reset to point to the first character following the q value.
09818    The q value setting is inserted in block.
09819 
09820 Called by: read_one_item
09821 
09822 When this function is called, counter is pointing at an item on the
09823 line that starts with the character 'q', indicating a q value
09824 setting. The function reads characters which tell how to set the q
09825 value, up to the start of the next item or the end of the line. This
09826 information is inserted in the block.
09827 
09828 Q is used only in the G87 canned cycle [NCMS, page 98], where it must
09829 be positive.
09830 
09831 */
09832 
09833 static int read_q(    /* ARGUMENTS                                      */
09834  char * line,         /* string: line of RS274/NGC code being processed */
09835  int * counter,       /* pointer to a counter for position on the line  */
09836  block_pointer block, /* pointer to a block being filled from the line  */
09837  double * parameters) /* array of system parameters                     */
09838 {
09839   static char name[] SET_TO "read_q";
09840   double value;
09841   int status;
09842 
09843   CHK((line[*counter] ISNT 'q'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
09844   *counter SET_TO (*counter + 1);
09845   CHK((block->q_number > -1.0), NCE_MULTIPLE_Q_WORDS_ON_ONE_LINE);
09846   CHP(read_real_value(line, counter, &value, parameters));
09847   CHK((value <= 0.0), NCE_NEGATIVE_OR_ZERO_Q_VALUE_USED);
09848   block->q_number SET_TO value;
09849   return RS274NGC_OK;
09850 }
09851 
09852 /****************************************************************************/
09853 
09854 /* read_r
09855 
09856 Returned Value: int
09857    If read_real_value returns an error code, this returns that code.
09858    If any of the following errors occur, this returns the error code shown.
09859    Otherwise, it returns RS274NGC_OK.
09860    1. The first character read is not r:
09861       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09862    2. An r_number has already been inserted in the block:
09863       NCE_MULTIPLE_R_WORDS_ON_ONE_LINE
09864 
09865 Side effects:
09866    counter is reset.
09867    The r_flag in the block is turned on.
09868    The r_number is inserted in the block.
09869 
09870 Called by: read_one_item
09871 
09872 When this function is called, counter is pointing at an item on the
09873 line that starts with the character 'r'. The function reads characters
09874 which tell how to set the coordinate, up to the start of the next item
09875 or the end of the line. This information is inserted in the block. The
09876 counter is then set to point to the character following.
09877 
09878 An r number indicates the clearance plane in canned cycles.
09879 An r number may also be the radius of an arc.
09880 
09881 The value may be a real number or something that evaluates to a
09882 real number, so read_real_value is used to read it. Parameters
09883 may be involved.
09884 
09885 */
09886 
09887 static int read_r(    /* ARGUMENTS                                     */
09888  char * line,         /* string: line of RS274 code being processed    */
09889  int * counter,       /* pointer to a counter for position on the line */
09890  block_pointer block, /* pointer to a block being filled from the line */
09891  double * parameters) /* array of system parameters                    */
09892 {
09893   static char name[] SET_TO "read_r";
09894   double value;
09895   int status;
09896 
09897   CHK((line[*counter] ISNT 'r'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
09898   *counter SET_TO (*counter + 1);
09899   CHK((block->r_flag ISNT OFF), NCE_MULTIPLE_R_WORDS_ON_ONE_LINE);
09900   CHP(read_real_value(line, counter, &value, parameters));
09901   block->r_flag SET_TO ON;
09902   block->r_number SET_TO value;
09903   return RS274NGC_OK;
09904 }
09905 
09906 /****************************************************************************/
09907 
09908 /* read_real_expression
09909 
09910 Returned Value: int
09911    If any of the following functions returns an error code,
09912    this returns that code.
09913      read_real_value
09914      read_operation
09915      execute_binary
09916    If any of the following errors occur, this returns the error shown.
09917    Otherwise, it returns RS274NGC_OK.
09918    1. The first character is not [ :
09919       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
09920 
09921 Side effects:
09922    The number read from the line is put into what value_ptr points at.
09923    The counter is reset to point to the first character after the real
09924    expression.
09925 
09926 Called by:
09927  read_atan
09928  read_real_value
09929  read_unary
09930 
09931 Example 1: [2 - 3 * 4 / 5] means [2 - [[3 * 4] / 5]] and equals -0.4.
09932 
09933 Segmenting Expressions -
09934 
09935 The RS274/NGC manual, section 3.5.1.1 [NCMS, page 50], provides for
09936 using square brackets to segment expressions.
09937 
09938 Binary Operations -
09939 
09940 The RS274/NGC manual, section 3.5.1.1, discusses expression evaluation.
09941 The manual provides for eight binary operations: the four basic
09942 mathematical operations (addition, subtraction, multiplication,
09943 division), three logical operations (non-exclusive OR, exclusive OR,
09944 and AND2) and the modulus operation. The manual does not explicitly call
09945 these "binary" operations, but implicitly recognizes that they are
09946 binary. We have added the "power" operation of raising the number
09947 on the left of the operation to the power on the right; this is
09948 needed for many basic machining calculations.
09949 
09950 There are two groups of binary operations given in the manual. If
09951 operations are strung together as shown in Example 1, operations in
09952 the first group are to be performed before operations in the second
09953 group. If an expression contains more than one operation from the same
09954 group (such as * and / in Example 1), the operation on the left is
09955 performed first. The first group is: multiplication (*), division (/),
09956 and modulus (MOD). The second group is: addition(+), subtraction (-),
09957 logical non-exclusive OR (OR), logical exclusive OR (XOR), and logical
09958 AND (AND2). We have added a third group with higher precedence than
09959 the first group. The third group contains only the power (**)
09960 operation.
09961 
09962 The logical operations and modulus are apparently to be performed on
09963 any real numbers, not just on integers or on some other data type.
09964 
09965 Unary Operations -
09966 
09967 The RS274/NGC manual, section 3.5.1.2, provides for fifteen unary
09968 mathematical operations. Two of these, BIN and BCD, are apparently for
09969 converting between decimal and hexadecimal number representation,
09970 although the text is not clear. These have not been implemented, since
09971 we are not using any hexadecimal numbers. The other thirteen unary
09972 operations have been implemented: absolute_value, arc_cosine, arc_sine,
09973 arc_tangent, cosine, e_raised_to, fix_down, fix_up, natural_log_of,
09974 round, sine, square_root, tangent.
09975 
09976 The manual section 3.5.1.2 [NCMS, page 51] requires the argument to
09977 all unary operations (except atan) to be in square brackets.  Thus,
09978 for example "sin[90]" is allowed in the interpreter, but "sin 90" is
09979 not. The atan operation must be in the format "atan[..]/[..]".
09980 
09981 Production Rule Definitions in Terms of Tokens -
09982 
09983 The following is a production rule definition of what this RS274NGC
09984 interpreter recognizes as valid combinations of symbols which form a
09985 recognized real_value (the top of this production hierarchy).
09986 
09987 The notion of "integer_value" is used in the interpreter. Below it is
09988 defined as a synonym for real_value, but in fact a constraint is added
09989 which cannot be readily written in a production language.  An
09990 integer_value is a real_value which is very close to an integer.
09991 Integer_values are needed for array and table indices and (when
09992 divided by 10) for the values of M codes and G codes. All numbers
09993 (including integers) are read as real numbers and stored as doubles.
09994 If an integer_value is required in some situation, a test for being
09995 close to an integer is applied to the number after it is read.
09996 
09997 
09998 arc_tangent_combo = arc_tangent expression divided_by expression .
09999 
10000 binary_operation1 = divided_by | modulo | power | times .
10001 
10002 binary_operation2 = and | exclusive_or | minus |  non_exclusive_or | plus .
10003 
10004 combo1 = real_value { binary_operation1 real_value } .
10005 
10006 digit = zero | one | two | three | four | five | six | seven |eight | nine .
10007 
10008 expression =
10009    left_bracket
10010    (unary_combo | (combo1 { binary_operation2 combo1 }))
10011    right_bracket .
10012 
10013 integer_value = real_value .
10014 
10015 ordinary_unary_combo =  ordinary_unary_operation expression .
10016 
10017 ordinary_unary_operation =
10018    absolute_value | arc_cosine | arc_sine | cosine | e_raised_to |
10019    fix_down | fix_up | natural_log_of | round | sine | square_root | tangent .
10020 
10021 parameter_index = integer_value .
10022 
10023 parameter_value = parameter_sign  parameter_index .
10024 
10025 real_number =
10026    [ plus | minus ]
10027    (( digit { digit } decimal_point {digit}) | ( decimal_point digit {digit})).
10028 
10029 real_value =
10030    real_number | expression | parameter_value | unary_combo.
10031 
10032 unary_combo = ordinary_unary_combo | arc_tangent_combo .
10033 
10034 
10035 Production Tokens in Terms of Characters -
10036 
10037 absolute_value   = 'abs'
10038 and              = 'and'
10039 arc_cosine       = 'acos'
10040 arc_sine         = 'asin'
10041 arc_tangent      = 'atan'
10042 cosine           = 'cos'
10043 decimal_point    = '.'
10044 divided_by       = '/'
10045 eight            = '8'
10046 exclusive_or     = 'xor'
10047 e_raised_to      = 'exp'
10048 five             = '5'
10049 fix_down         = 'fix'
10050 fix_up           = 'fup'
10051 four             = '4'
10052 left_bracket     = '['
10053 minus            = '-'
10054 modulo           = 'mod'
10055 natural_log_of   = 'ln'
10056 nine             = '9'
10057 non_exclusive_or = 'or'
10058 one              = '1'
10059 parameter_sign   = '#'
10060 plus             = '+'
10061 power            = '**'
10062 right_bracket    = ']'
10063 round            = 'round'
10064 seven            = '7'
10065 sine             = 'sin'
10066 six              = '6'
10067 square_root      = 'sqrt'
10068 tangent          = 'tan'
10069 three            = '3'
10070 times            = '*'
10071 two              = '2'
10072 zero             = '0'
10073 
10074 When this function is called, the counter should be set at a left
10075 bracket. The function reads up to and including the right bracket
10076 which closes the expression.
10077 
10078 The basic form of an expression is: [v1 bop v2 bop ... vn], where the
10079 vi are real_values and the bops are binary operations. The vi may be
10080 numbers, parameters, expressions, or unary functions. Because some
10081 bops are to be evaluated before others, for understanding the order of
10082 evaluation, it is useful to rewrite the general form collecting any
10083 subsequences of bops of the same precedence. For example, suppose the
10084 expression is: [9+8*7/6+5-4*3**2+1]. It may be rewritten as:
10085 [9+[8*7/6]+5-[4*[3**2]]+1] to show how it should be evaluated.
10086 
10087 The manual provides that operations of the same precedence should be
10088 processed left to right.
10089 
10090 The first version of this function is commented out. It is suitable
10091 for when there are only two precendence levels. It is an improvement
10092 over the version used in interpreters before 2000, but not as general
10093 as the second version given here.
10094 
10095 The first version of this function reads the first value and the first
10096 operation in the expression. Then it calls either read_rest_bop1 or
10097 read_rest_bop2 according to whether the first operation is a bop1 or a
10098 bop2.  Read_rest_bop1 resets the next_operation to either a right
10099 bracket or a bop2. If it is reset to a bop2, read_rest_bop2 is called
10100 when read_rest_bop1 returns.
10101 
10102 */
10103 
10104 #ifdef UNDEFINED
10105 static int read_real_expression( /* ARGUMENTS                               */
10106  char * line,             /* string: line of RS274/NGC code being processed */
10107  int * counter,           /* pointer to a counter for position on the line  */
10108  double * value,          /* pointer to double to be read                   */
10109  double * parameters)     /* array of system parameters                     */
10110 {
10111   static char name[] SET_TO "read_real_expression";
10112   int next_operation;
10113   int status;
10114 
10115   CHK((line[*counter] ISNT '['), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
10116   *counter SET_TO (*counter + 1);
10117   CHP(read_real_value(line, counter, value, parameters));
10118   CHP(read_operation(line, counter, &next_operation));
10119   if (next_operation IS RIGHT_BRACKET); /* nothing to do */
10120   else if (next_operation < AND2)  /* next operation is a bop1, times-like */
10121     {
10122       CHP(read_rest_bop1(line, counter, value, &next_operation, parameters));
10123       if (next_operation IS RIGHT_BRACKET); /* next_operation has been reset */
10124       else /* next_operation is now a bop2, plus-like */
10125         CHP(read_rest_bop2(line, counter, value, next_operation, parameters));
10126     }
10127   else  /* next operation is a bop2, plus-like */
10128     CHP(read_rest_bop2(line, counter, value, next_operation, parameters));
10129   return RS274NGC_OK;
10130 }
10131 #endif
10132 
10133 /****************************************************************************/
10134 
10135 /*
10136 
10137 The following version is stack-based and fully general. It is the
10138 classical stack-based version with left-to-right evaluation of
10139 operations of the same precedence. Separate stacks are used for
10140 operations and values, and the stacks are made with arrays
10141 rather than lists, but those are implementation details. Pushing
10142 and popping are implemented by increasing or decreasing the
10143 stack index.
10144 
10145 Additional levels of precedence may be defined easily by changing the
10146 precedence function. The size of MAX_STACK should always be at least
10147 as large as the number of precedence levels used. We are currently
10148 using four precedence levels (for right-bracket, plus-like operations,
10149 times-like operations, and power).
10150 
10151 */
10152 
10153 #define MAX_STACK 5
10154 
10155 static int read_real_expression( /* ARGUMENTS                               */
10156  char * line,             /* string: line of RS274/NGC code being processed */
10157  int * counter,           /* pointer to a counter for position on the line  */
10158  double * value,          /* pointer to double to be computed               */
10159  double * parameters)     /* array of system parameters                     */
10160 {
10161   static char name[] SET_TO "read_real_expression";
10162   double values[MAX_STACK];
10163   int operators[MAX_STACK];
10164   int stack_index;
10165   int status;
10166 
10167   CHK((line[*counter] ISNT '['), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
10168   *counter SET_TO (*counter + 1);
10169   CHP(read_real_value(line, counter, values, parameters));
10170   CHP(read_operation(line, counter, operators));
10171   stack_index SET_TO 1;
10172   for(; operators[0] ISNT RIGHT_BRACKET ;)
10173     {
10174       CHP(read_real_value(line, counter, values+stack_index, parameters));
10175       CHP(read_operation(line, counter, operators+stack_index));
10176       if (precedence(operators[stack_index]) >
10177           precedence(operators[stack_index - 1]))
10178         stack_index++;
10179       else /* precedence of latest operator is <= previous precedence */
10180         {
10181           for (;precedence(operators[stack_index]) <=
10182                  precedence(operators[stack_index - 1]); )
10183             {
10184               CHP(execute_binary((values + stack_index - 1),
10185                                  operators[stack_index -1],
10186                                  (values + stack_index)));
10187               operators[stack_index - 1] SET_TO operators[stack_index];
10188               if ((stack_index > 1) AND
10189                   (precedence(operators[stack_index - 1]) <=
10190                    precedence(operators[stack_index - 2])))
10191                 stack_index--;
10192               else
10193                 break;
10194             }
10195         }
10196     }
10197   *value SET_TO values[0];
10198   return RS274NGC_OK;
10199 }
10200 
10201 
10202 /****************************************************************************/
10203 
10204 /* read_real_number
10205 
10206 Returned Value: int
10207    If any of the following errors occur, this returns the error shown.
10208    Otherwise, it returns RS274NGC_OK.
10209    1. The first character is not "+", "-", "." or a digit:
10210       NCE_BAD_NUMBER_FORMAT
10211    2. No digits are found after the first character and before the
10212       end of the line or the next character that cannot be part of a real:
10213       NCE_NO_DIGITS_FOUND_WHERE_REAL_NUMBER_SHOULD_BE
10214    3. sscanf fails: NCE_SSCANF_FAILED
10215 
10216 Side effects:
10217    The number read from the line is put into what double_ptr points at.
10218    The counter is reset to point to the first character after the real.
10219 
10220 Called by:  read_real_value
10221 
10222 This attempts to read a number out of the line, starting at the index
10223 given by the counter. It stops when the first character that cannot
10224 be part of the number is found.
10225 
10226 The first character may be a digit, "+", "-", or "."
10227 Every following character must be a digit or "." up to anything
10228 that is not a digit or "." (a second "." terminates reading).
10229 
10230 This function is not called if the first character is NULL, so it is
10231 not necessary to check that.
10232 
10233 The temporary insertion of a NULL character on the line is to avoid
10234 making a format string like "%3lf" which the LynxOS compiler cannot
10235 handle.
10236 
10237 */
10238 
10239 static int read_real_number( /* ARGUMENTS                               */
10240  char * line,         /* string: line of RS274/NGC code being processed */
10241  int * counter,       /* pointer to a counter for position on the line  */
10242  double * double_ptr) /* pointer to double to be read                   */
10243 {
10244   static char name[] SET_TO "read_real_number";
10245   char c;          /* for character being processed    */
10246   int flag_digit;  /* set to ON if digit found         */
10247   int flag_point;  /* set to ON if decimal point found */
10248   int n;           /* for indexing line                */
10249 
10250   n SET_TO *counter;
10251   flag_point SET_TO OFF;
10252   flag_digit SET_TO OFF;
10253 
10254 /* check first character */
10255   c SET_TO line[n];
10256   if (c IS '+')
10257     {
10258       *counter SET_TO (*counter + 1); /* skip plus sign */
10259       n++;
10260     }
10261   else if (c IS '-')
10262     {
10263       n++;
10264     }
10265   else if ((c ISNT '.') AND ((c < 48) OR (c > 57)))
10266     ERM(NCE_BAD_NUMBER_FORMAT);
10267 
10268 /* check out rest of characters (must be digit or decimal point) */
10269   for (; (c SET_TO line[n]) ISNT (char) NULL; n++)
10270     {
10271       if (( 47 < c) AND ( c < 58))
10272         {
10273           flag_digit SET_TO ON;
10274         }
10275       else if (c IS '.')
10276         {
10277           if (flag_point IS OFF)
10278             {
10279               flag_point SET_TO ON;
10280             }
10281           else
10282             break; /* two decimal points, error appears on reading next item */
10283         }
10284       else
10285         break;
10286     }
10287 
10288   CHK((flag_digit IS OFF), NCE_NO_DIGITS_FOUND_WHERE_REAL_NUMBER_SHOULD_BE);
10289   line[n] SET_TO (char) NULL; /* temporary string termination for sscanf */
10290   if (sscanf(line + *counter, "%lf", double_ptr) IS 0)
10291     {
10292       line[n] SET_TO c;
10293       ERM(NCE_SSCANF_FAILED);
10294     }
10295   else
10296     {
10297       line[n] SET_TO c;
10298       *counter SET_TO n;
10299     }
10300   return RS274NGC_OK;
10301 }
10302 
10303 /****************************************************************************/
10304 
10305 /* read_real_value
10306 
10307 Returned Value: int
10308    If one of the following functions returns an error code,
10309    this returns that code.
10310       read_real_expression
10311       read_parameter
10312       read_unary
10313       read_real_number
10314    If no characters are found before the end of the line this
10315    returns NCE_NO_CHARACTERS_FOUND_IN_READING_REAL_VALUE.
10316    Otherwise, this returns RS274NGC_OK.
10317 
10318 Side effects:
10319    The value read from the line is put into what double_ptr points at.
10320    The counter is reset to point to the first character after the
10321    characters which make up the value.
10322 
10323 Called by:
10324    read_a
10325    read_b
10326    read_c
10327    read_f
10328    read_g
10329    read_i
10330    read_integer_value
10331    read_j
10332    read_k
10333    read_p
10334    read_parameter_setting
10335    read_q
10336    read_r
10337    read_real_expression
10338    read_s
10339    read_x
10340    read_y
10341    read_z
10342 
10343 This attempts to read a real value out of the line, starting at the
10344 index given by the counter. The value may be a number, a parameter
10345 value, a unary function, or an expression. It calls one of four
10346 other readers, depending upon the first character.
10347 
10348 */
10349 
10350 static int read_real_value(  /* ARGUMENTS                               */
10351  char * line,         /* string: line of RS274/NGC code being processed */
10352  int * counter,       /* pointer to a counter for position on the line  */
10353  double * double_ptr, /* pointer to double to be read                   */
10354  double * parameters) /* array of system parameters                     */
10355 {
10356   static char name[] SET_TO "read_real_value";
10357   char c;
10358   int status;
10359 
10360   c SET_TO line[*counter];
10361   CHK((c IS 0), NCE_NO_CHARACTERS_FOUND_IN_READING_REAL_VALUE);
10362   if (c IS '[')
10363     CHP(read_real_expression (line, counter, double_ptr, parameters));
10364   else if (c IS '#')
10365     CHP(read_parameter(line, counter, double_ptr, parameters));
10366   else if ((c >= 'a') AND (c <= 'z'))
10367     CHP(read_unary(line, counter, double_ptr, parameters));
10368   else
10369     CHP(read_real_number(line, counter, double_ptr));
10370 
10371   return RS274NGC_OK;
10372 }
10373 
10374 /****************************************************************************/
10375 
10376 /* read_rest_bop1
10377 
10378 Returned Value: int
10379   If any of the following functions returns an error code,
10380   this returns that code.
10381      execute_binary1
10382      read_real_value
10383      read_operation
10384   Otherwise, it returns RS274NGC_OK.
10385 
10386 Side effects:
10387    The value argument is set to the value of the expression.
10388    The counter is reset to point to the first character after the real
10389    expression.
10390 
10391 Called by:
10392   read_real_expression
10393   read_rest_bop2
10394 
10395 The value argument has a value in it when this is called. This repeatedly
10396 gets the next_value and the next_operation, performs the last_operation
10397 on the value and the next_value and resets the last_operation to the
10398 next_operation. Observe that both the value and the last_operation
10399 are passed back to the caller.
10400 
10401 This is commented out since it is not used in the uncommented version
10402 of read_real_expression. It has been tested.
10403 
10404 */
10405 
10406 #ifdef UNDEFINED
10407 static int read_rest_bop1(/* ARGUMENTS                                      */
10408  char * line,             /* string: line of RS274/NGC code being processed */
10409  int * counter,           /* pointer to a counter for position on the line  */
10410  double * value,          /* pointer to double to be calculated             */
10411  int * last_operation,    /* last operation read, reset to next operation   */
10412  double * parameters)     /* array of system parameters                     */
10413 {
10414   static char name[] SET_TO "read_rest_bop1";
10415   double next_value;
10416   int next_operation;
10417   int status;
10418 
10419   for(; ; )
10420     {
10421       CHP(read_real_value(line, counter, &next_value, parameters));
10422       CHP(read_operation(line, counter, &next_operation));
10423       CHP(execute_binary1(value, *last_operation, &next_value));
10424       *last_operation SET_TO next_operation;
10425       if (next_operation >= AND2) /* next op is a bop2 or right bracket */
10426         break;
10427     }
10428   return RS274NGC_OK;
10429 }
10430 #endif
10431 
10432 /****************************************************************************/
10433 
10434 /* read_rest_bop2
10435 
10436 Returned Value: int
10437   If any of the following functions returns an error code,
10438   this returns that code.
10439      execute_binary2
10440      read_real_value
10441      read_operation
10442      read_rest_bop1
10443   Otherwise, it returns RS274NGC_OK.
10444 
10445 Side effects:
10446    The value argument is set to the value of the expression.
10447    The counter is reset to point to the first character after the real
10448    expression.
10449 
10450 Called by:  read_real_expression
10451 
10452 The value argument has a value in it when this is called. This repeatedly
10453 gets the next_value and the next_operation, performs the last_operation
10454 on the value and the next_value and resets the last_operation to the
10455 next_operation. If the next_operation is ever a bop1 read_rest_bop1 is
10456 called to set the next_value.
10457 
10458 This is commented out since it is not used in the uncommented version
10459 of read_real_expression. It has been tested.
10460 
10461 */
10462 
10463 #ifdef UNDEFINED
10464 static int read_rest_bop2(/* ARGUMENTS                                      */
10465  char * line,             /* string: line of RS274/NGC code being processed */
10466  int * counter,           /* pointer to a counter for position on the line  */
10467  double * value,          /* pointer to double to be calculated             */
10468  int last_operation,      /* last operation read                            */
10469  double * parameters)     /* array of system parameters                     */
10470 {
10471   static char name[] SET_TO "read_rest_bop2";
10472   double next_value;
10473   int next_operation;
10474   int status;
10475 
10476   for(; ; last_operation SET_TO next_operation)
10477     {
10478       CHP(read_real_value(line, counter, &next_value, parameters));
10479       CHP(read_operation(line, counter, &next_operation));
10480       if (next_operation < AND2)  /* next operation is a bop1 */
10481         {
10482           CHP(read_rest_bop1(line, counter, &next_value,
10483                              &next_operation, parameters));
10484         }
10485       CHP(execute_binary2(value, last_operation, &next_value));
10486       if (next_operation IS RIGHT_BRACKET)
10487         break;
10488     }
10489   return RS274NGC_OK;
10490 }
10491 #endif
10492 
10493 /****************************************************************************/
10494 
10495 /* read_s
10496 
10497 Returned Value: int
10498    If read_real_value returns an error code, this returns that code.
10499    If any of the following errors occur, this returns the error code shown.
10500    Otherwise, it returns RS274NGC_OK.
10501    1. The first character read is not s:
10502       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
10503    2. A spindle speed has already been inserted in the block:
10504       NCE_MULTIPLE_S_WORDS_ON_ONE_LINE
10505    3. The spindle speed is negative: NCE_NEGATIVE_SPINDLE_SPEED_USED
10506 
10507 Side effects:
10508    counter is reset to the character following the spindle speed.
10509    A spindle speed setting is inserted in the block.
10510 
10511 Called by: read_one_item
10512 
10513 When this function is called, counter is pointing at an item on the
10514 line that starts with the character 's', indicating a spindle speed
10515 setting. The function reads characters which tell how to set the spindle
10516 speed.
10517 
10518 The value may be a real number or something that evaluates to a
10519 real number, so read_real_value is used to read it. Parameters
10520 may be involved.
10521 
10522 */
10523 
10524 static int read_s(    /* ARGUMENTS                                     */
10525  char * line,         /* string: line of RS274NGC code being processed */
10526  int * counter,       /* pointer to a counter for position on the line */
10527  block_pointer block, /* pointer to a block being filled from the line */
10528  double * parameters) /* array of system parameters                    */
10529 {
10530   static char name[] SET_TO "read_s";
10531   double value;
10532   int status;
10533 
10534   CHK((line[*counter] ISNT 's'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
10535   *counter SET_TO (*counter + 1);
10536   CHK((block->s_number > -1.0), NCE_MULTIPLE_S_WORDS_ON_ONE_LINE);
10537   CHP(read_real_value(line, counter, &value, parameters));
10538   CHK((value < 0.0), NCE_NEGATIVE_SPINDLE_SPEED_USED);
10539   block->s_number SET_TO value;
10540   return RS274NGC_OK;
10541 }
10542 
10543 /****************************************************************************/
10544 
10545 /* read_t
10546 
10547 Returned Value: int
10548    If read_integer_value returns an error code, this returns that code.
10549    If any of the following errors occur, this returns the error code shown.
10550    Otherwise, it returns RS274NGC_OK.
10551    1. The first character read is not t:
10552       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
10553    2. A t_number has already been inserted in the block:
10554       NCE_MULTIPLE_T_WORDS_ON_ONE_LINE
10555    3. The t_number is negative: NCE_NEGATIVE_TOOL_ID_USED
10556 
10557 Side effects:
10558    counter is reset to the character following the t_number.
10559    A t_number is inserted in the block.
10560 
10561 Called by: read_one_item
10562 
10563 When this function is called, counter is pointing at an item on the
10564 line that starts with the character 't', indicating a tool.
10565 The function reads characters which give the (integer) value of the
10566 tool code.
10567 
10568 The value must be an integer or something that evaluates to a
10569 real number, so read_integer_value is used to read it. Parameters
10570 may be involved.
10571 
10572 */
10573 
10574 static int read_t(    /* ARGUMENTS                                      */
10575  char * line,         /* string: line of RS274/NGC code being processed */
10576  int * counter,       /* pointer to a counter for position on the line  */
10577  block_pointer block, /* pointer to a block being filled from the line  */
10578  double * parameters) /* array of system parameters                     */
10579 {
10580   static char name[] SET_TO "read_t";
10581   int value;
10582   int status;
10583 
10584   CHK((line[*counter] ISNT 't'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
10585   *counter SET_TO (*counter + 1);
10586   CHK((block->t_number > -1), NCE_MULTIPLE_T_WORDS_ON_ONE_LINE);
10587   CHP(read_integer_value(line, counter, &value, parameters));
10588   CHK((value < 0), NCE_NEGATIVE_TOOL_ID_USED);
10589   block->t_number SET_TO value;
10590   return RS274NGC_OK;
10591 }
10592 
10593 /****************************************************************************/
10594 
10595 /* read_text
10596 
10597 Returned Value: int
10598    If close_and_downcase returns an error code, this returns that code.
10599    If any of the following errors occur, this returns the error code shown.
10600    Otherwise, this returns:
10601        a. RS274NGC_ENDFILE if the percent_flag is ON and the only
10602           non-white character on the line is %,
10603        b. RS274NGC_EXECUTE_FINISH if the first character of the
10604           close_and_downcased line is a slash, and
10605        c. RS274NGC_OK otherwise.
10606    1. The end of the file is found and the percent_flag is ON:
10607       NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN
10608    2. The end of the file is found and the percent_flag is OFF:
10609       NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN_OR_PROGRAM_END
10610    3. The command argument is not null and is too long or the command
10611       argument is null and the line read from the file is too long:
10612       NCE_COMMAND_TOO_LONG
10613 
10614 Side effects: See below
10615 
10616 Called by:  rs274ngc_read
10617 
10618 This reads a line of RS274 code from a command string or a file into
10619 the line array. If the command string is not null, the file is ignored.
10620 
10621 If the end of file is reached, an error is returned as described
10622 above. The end of the file should not be reached because (a) if the
10623 file started with a percent line, it must end with a percent line, and
10624 no more reading of the file should occur after that, and (b) if the
10625 file did not start with a percent line, it must have a program ending
10626 command (M2 or M30) in it, and no more reading of the file should
10627 occur after that.
10628 
10629 All blank space at the end of a line read from a file is removed and
10630 replaced here with NULL characters.
10631 
10632 This then calls close_and_downcase to downcase and remove tabs and
10633 spaces from everything on the line that is not part of a comment. Any
10634 comment is left as is.
10635 
10636 The length is set to zero if any of the following occur:
10637 1. The line now starts with a slash, but the second character is NULL.
10638 2. The first character is NULL.
10639 Otherwise, length is set to the length of the line.
10640 
10641 An input line is blank if the first character is NULL or it consists
10642 entirely of tabs and spaces and, possibly, a newline before the first
10643 NULL.
10644 
10645 Block delete is discussed in [NCMS, page 3] but the discussion makes
10646 no sense. Block delete is handled by having this function return
10647 RS274NGC_EXECUTE_FINISH if the first character of the
10648 close_and_downcased line is a slash. When the caller sees this,
10649 the caller is expected not to call rs274ngc_execute if the switch
10650 is on, but rather call rs274ngc_read again to overwrite and ignore
10651 what is read here.
10652 
10653 The value of the length argument is set to the number of characters on
10654 the reduced line.
10655 
10656 */
10657 
10658 static int read_text(  /* ARGUMENTS                                   */
10659  const char * command, /* a string which may have input text, or null */
10660  FILE * inport,        /* a file pointer for an input file, or null   */
10661  char * raw_line,      /* array to write raw input line into          */
10662  char * line,          /* array for input line to be processed in     */
10663  int * length)         /* a pointer to an integer to be set           */
10664 {
10665   static char name[] SET_TO "read_text";
10666   int status;          /* used in CHP */
10667   int index;
10668 
10669 
10670   if (command IS NULL)
10671     {
10672       if(fgets(raw_line, RS274NGC_TEXT_SIZE, inport) IS NULL)
10673         {
10674           if (_setup.percent_flag IS ON)
10675             ERM(NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN);
10676           else
10677             ERM(NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN_OR_PROGRAM_END);
10678         }
10679       _setup.sequence_number++;
10680       if (strlen(raw_line) IS (RS274NGC_TEXT_SIZE - 1))
10681         { // line is too long. need to finish reading the line to recover
10682           for(;fgetc(inport) ISNT '\n';){} // could also look for EOF
10683           ERM(NCE_COMMAND_TOO_LONG);
10684         }
10685       for(index SET_TO (strlen(raw_line) -1); // index set on last char
10686           (index >= 0) AND (isspace(raw_line[index]));
10687           index--)
10688         {        // remove space at end of raw_line, especially CR & LF
10689           raw_line[index] SET_TO 0;
10690         }
10691       strcpy(line, raw_line);
10692       CHP(close_and_downcase(line));
10693       if ((line[0] IS '%') AND (line[1] IS 0) AND (_setup.percent_flag IS ON))
10694         return RS274NGC_ENDFILE;
10695     }
10696   else
10697     {
10698       CHK((strlen(command) >= RS274NGC_TEXT_SIZE), NCE_COMMAND_TOO_LONG);
10699       strcpy(raw_line, command);
10700       strcpy(line, command);
10701       CHP(close_and_downcase(line));
10702     }
10703   _setup.parameter_occurrence SET_TO 0; /* initialize parameter buffer */
10704   if ((line[0] IS 0) OR ((line[0] IS '/') AND (line[1] IS 0)))
10705     *length SET_TO 0;
10706   else
10707     *length SET_TO strlen(line);
10708 
10709   return ((line[0] IS '/')? RS274NGC_EXECUTE_FINISH : RS274NGC_OK);
10710 }
10711 
10712 /****************************************************************************/
10713 
10714 /* read_unary
10715 
10716 Returned Value: int
10717    If any of the following functions returns an error code,
10718    this returns that code.
10719      execute_unary
10720      read_atan
10721      read_operation_unary
10722      read_real_expression
10723    If any of the following errors occur, this returns the error code shown.
10724    Otherwise, it returns RS274NGC_OK.
10725    1. the name of the unary operation is not followed by a left bracket:
10726       NCE_LEFT_BRACKET_MISSING_AFTER_UNARY_OPERATION_NAME
10727 
10728 Side effects:
10729    The value read from the line is put into what double_ptr points at.
10730    The counter is reset to point to the first character after the
10731    characters which make up the value.
10732 
10733 Called by:  read_real_value
10734 
10735 This attempts to read the value of a unary operation out of the line,
10736 starting at the index given by the counter. The atan operation is
10737 handled specially because it is followed by two arguments.
10738 
10739 */
10740 
10741 static int read_unary( /* ARGUMENTS                                      */
10742  char * line,          /* string: line of RS274/NGC code being processed */
10743  int * counter,        /* pointer to a counter for position on the line  */
10744  double * double_ptr,  /* pointer to double to be read                   */
10745  double * parameters)  /* array of system parameters                     */
10746 {
10747   static char name[] SET_TO "read_unary";
10748   int operation;
10749   int status;
10750 
10751   CHP(read_operation_unary (line, counter, &operation));
10752   CHK((line[*counter] ISNT '['),
10753       NCE_LEFT_BRACKET_MISSING_AFTER_UNARY_OPERATION_NAME);
10754   CHP(read_real_expression (line, counter, double_ptr, parameters));
10755 
10756   if (operation IS ATAN)
10757     CHP(read_atan(line, counter, double_ptr, parameters));
10758   else
10759     CHP(execute_unary(double_ptr, operation));
10760   return RS274NGC_OK;
10761 }
10762 
10763 /****************************************************************************/
10764 
10765 /* read_x
10766 
10767 Returned Value: int
10768    If read_real_value returns an error code, this returns that code.
10769    If any of the following errors occur, this returns the error code shown.
10770    Otherwise, it returns RS274NGC_OK.
10771    1. The first character read is not x:
10772       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
10773    2. A x_coordinate has already been inserted in the block:
10774       NCE_MULTIPLE_X_WORDS_ON_ONE_LINE
10775 
10776 Side effects:
10777    counter is reset.
10778    The x_flag in the block is turned on.
10779    An x_number is inserted in the block.
10780 
10781 Called by: read_one_item
10782 
10783 When this function is called, counter is pointing at an item on the
10784 line that starts with the character 'x', indicating a x_coordinate
10785 setting. The function reads characters which tell how to set the
10786 coordinate, up to the start of the next item or the end of the line.
10787 This information is inserted in the block. The counter is then set to
10788 point to the character following.
10789 
10790 The value may be a real number or something that evaluates to a
10791 real number, so read_real_value is used to read it. Parameters
10792 may be involved.
10793 
10794 */
10795 
10796 static int read_x(    /* ARGUMENTS                                      */
10797  char * line,         /* string: line of RS274 code being processed     */
10798  int * counter,       /* pointer to a counter for position on the line  */
10799  block_pointer block, /* pointer to a block being filled from the line  */
10800  double * parameters) /* array of system parameters                     */
10801 {
10802   static char name[] SET_TO "read_x";
10803   double value;
10804   int status;
10805 
10806   CHK((line[*counter] ISNT 'x'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
10807   *counter SET_TO (*counter + 1);
10808   CHK((block->x_flag ISNT OFF), NCE_MULTIPLE_X_WORDS_ON_ONE_LINE);
10809   CHP(read_real_value(line, counter, &value, parameters));
10810   block->x_flag SET_TO ON;
10811   block->x_number SET_TO value;
10812   return RS274NGC_OK;
10813 }
10814 
10815 /****************************************************************************/
10816 
10817 /* read_y
10818 
10819 Returned Value: int
10820    If read_real_value returns an error code, this returns that code.
10821    If any of the following errors occur, this returns the error code shown.
10822    Otherwise, it returns RS274NGC_OK.
10823    1. The first character read is not y:
10824       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
10825    2. A y_coordinate has already been inserted in the block:
10826       NCE_MULTIPLE_Y_WORDS_ON_ONE_LINE
10827 
10828 Side effects:
10829    counter is reset.
10830    The y_flag in the block is turned on.
10831    A y_number is inserted in the block.
10832 
10833 Called by: read_one_item
10834 
10835 When this function is called, counter is pointing at an item on the
10836 line that starts with the character 'y', indicating a y_coordinate
10837 setting. The function reads characters which tell how to set the
10838 coordinate, up to the start of the next item or the end of the line.
10839 This information is inserted in the block. The counter is then set to
10840 point to the character following.
10841 
10842 The value may be a real number or something that evaluates to a
10843 real number, so read_real_value is used to read it. Parameters
10844 may be involved.
10845 
10846 */
10847 
10848 static int read_y(    /* ARGUMENTS                                      */
10849  char * line,         /* string: line of RS274 code being processed     */
10850  int * counter,       /* pointer to a counter for position on the line  */
10851  block_pointer block, /* pointer to a block being filled from the line  */
10852  double * parameters) /* array of system parameters                     */
10853 {
10854   static char name[] SET_TO "read_y";
10855   double value;
10856   int status;
10857 
10858   CHK((line[*counter] ISNT 'y'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
10859   *counter SET_TO (*counter + 1);
10860   CHK((block->y_flag ISNT OFF), NCE_MULTIPLE_Y_WORDS_ON_ONE_LINE);
10861   CHP(read_real_value(line, counter, &value, parameters));
10862   block->y_flag SET_TO ON;
10863   block->y_number SET_TO value;
10864   return RS274NGC_OK;
10865 }
10866 
10867 /****************************************************************************/
10868 
10869 /* read_z
10870 
10871 Returned Value: int
10872    If read_real_value returns an error code, this returns that code.
10873    If any of the following errors occur, this returns the error code shown.
10874    Otherwise, it returns RS274NGC_OK.
10875    1. The first character read is not z:
10876       NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED
10877    2. A z_coordinate has already been inserted in the block:
10878       NCE_MULTIPLE_Z_WORDS_ON_ONE_LINE
10879 
10880 Side effects:
10881    counter is reset.
10882    The z_flag in the block is turned on.
10883    A z_number is inserted in the block.
10884 
10885 Called by: read_one_item
10886 
10887 When this function is called, counter is pointing at an item on the
10888 line that starts with the character 'z', indicating a z_coordinate
10889 setting. The function reads characters which tell how to set the
10890 coordinate, up to the start of the next item or the end of the line.
10891 This information is inserted in the block. The counter is then set to
10892 point to the character following.
10893 
10894 The value may be a real number or something that evaluates to a
10895 real number, so read_real_value is used to read it. Parameters
10896 may be involved.
10897 
10898 */
10899 
10900 static int read_z(    /* ARGUMENTS                                      */
10901  char * line,         /* string: line of RS274 code being processed     */
10902  int * counter,       /* pointer to a counter for position on the line  */
10903  block_pointer block, /* pointer to a block being filled from the line  */
10904  double * parameters) /* array of system parameters                     */
10905 {
10906   static char name[] SET_TO "read_z";
10907   double value;
10908   int status;
10909 
10910   CHK((line[*counter] ISNT 'z'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
10911   *counter SET_TO (*counter + 1);
10912   CHK((block->z_flag ISNT OFF), NCE_MULTIPLE_Z_WORDS_ON_ONE_LINE);
10913   CHP(read_real_value(line, counter, &value, parameters));
10914   block->z_flag SET_TO ON;
10915   block->z_number SET_TO value;
10916   return RS274NGC_OK;
10917 }
10918 
10919 /****************************************************************************/
10920 
10921 /* set_probe_data
10922 
10923 Returned Value: int (RS274NGC_OK)
10924 
10925 Side effects:
10926   The current position is set.
10927   System parameters for probe position are set.
10928 
10929 Called by:  rs274ngc_read
10930 
10931 */
10932 
10933 static int set_probe_data( /* ARGUMENTS                   */
10934  setup_pointer settings)   /* pointer to machine settings */
10935 {
10936   static char name[] SET_TO "set_probe_data";
10937 
10938   settings->current_x SET_TO GET_EXTERNAL_POSITION_X();
10939   settings->current_y SET_TO GET_EXTERNAL_POSITION_Y();
10940   settings->current_z SET_TO GET_EXTERNAL_POSITION_Z();
10941 #ifdef AA
10942   settings->AA_current SET_TO GET_EXTERNAL_POSITION_A();  /*AA*/
10943 #endif
10944 #ifdef BB
10945   settings->BB_current SET_TO GET_EXTERNAL_POSITION_B();  /*BB*/
10946 #endif
10947 #ifdef CC
10948   settings->CC_current SET_TO GET_EXTERNAL_POSITION_C();  /*CC*/
10949 #endif
10950   settings->parameters[5061] SET_TO GET_EXTERNAL_PROBE_POSITION_X();
10951   settings->parameters[5062] SET_TO GET_EXTERNAL_PROBE_POSITION_Y();
10952   settings->parameters[5063] SET_TO GET_EXTERNAL_PROBE_POSITION_Z();
10953 #ifdef AA
10954   settings->parameters[5064] SET_TO GET_EXTERNAL_PROBE_POSITION_A();  /*AA*/
10955 #endif
10956 #ifdef BB
10957   settings->parameters[5065] SET_TO GET_EXTERNAL_PROBE_POSITION_B();  /*BB*/
10958 #endif
10959 #ifdef CC
10960   settings->parameters[5066] SET_TO GET_EXTERNAL_PROBE_POSITION_C();  /*CC*/
10961 #endif
10962   settings->parameters[5067] SET_TO GET_EXTERNAL_PROBE_VALUE();
10963   return RS274NGC_OK;
10964 }
10965 
10966 /****************************************************************************/
10967 /* write_g_codes
10968 
10969 Returned Value: int (RS274NGC_OK)
10970 
10971 Side effects:
10972    The active_g_codes in the settings are updated.
10973 
10974 Called by:
10975    rs274ngc_execute
10976    rs274ngc_init
10977 
10978 The block may be NULL.
10979 
10980 This writes active g_codes into the settings->active_g_codes array by
10981 examining the interpreter settings. The array of actives is composed
10982 of ints, so (to handle codes like 59.1) all g_codes are reported as
10983 ints ten times the actual value. For example, 59.1 is reported as 591.
10984 
10985 The correspondence between modal groups and array indexes is as follows
10986 (no apparent logic to it).
10987 
10988 The group 0 entry is taken from the block (if there is one), since its
10989 codes are not modal.
10990 
10991 group 0  - gez[2]  g4, g10, g28, g30, g53, g92 g92.1, g92.2, g92.3 - misc
10992 group 1  - gez[1]  g0, g1, g2, g3, g38.2, g80, g81, g82, g83, g84, g85,
10993                    g86, g87, g88, g89 - motion
10994 group 2  - gez[3]  g17, g18, g19 - plane selection
10995 group 3  - gez[6]  g90, g91 - distance mode
10996 group 4  - no such group
10997 group 5  - gez[7]  g93, g94 - feed rate mode
10998 group 6  - gez[5]  g20, g21 - units
10999 group 7  - gez[4]  g40, g41, g42 - cutter radius compensation
11000 group 8  - gez[9]  g43, g49 - tool length offse
11001 group 9  - no such group
11002 group 10 - gez[10] g98, g99 - return mode in canned cycles
11003 group 11 - no such group
11004 group 12 - gez[8]  g54, g55, g56, g57, g58, g59, g59.1, g59.2, g59.3
11005                    - coordinate system
11006 group 13 - gez[11] g61, g61.1, g64 - control mode
11007 
11008 */
11009 
11010 static int write_g_codes( /* ARGUMENTS                                    */
11011  block_pointer block,     /* pointer to a block of RS274/NGC instructions */
11012  setup_pointer settings)  /* pointer to machine settings                  */
11013 {
11014   int * gez;
11015 
11016   gez SET_TO settings->active_g_codes;
11017   gez[0] SET_TO settings->sequence_number;
11018   gez[1] SET_TO settings->motion_mode;
11019   gez[2] SET_TO ((block IS NULL) ? -1 : block->g_modes[0]);
11020   gez[3] SET_TO
11021     (settings->plane IS CANON_PLANE_XY) ? G_17 :
11022     (settings->plane IS CANON_PLANE_XZ) ? G_18 : G_19;
11023   gez[4] SET_TO
11024     (settings->cutter_comp_side IS RIGHT) ? G_42 :
11025     (settings->cutter_comp_side IS LEFT) ? G_41 : G_40;
11026   gez[5] SET_TO
11027     (settings->length_units IS CANON_UNITS_INCHES) ? G_20 : G_21;
11028   gez[6] SET_TO
11029     (settings->distance_mode IS MODE_ABSOLUTE) ? G_90 : G_91;
11030   gez[7] SET_TO
11031     (settings->feed_mode IS INVERSE_TIME) ? G_93 : G_94;
11032   gez[8] SET_TO
11033     (settings->origin_index < 7) ? (530 + (10 * settings->origin_index)) :
11034                                    (584 + settings->origin_index);
11035   gez[9] SET_TO
11036     (settings->tool_length_offset IS 0.0) ? G_49 : G_43;
11037   gez[10] SET_TO
11038     (settings->retract_mode IS OLD_Z) ? G_98 : G_99;
11039   gez[11] SET_TO
11040     (settings->control_mode IS CANON_CONTINUOUS) ? G_64 :
11041     (settings->control_mode IS CANON_EXACT_PATH) ? G_61 : G_61_1;
11042 
11043   return RS274NGC_OK;
11044 }
11045 
11046 /****************************************************************************/
11047 
11048 /* write_m_codes
11049 
11050 Returned Value: int (RS274NGC_OK)
11051 
11052 Side effects:
11053    The settings->active_m_codes are updated.
11054 
11055 Called by:
11056    rs274ngc_execute
11057    rs274ngc_init
11058 
11059 This is testing only the feed override to see if overrides is on.
11060 Might add check of speed override.
11061 
11062 */
11063 
11064 static int write_m_codes( /* ARGUMENTS                                    */
11065  block_pointer block,     /* pointer to a block of RS274/NGC instructions */
11066  setup_pointer settings)  /* pointer to machine settings                  */
11067 {
11068   int * emz;
11069 
11070   emz SET_TO settings->active_m_codes;
11071   emz[0] SET_TO settings->sequence_number;                /* 0 seq number  */
11072   emz[1] SET_TO
11073     (block IS NULL) ? -1 : block->m_modes[4];             /* 1 stopping    */
11074   emz[2] SET_TO
11075     (settings->spindle_turning IS CANON_STOPPED) ? 5 :    /* 2 spindle     */
11076     (settings->spindle_turning IS CANON_CLOCKWISE) ? 3 : 4;
11077   emz[3] SET_TO                                           /* 3 tool change */
11078     (block IS NULL) ? -1 : block->m_modes[6];
11079   emz[4] SET_TO                                           /* 4 mist        */
11080     (settings->mist IS ON) ? 7 :
11081     (settings->flood IS ON) ? -1 : 9;
11082   emz[5] SET_TO                                           /* 5 flood       */
11083     (settings->flood IS ON) ? 8 : -1;
11084   emz[6] SET_TO                                           /* 6 overrides   */
11085     (settings->feed_override IS ON) ? 48 : 49;
11086 
11087   return RS274NGC_OK;
11088 }
11089 
11090 /****************************************************************************/
11091 
11092 /* write_settings
11093 
11094 Returned Value: int (RS274NGC_OK)
11095 
11096 Side effects:
11097   The settings->active_settings array of doubles is updated with the
11098   sequence number, feed, and speed settings.
11099 
11100 Called by:
11101   rs274ngc_execute
11102   rs274ngc_init
11103 
11104 */
11105 
11106 static int write_settings( /* ARGUMENTS                   */
11107  setup_pointer settings)   /* pointer to machine settings */
11108 {
11109   double * vals;
11110 
11111   vals SET_TO settings->active_settings;
11112   vals[0] SET_TO settings->sequence_number; /* 0 sequence number */
11113   vals[1] SET_TO settings->feed_rate;       /* 1 feed rate       */
11114   vals[2] SET_TO settings->speed;           /* 2 spindle speed   */
11115 
11116   return RS274NGC_OK;
11117 }
11118 
11119 /****************************************************************************/
11120 /****************************************************************************/
11121 
11122 /*
11123 
11124 The functions in this section of this file are functions for
11125 external programs to call to tell the rs274ngc interpreter
11126 what to do. They are declared in rs274ngc.hh.
11127 
11128 */
11129 
11130 /***********************************************************************/
11131 
11132 /* rs274ngc_close
11133 
11134 Returned Value: int (RS274NGC_OK)
11135 
11136 Side Effects:
11137    The NC-code file is closed if open.
11138    The _setup world model is reset.
11139 
11140 Called By: external programs
11141 
11142 */
11143 
11144 int rs274ngc_close()
11145 {
11146   if (_setup.file_pointer ISNT NULL)
11147   {
11148     fclose(_setup.file_pointer);
11149     _setup.file_pointer SET_TO NULL;
11150   }
11151   rs274ngc_reset();
11152 
11153   return RS274NGC_OK;
11154 }
11155 
11156 /***********************************************************************/
11157 
11158 /* rs274ngc_execute
11159 
11160 Returned Value: int)
11161    If execute_block returns RS274NGC_EXIT, this returns that.
11162    If execute_block returns RS274NGC_EXECUTE_FINISH, this returns that.
11163    If execute_block returns an error code, this returns that code.
11164    Otherwise, this returns RS274NGC_OK.
11165 
11166 Side Effects:
11167    Calls to canonical machining commands are made.
11168    The interpreter variables are changed.
11169    At the end of the program, the file is closed.
11170    If using a file, the active G codes and M codes are updated.
11171 
11172 Called By: external programs
11173 
11174 This executes a previously parsed block.
11175 
11176 */
11177 
11178 #ifndef NOT_OLD_EMC_INTERP_COMPATIBLE
11179 int rs274ngc_execute(const char *command)  /* NO ARGUMENTS */
11180 #else
11181 int rs274ngc_execute()
11182 #endif
11183 {
11184   static char name[] SET_TO "rs274ngc_execute";
11185   int status;
11186   int n;
11187 
11188 #ifndef NOT_OLD_EMC_INTERP_COMPATIBLE
11189   if(NULL != command)
11190     {
11191       status = rs274ngc_read(command);
11192     }
11193 #endif
11194 
11195   for (n SET_TO 0; n < _setup.parameter_occurrence; n++)
11196     { // copy parameter settings from parameter buffer into parameter table
11197       _setup.parameters[_setup.parameter_numbers[n]]
11198         SET_TO _setup.parameter_values[n];
11199     }
11200   if (_setup.line_length ISNT 0) /* line not blank */
11201     {
11202       status SET_TO execute_block (&(_setup.block1), &_setup);
11203       write_g_codes(&(_setup.block1), &_setup);
11204       write_m_codes(&(_setup.block1), &_setup);
11205       write_settings(&_setup);
11206       if ((status ISNT RS274NGC_OK) AND
11207           (status ISNT RS274NGC_EXECUTE_FINISH) AND
11208           (status ISNT RS274NGC_EXIT))
11209         ERP(status);
11210     }
11211   else /* blank line is OK */
11212     status SET_TO RS274NGC_OK;
11213   return status;
11214 }
11215 
11216 /***********************************************************************/
11217 
11218 /* rs274ngc_exit
11219 
11220 Returned Value: int (RS274NGC_OK)
11221 
11222 Side Effects: See below
11223 
11224 Called By: external programs
11225 
11226 The system parameters are saved to a file and some parts of the world
11227 model are reset. If GET_EXTERNAL_PARAMETER_FILE_NAME provides a
11228 non-empty file name, that name is used for the file that is
11229 written. Otherwise, the default parameter file name is used.
11230 
11231 */
11232 
11233 int rs274ngc_exit() /* NO ARGUMENTS */
11234 {
11235   char file_name[RS274NGC_TEXT_SIZE];
11236 
11237   GET_EXTERNAL_PARAMETER_FILE_NAME(file_name, (RS274NGC_TEXT_SIZE - 1));
11238   rs274ngc_save_parameters
11239     (((file_name[0] IS 0) ? RS274NGC_PARAMETER_FILE_NAME_DEFAULT : file_name),
11240      _setup.parameters);
11241   rs274ngc_reset();
11242 
11243   return RS274NGC_OK;
11244 }
11245 
11246 /***********************************************************************/
11247 
11248 /* rs274_ngc_init
11249 
11250 Returned Value: int
11251    If any of the following errors occur, this returns the error code shown.
11252    Otherwise, this returns RS274NGC_OK.
11253    1. rs274ngc_restore_parameters returns an error code.
11254    2. Parameter 5220, the work coordinate system index, is not in the range
11255       1 to 9: NCE_COORDINATE_SYSTEM_INDEX_PARAMETER_5220_OUT_OF_RANGE
11256 
11257 Side Effects:
11258    Many values in the _setup structure are reset.
11259    A USE_LENGTH_UNITS canonical command call is made.
11260    A SET_FEED_REFERENCE canonical command call is made.
11261    A SET_ORIGIN_OFFSETS canonical command call is made.
11262    An INIT_CANON call is made.
11263 
11264 Called By: external programs
11265 
11266 Currently we are running only in CANON_XYZ feed_reference mode.  There
11267 is no command regarding feed_reference in the rs274 language (we
11268 should try to get one added). The initialization routine, therefore,
11269 always calls SET_FEED_REFERENCE(CANON_XYZ).
11270 
11271 */
11272 
11273 int rs274ngc_init() /* NO ARGUMENTS */
11274 {
11275   static char name[] SET_TO "rs274ngc_init";
11276   int k; // starting index in parameters of origin offsets
11277   int status;
11278   char filename[RS274NGC_TEXT_SIZE];
11279   double * pars; // short name for _setup.parameters
11280 
11281   INIT_CANON();
11282   _setup.length_units SET_TO GET_EXTERNAL_LENGTH_UNIT_TYPE();
11283   USE_LENGTH_UNITS(_setup.length_units);
11284   GET_EXTERNAL_PARAMETER_FILE_NAME(filename, RS274NGC_TEXT_SIZE);
11285   if (filename[0] IS 0)
11286     strcpy(filename, RS274NGC_PARAMETER_FILE_NAME_DEFAULT);
11287   CHP(rs274ngc_restore_parameters(filename));
11288   pars SET_TO _setup.parameters;
11289   _setup.origin_index SET_TO (int)(pars[5220] + 0.0001);
11290   CHK(((_setup.origin_index < 1) OR (_setup.origin_index > 9)),
11291       NCE_COORDINATE_SYSTEM_INDEX_PARAMETER_5220_OUT_OF_RANGE);
11292   k SET_TO (5200 + (_setup.origin_index * 20));
11293   SET_ORIGIN_OFFSETS((pars[k + 1] + pars[5211]),
11294                      (pars[k + 2] + pars[5212]),
11295                      (pars[k + 3] + pars[5213])
11296 #ifdef AA
11297 ,                    (pars[k + 4] + pars[5214])
11298 #else
11299 #ifdef ALL_AXES
11300 , 0
11301 #endif
11302 #endif
11303 #ifdef BB
11304 ,                    (pars[k + 5] + pars[5215])
11305 #else
11306 #ifdef ALL_AXES
11307 , 0
11308 #endif
11309 #endif
11310 #ifdef CC
11311 ,                    (pars[k + 6] + pars[5216])
11312 #else
11313 #ifdef ALL_AXES
11314 , 0
11315 #endif
11316 #endif
11317 );
11318   SET_FEED_REFERENCE(CANON_XYZ);
11319 #ifdef AA
11320   _setup.AA_axis_offset SET_TO pars[5214];                 /*AA*/
11321 #endif
11322 //_setup.Aa_current set in rs274ngc_synch
11323 #ifdef AA
11324   _setup.AA_origin_offset SET_TO pars[k + 4];              /*AA*/
11325 #endif
11326 //_setup.active_g_codes initialized below
11327 //_setup.active_m_codes initialized below
11328 //_setup.active_settings initialized below
11329   _setup.axis_offset_x SET_TO pars[5211];
11330   _setup.axis_offset_y SET_TO pars[5212];
11331   _setup.axis_offset_z SET_TO pars[5213];
11332 #ifdef BB
11333   _setup.BB_axis_offset SET_TO pars[5215];                 /*BB*/
11334 #endif
11335 //_setup.Bb_current set in rs274ngc_synch
11336 #ifdef BB
11337   _setup.BB_origin_offset SET_TO pars[k + 5];              /*BB*/
11338 #endif
11339 //_setup.block1 does not need initialization
11340   _setup.blocktext[0] SET_TO 0;
11341 #ifdef CC
11342   _setup.CC_axis_offset SET_TO pars[5216];                 /*CC*/
11343 #endif
11344 //_setup.Cc_current set in rs274ngc_synch
11345 #ifdef CC
11346   _setup.CC_origin_offset SET_TO pars[k + 6];              /*CC*/
11347 #endif
11348 //_setup.current_slot set in rs274ngc_synch
11349 //_setup.current_x set in rs274ngc_synch
11350 //_setup.current_y set in rs274ngc_synch
11351 //_setup.current_z set in rs274ngc_synch
11352   _setup.cutter_comp_side SET_TO OFF;
11353 //_setup.cycle values do not need initialization
11354   _setup.distance_mode SET_TO MODE_ABSOLUTE;
11355   _setup.feed_mode SET_TO UNITS_PER_MINUTE;
11356   _setup.feed_override SET_TO ON;
11357 //_setup.feed_rate set in rs274ngc_synch
11358   _setup.filename[0] SET_TO 0;
11359   _setup.file_pointer SET_TO NULL;
11360 //_setup.flood set in rs274ngc_synch
11361   _setup.length_offset_index SET_TO 1;
11362 //_setup.length_units set in rs274ngc_synch
11363   _setup.line_length SET_TO 0;
11364   _setup.linetext[0] SET_TO 0;
11365 //_setup.mist set in rs274ngc_synch
11366   _setup.motion_mode SET_TO G_80;
11367 //_setup.origin_index set above
11368   _setup.origin_offset_x SET_TO pars[k + 1];
11369   _setup.origin_offset_y SET_TO pars[k + 2];
11370   _setup.origin_offset_z SET_TO pars[k + 3];
11371 //_setup.parameters set above
11372 //_setup.parameter_occurrence does not need initialization
11373 //_setup.parameter_numbers does not need initialization
11374 //_setup.parameter_values does not need initialization
11375 //_setup.percent_flag does not need initialization
11376 //_setup.plane set in rs274ngc_synch
11377   _setup.probe_flag SET_TO OFF;
11378   _setup.program_x SET_TO UNKNOWN; /* for cutter comp */
11379   _setup.program_y SET_TO UNKNOWN; /* for cutter comp */
11380 //_setup.retract_mode does not need initialization
11381 //_setup.selected_tool_slot set in rs274ngc_synch
11382   _setup.sequence_number SET_TO 0; /*DOES THIS NEED TO BE AT TOP? */
11383 //_setup.speed set in rs274ngc_synch
11384   _setup.speed_feed_mode SET_TO CANON_INDEPENDENT;
11385   _setup.speed_override SET_TO ON;
11386 //_setup.spindle_turning set in rs274ngc_synch
11387 //_setup.stack does not need initialization
11388 //_setup.stack_index does not need initialization
11389   _setup.tool_length_offset SET_TO 0.0;
11390 //_setup.tool_max set in rs274ngc_synch
11391 //_setup.tool_table set in rs274ngc_synch
11392   _setup.tool_table_index SET_TO 1;
11393 //_setup.traverse_rate set in rs274ngc_synch
11394 
11395   write_g_codes((block_pointer)NULL, &_setup);
11396   write_m_codes((block_pointer)NULL, &_setup);
11397   write_settings(&_setup);
11398 
11399   // Synch rest of settings to external world
11400   rs274ngc_synch();
11401 
11402   return RS274NGC_OK;
11403 }
11404 
11405 /***********************************************************************/
11406 
11407 /* rs274ngc_load_tool_table
11408 
11409 Returned Value: int
11410    If any of the following errors occur, this returns the error code shown.
11411    Otherwise, this returns RS274NGC_OK.
11412    1. _setup.tool_max is larger than CANON_TOOL_MAX: NCE_TOOL_MAX_TOO_LARGE
11413 
11414 Side Effects:
11415    _setup.tool_table[] is modified.
11416 
11417 Called By:
11418    rs274ngc_synch
11419    external programs
11420 
11421 This function calls the canonical interface function GET_EXTERNAL_TOOL_TABLE
11422 to load the whole tool table into the _setup.
11423 
11424 The CANON_TOOL_MAX is an upper limit for this software. The
11425 _setup.tool_max is intended to be set for a particular machine.
11426 
11427 */
11428 
11429 int rs274ngc_load_tool_table() /* NO ARGUMENTS */
11430 {
11431   static char name[] SET_TO "rs274ngc_load_tool_table";
11432   int n;
11433 
11434   CHK((_setup.tool_max > CANON_TOOL_MAX), NCE_TOOL_MAX_TOO_LARGE);
11435   for (n SET_TO 0; n <= _setup.tool_max; n++)
11436     {
11437       _setup.tool_table[n] SET_TO GET_EXTERNAL_TOOL_TABLE(n);
11438     }
11439   for(; n <= CANON_TOOL_MAX; n++)
11440     {
11441       _setup.tool_table[n].id SET_TO 0;
11442       _setup.tool_table[n].length SET_TO 0;
11443       _setup.tool_table[n].diameter SET_TO 0;
11444     }
11445 
11446   return RS274NGC_OK;
11447 }
11448 
11449 /***********************************************************************/
11450 
11451 /* rs274ngc_open
11452 
11453 Returned Value: int
11454    If any of the following errors occur, this returns the error code shown.
11455    Otherwise it returns RS274NGC_OK.
11456    1. A file is already open: NCE_A_FILE_IS_ALREADY_OPEN
11457    2. The name of the file is too long: NCE_FILE_NAME_TOO_LONG
11458    3. The file cannot be opened: NCE_UNABLE_TO_OPEN_FILE
11459 
11460 Side Effects: See below
11461 
11462 Called By: external programs
11463 
11464 The file is opened for reading and _setup.file_pointer is set.
11465 The file name is copied into _setup.filename.
11466 The _setup.sequence_number, is set to zero.
11467 rs274ngc_reset() is called, changing several more _setup attributes.
11468 
11469 The manual [NCMS, page 3] discusses the use of the "%" character at the
11470 beginning of a "tape". It is not clear whether it is intended that
11471 every NC-code file should begin with that character.
11472 
11473 In the following, "uses percents" means the first non-blank line
11474 of the file must consist of nothing but the percent sign, with optional
11475 leading and trailing white space, and there must be a second line
11476 of the same sort later on in the file. If a file uses percents,
11477 execution stops at the second percent line. Any lines after the
11478 second percent line are ignored.
11479 
11480 In this interpreter (recalling that M2 and M30 always ends execution):
11481 1. If execution of a file is ended by M2 or M30 (not necessarily on
11482 the last line of the file), then it is optional that the file
11483 uses percents.
11484 2. If execution of a file is not ended by M2 or M30, then it is
11485 required that the file uses percents.
11486 
11487 If the file being opened uses percents, this function turns on the
11488 _setup.percent flag, reads any initial blank lines, and reads the
11489 first line with the "%". If not, after reading enough to determine
11490 that, this function puts the file pointer back at the beginning of the
11491 file.
11492 
11493 */
11494 
11495 int rs274ngc_open(       /* ARGUMENTS                                     */
11496  const char * filename)  /* string: the name of the input NC-program file */
11497 {
11498   static char name[] SET_TO "rs274ngc_open";
11499   char * line;
11500   int index;
11501   int length;
11502 
11503   CHK((_setup.file_pointer ISNT NULL), NCE_A_FILE_IS_ALREADY_OPEN);
11504   CHK((strlen(filename) > (RS274NGC_TEXT_SIZE - 1)), NCE_FILE_NAME_TOO_LONG);
11505   _setup.file_pointer SET_TO fopen(filename, "r");
11506   CHK((_setup.file_pointer IS NULL), NCE_UNABLE_TO_OPEN_FILE);
11507   line SET_TO _setup.linetext;
11508   for(index SET_TO -1; index IS -1;) /* skip blank lines */
11509     {
11510       CHK((fgets(line, RS274NGC_TEXT_SIZE, _setup.file_pointer) IS NULL),
11511           NCE_FILE_ENDED_WITH_NO_PERCENT_SIGN);
11512       length SET_TO strlen(line);
11513       if (length IS (RS274NGC_TEXT_SIZE - 1))
11514         { // line is too long. need to finish reading the line to recover
11515           for(;fgetc(_setup.file_pointer) ISNT '\n';); // could look for EOF
11516           ERM(NCE_COMMAND_TOO_LONG);
11517         }
11518       for(index SET_TO (length -1); // index set on last char
11519           (index >= 0) AND (isspace(line[index]));
11520           index--);
11521     }
11522   if(line[index] IS '%')
11523     {
11524       for(index--; (index >= 0) AND (isspace(line[index])); index--);
11525       if (index IS -1)
11526         {
11527           _setup.percent_flag SET_TO ON;
11528           _setup.sequence_number=1; // We have already read the first line
11529           // and we are not going back to it.
11530         }
11531       else
11532         {
11533           fseek(_setup.file_pointer, 0, SEEK_SET);
11534           _setup.percent_flag SET_TO OFF;
11535           _setup.sequence_number=0; // Going back to line 0
11536         }
11537     }
11538   else
11539     {
11540       fseek(_setup.file_pointer, 0, SEEK_SET);
11541       _setup.percent_flag SET_TO OFF;
11542       _setup.sequence_number=0; // Going back to line 0
11543     }
11544   strcpy(_setup.filename, filename);
11545   rs274ngc_reset();
11546   return RS274NGC_OK;
11547 }
11548 
11549 /***********************************************************************/
11550 
11551 /* rs274ngc_read
11552 
11553 Returned Value: int
11554    If any of the following errors occur, this returns the error code shown.
11555    Otherwise, this returns:
11556        a. RS274NGC_ENDFILE if the only non-white character on the line is %,
11557        b. RS274NGC_EXECUTE_FINISH if the first character of the
11558           close_and_downcased line is a slash, and
11559        c. RS274NGC_OK otherwise.
11560    1. The command and_setup.file_pointer are both NULL: NCE_FILE_NOT_OPEN
11561    2. The probe_flag is ON but the HME command queue is not empty:
11562       NCE_QUEUE_IS_NOT_EMPTY_AFTER_PROBING
11563    3. If read_text (which gets a line of NC code from file) or parse_line
11564      (which parses the line) returns an error code, this returns that code.
11565 
11566 Side Effects:
11567    _setup.sequence_number is incremented.
11568    The _setup.block1 is filled with data.
11569 
11570 Called By: external programs
11571 
11572 This reads a line of NC-code from the command string or, (if the
11573 command string is NULL) from the currently open file. The
11574 _setup.line_length will be set by read_text. This will be zero if the
11575 line is blank or consists of nothing but a slash. If the length is not
11576 zero, this parses the line into the _setup.block1.
11577 
11578 */
11579 
11580 int rs274ngc_read(      /* ARGUMENTS                       */
11581  const char * command)  /* may be NULL or a string to read */
11582 {
11583   static char name[] SET_TO "rs274ngc_read";
11584   int status;
11585   int read_status;
11586 
11587   if (_setup.probe_flag IS ON)
11588     {
11589       CHK((GET_EXTERNAL_QUEUE_EMPTY() IS 0),
11590           NCE_QUEUE_IS_NOT_EMPTY_AFTER_PROBING);
11591       set_probe_data(&_setup);
11592       _setup.probe_flag SET_TO OFF;
11593     }
11594   CHK(((command IS NULL) AND (_setup.file_pointer IS NULL)),
11595       NCE_FILE_NOT_OPEN);
11596   read_status SET_TO read_text(command, _setup.file_pointer, _setup.linetext,
11597                                _setup.blocktext, &_setup.line_length);
11598   if ((read_status IS RS274NGC_EXECUTE_FINISH) OR
11599       (read_status IS RS274NGC_OK))
11600     {
11601       if (_setup.line_length ISNT 0)
11602         {
11603           CHP(parse_line(_setup.blocktext, &(_setup.block1), &_setup));
11604         }
11605     }
11606   else if (read_status IS RS274NGC_ENDFILE);
11607   else
11608     ERP(read_status);
11609   return read_status;
11610 }
11611 
11612 /***********************************************************************/
11613 
11614 /* rs274ngc_reset
11615 
11616 Returned Value: int (RS274NGC_OK)
11617 
11618 Side Effects: See below
11619 
11620 Called By:
11621    external programs
11622    rs274ngc_close
11623    rs274ngc_exit
11624    rs274ngc_open
11625 
11626 This function resets the parts of the _setup model having to do with
11627 reading and interpreting one line. It does not affect the parts of the
11628 model dealing with a file being open; rs274ngc_open and rs274ngc_close
11629 do that.
11630 
11631 There is a hierarchy of resetting the interpreter. Each of the following
11632 calls does everything the ones above it do.
11633 
11634 rs274ngc_reset()
11635 rs274ngc_close()
11636 rs274ngc_init()
11637 
11638 In addition, rs274ngc_synch and rs274ngc_restore_parameters (both of
11639 which are called by rs274ngc_init) change the model.
11640 
11641 */
11642 
11643 int rs274ngc_reset()
11644 {
11645   _setup.linetext[0] SET_TO 0;
11646   _setup.blocktext[0] SET_TO 0;
11647   _setup.line_length SET_TO 0;
11648 
11649   return RS274NGC_OK;
11650 }
11651 
11652 /***********************************************************************/
11653 
11654 /* rs274ngc_restore_parameters
11655 
11656 Returned Value:
11657   If any of the following errors occur, this returns the error code shown.
11658   Otherwise it returns RS274NGC_OK.
11659   1. The parameter file cannot be opened for reading: NCE_UNABLE_TO_OPEN_FILE
11660   2. A parameter index is out of range: NCE_PARAMETER_NUMBER_OUT_OF_RANGE
11661   3. A required parameter is missing from the file:
11662      NCE_REQUIRED_PARAMETER_MISSING
11663   4. The parameter file is not in increasing order:
11664      NCE_PARAMETER_FILE_OUT_OF_ORDER
11665 
11666 Side Effects: See below
11667 
11668 Called By:
11669   external programs
11670   rs274ngc_init
11671 
11672 This function restores the parameters from a file, modifying the
11673 parameters array. Usually parameters is _setup.parameters. The file
11674 contains lines of the form:
11675 
11676 <variable number> <value>
11677 
11678 e.g.,
11679 
11680 5161 10.456
11681 
11682 The variable numbers must be in increasing order, and certain
11683 parameters must be included, as given in the _required_parameters
11684 array. These are the axis offsets, the origin index (5220), and nine
11685 sets of origin offsets. Any parameter not given a value in the file
11686 has its value set to zero.
11687 
11688 */
11689 int rs274ngc_restore_parameters( /* ARGUMENTS                        */
11690  const char * filename)          /* name of parameter file to read   */
11691 {
11692   static char name[] SET_TO "rs274ngc_restore_parameters";
11693   FILE * infile;
11694   char line[256];
11695   int variable;
11696   double value;
11697   int required;    // number of next required parameter
11698   int index;       // index into _required_parameters
11699   double * pars;      // short name for _setup.parameters
11700   int k;
11701 
11702   // open original for reading
11703   infile SET_TO fopen(filename, "r");
11704   CHK((infile IS NULL), NCE_UNABLE_TO_OPEN_FILE);
11705 
11706   pars SET_TO _setup.parameters;
11707   k SET_TO 0;
11708   index SET_TO 0;
11709   required SET_TO _required_parameters[index++];
11710   while (feof(infile) IS 0)
11711     {
11712       if (fgets(line, 256, infile) IS NULL)
11713         {
11714           break;
11715         }
11716 
11717       // try for a variable-value match in the file
11718       if (sscanf(line, "%d %lf", &variable, &value) IS 2)
11719         {
11720           CHK(((variable <= 0) OR (variable >= RS274NGC_MAX_PARAMETERS)),
11721               NCE_PARAMETER_NUMBER_OUT_OF_RANGE);
11722           for (; k < RS274NGC_MAX_PARAMETERS; k++)
11723             {
11724               if (k > variable)
11725                 ERM(NCE_PARAMETER_FILE_OUT_OF_ORDER);
11726               else if (k IS variable)
11727                 {
11728                   pars[k] SET_TO value;
11729                   if (k IS required)
11730                     required SET_TO _required_parameters[index++];
11731                   k++;
11732                   break;
11733                 }
11734               else // if (k < variable)
11735                 {
11736                   if (k IS required)
11737                     ERM(NCE_REQUIRED_PARAMETER_MISSING);
11738                   else
11739                     pars[k] SET_TO 0;
11740                 }
11741             }
11742         }
11743     }
11744   fclose(infile);
11745   CHK((required ISNT RS274NGC_MAX_PARAMETERS), NCE_REQUIRED_PARAMETER_MISSING);
11746   for (; k < RS274NGC_MAX_PARAMETERS; k++)
11747     {
11748       pars[k] SET_TO 0;
11749     }
11750   return RS274NGC_OK;
11751 }
11752 
11753 /***********************************************************************/
11754 
11755 /* rs274ngc_save_parameters
11756 
11757 Returned Value:
11758   If any of the following errors occur, this returns the error code shown.
11759   Otherwise it returns RS274NGC_OK.
11760   1. The existing file cannot be renamed:  NCE_CANNOT_CREATE_BACKUP_FILE
11761   2. The renamed file cannot be opened to read: NCE_CANNOT_OPEN_BACKUP_FILE
11762   3. The new file cannot be opened to write: NCE_CANNOT_OPEN_VARIABLE_FILE
11763   4. A parameter index is out of range: NCE_PARAMETER_NUMBER_OUT_OF_RANGE
11764   5. The renamed file is out of order: NCE_PARAMETER_FILE_OUT_OF_ORDER
11765 
11766 Side Effects: See below
11767 
11768 Called By:
11769    external programs
11770    rs274ngc_exit
11771 
11772 A file containing variable-value assignments is updated. The old
11773 version of the file is saved under a different name.  For each
11774 variable-value pair in the old file, a line is written in the new file
11775 giving the current value of the variable.  File lines have the form:
11776 
11777 <variable number> <value>
11778 
11779 e.g.,
11780 
11781 5161 10.456
11782 
11783 If a required parameter is missing from the input file, this does not
11784 complain, but does write it in the output file.
11785 
11786 */
11787 int rs274ngc_save_parameters( /* ARGUMENTS             */
11788  const char * filename,       /* name of file to write */
11789  const double parameters[])   /* parameters to save    */
11790 {
11791   static char name[] SET_TO "rs274ngc_save_parameters";
11792   FILE * infile;
11793   FILE * outfile;
11794   char line[256];
11795   int variable;
11796   double value;
11797   int required;    // number of next required parameter
11798   int index;       // index into _required_parameters
11799   int k;
11800 
11801   // rename as .bak
11802   strcpy(line, filename);
11803   strcat(line, RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX);
11804   CHK((rename(filename, line) ISNT 0), NCE_CANNOT_CREATE_BACKUP_FILE);
11805 
11806   // open backup for reading
11807   infile SET_TO fopen(line, "r");
11808   CHK((infile IS NULL), NCE_CANNOT_OPEN_BACKUP_FILE);
11809 
11810   // open original for writing
11811   outfile SET_TO fopen(filename, "w");
11812   CHK((outfile IS NULL), NCE_CANNOT_OPEN_VARIABLE_FILE);
11813 
11814   k SET_TO 0;
11815   index SET_TO 0;
11816   required SET_TO _required_parameters[index++];
11817   while (feof(infile) IS 0)
11818     {
11819       if (fgets(line, 256, infile) IS NULL)
11820         {
11821           break;
11822         }
11823       // try for a variable-value match
11824       if (sscanf(line, "%d %lf", &variable, &value) IS 2)
11825         {
11826           CHK(((variable <= 0) OR (variable >= RS274NGC_MAX_PARAMETERS)),
11827               NCE_PARAMETER_NUMBER_OUT_OF_RANGE);
11828           for (; k < RS274NGC_MAX_PARAMETERS; k++)
11829             {
11830               if (k > variable)
11831                 ERM(NCE_PARAMETER_FILE_OUT_OF_ORDER);
11832               else if (k IS variable)
11833                 {
11834                   sprintf(line, "%d\t%f\n", k, parameters[k]);
11835                   fputs(line, outfile);
11836                   if (k IS required)
11837                     required SET_TO _required_parameters[index++];
11838                   k++;
11839                   break;
11840                 }
11841               else if (k IS required) // know (k < variable)
11842                 {
11843                   sprintf(line, "%d\t%f\n", k, parameters[k]);
11844                   fputs(line, outfile);
11845                   required SET_TO _required_parameters[index++];
11846                 }
11847             }
11848         }
11849     }
11850   fclose(infile);
11851   for (; k < RS274NGC_MAX_PARAMETERS; k++)
11852     {
11853       if (k IS required)
11854         {
11855           sprintf(line, "%d\t%f\n", k, parameters[k]);
11856           fputs(line, outfile);
11857           required SET_TO _required_parameters[index++];
11858         }
11859     }
11860   fclose(outfile);
11861 
11862   return RS274NGC_OK;
11863 }
11864 
11865 /***********************************************************************/
11866 
11867 /* rs274ngc_synch
11868 
11869 Returned Value: int (RS274NGC_OK)
11870 
11871 Side Effects:
11872    sets the value of many attribute of _setup by calling various
11873    GET_EXTERNAL_xxx functions.
11874 
11875 Called By:
11876    rs274ngc_init
11877    external programs
11878 
11879 This function gets the _setup world model in synch with the rest of
11880 the controller.
11881 
11882 */
11883 
11884 int rs274ngc_synch() /* NO ARGUMENTS */
11885 {
11886   _setup.control_mode SET_TO GET_EXTERNAL_MOTION_CONTROL_MODE();
11887 #ifdef AA
11888   _setup.AA_current SET_TO GET_EXTERNAL_POSITION_A(); /*AA*/
11889 #endif
11890 #ifdef BB
11891   _setup.BB_current SET_TO GET_EXTERNAL_POSITION_B(); /*BB*/
11892 #endif
11893 #ifdef CC
11894   _setup.CC_current SET_TO GET_EXTERNAL_POSITION_C(); /*CC*/
11895 #endif
11896   _setup.current_slot SET_TO GET_EXTERNAL_TOOL_SLOT();
11897   _setup.current_x SET_TO GET_EXTERNAL_POSITION_X();
11898   _setup.current_y SET_TO GET_EXTERNAL_POSITION_Y();
11899   _setup.current_z SET_TO GET_EXTERNAL_POSITION_Z();
11900   _setup.feed_rate SET_TO GET_EXTERNAL_FEED_RATE();
11901   _setup.flood SET_TO (GET_EXTERNAL_FLOOD() ISNT 0) ? ON : OFF;
11902   _setup.length_units SET_TO GET_EXTERNAL_LENGTH_UNIT_TYPE();
11903   _setup.mist SET_TO (GET_EXTERNAL_MIST() ISNT 0) ? ON : OFF;
11904   _setup.plane SET_TO GET_EXTERNAL_PLANE();
11905   _setup.selected_tool_slot SET_TO GET_EXTERNAL_TOOL_SLOT();
11906   _setup.speed SET_TO GET_EXTERNAL_SPEED();
11907   _setup.spindle_turning SET_TO GET_EXTERNAL_SPINDLE();
11908   _setup.tool_max SET_TO GET_EXTERNAL_TOOL_MAX();
11909   _setup.traverse_rate SET_TO GET_EXTERNAL_TRAVERSE_RATE();
11910 
11911   rs274ngc_load_tool_table(); /*  must set  _setup.tool_max first */
11912 
11913   return RS274NGC_OK;
11914 }
11915 
11916 /***********************************************************************/
11917 /***********************************************************************/
11918 
11919 /*
11920 
11921 The functions in this section are to extract information from the
11922 interpreter.
11923 
11924 */
11925 
11926 /***********************************************************************/
11927 
11928 /* rs274ngc_active_g_codes
11929 
11930 Returned Value: none
11931 
11932 Side Effects: copies active G codes into the codes array
11933 
11934 Called By: external programs
11935 
11936 See documentation of write_g_codes.
11937 
11938 */
11939 
11940 void rs274ngc_active_g_codes( /* ARGUMENTS                   */
11941  int * codes)                 /* array of codes to copy into */
11942 {
11943   int n;
11944 
11945   for (n SET_TO 0; n < RS274NGC_ACTIVE_G_CODES; n++)
11946     {
11947       codes[n] SET_TO _setup.active_g_codes[n];
11948     }
11949 }
11950 
11951 /***********************************************************************/
11952 
11953 /* rs274ngc_active_m_codes
11954 
11955 Returned Value: none
11956 
11957 Side Effects: copies active M codes into the codes array
11958 
11959 Called By: external programs
11960 
11961 See documentation of write_m_codes.
11962 
11963 */
11964 
11965 void rs274ngc_active_m_codes( /* ARGUMENTS                   */
11966  int * codes)                 /* array of codes to copy into */
11967 {
11968   int n;
11969 
11970   for (n SET_TO 0; n < RS274NGC_ACTIVE_M_CODES; n++)
11971     {
11972       codes[n] SET_TO _setup.active_m_codes[n];
11973     }
11974 }
11975 
11976 /***********************************************************************/
11977 
11978 /* rs274ngc_active_settings
11979 
11980 Returned Value: none
11981 
11982 Side Effects: copies active F, S settings into array
11983 
11984 Called By: external programs
11985 
11986 See documentation of write_settings.
11987 
11988 */
11989 
11990 void rs274ngc_active_settings( /* ARGUMENTS                      */
11991  double * settings)            /* array of settings to copy into */
11992 {
11993   int n;
11994 
11995   for (n SET_TO 0; n < RS274NGC_ACTIVE_SETTINGS; n++)
11996     {
11997       settings[n] SET_TO _setup.active_settings[n];
11998     }
11999 }
12000 
12001 /***********************************************************************/
12002 
12003 /* rs274ngc_error_text
12004 
12005 Returned Value: none
12006 
12007 Side Effects: see below
12008 
12009 Called By: external programs
12010 
12011 This copies the error string whose index in the _rs274ngc_errors array
12012 is error_code into the error_text array -- unless the error_code is
12013 an out-of-bounds index or the length of the error string is not less
12014 than max_size, in which case an empty string is put into the
12015 error_text. The length of the error_text array should be at least
12016 max_size.
12017 
12018 */
12019 
12020 void rs274ngc_error_text( /* ARGUMENTS                            */
12021  int error_code,          /* code number of error                 */
12022  char * error_text,       /* char array to copy error text into   */
12023  int max_size)            /* maximum number of characters to copy */
12024 {
12025   if (((error_code >= RS274NGC_MIN_ERROR) AND
12026        (error_code <= RS274NGC_MAX_ERROR)) AND
12027       (strlen(_rs274ngc_errors[error_code]) < ((size_t) max_size) ))
12028     {
12029       strcpy(error_text, _rs274ngc_errors[error_code]);
12030     }
12031   else
12032     error_text[0] SET_TO 0;
12033 }
12034 
12035 /***********************************************************************/
12036 
12037 /* rs274ngc_file_name
12038 
12039 Returned Value: none
12040 
12041 Side Effects: see below
12042 
12043 Called By: external programs
12044 
12045 This copies the _setup.filename (the name of the currently open
12046 file) into the file_name array -- unless the name is not shorter than
12047 max_size, in which case a null string is put in the file_name array.
12048 
12049 
12050 */
12051 
12052 void rs274ngc_file_name( /* ARGUMENTS                            */
12053  char * file_name,       /* string: to copy file name into       */
12054  int max_size)           /* maximum number of characters to copy */
12055 {
12056   if (strlen(_setup.filename) < ((size_t) max_size) )
12057     strcpy(file_name, _setup.filename);
12058   else
12059     file_name[0] SET_TO 0;
12060 }
12061 
12062 /***********************************************************************/
12063 
12064 /* rs274ngc_line_length
12065 
12066 Returned Value: the length of the most recently read line
12067 
12068 Side Effects: none
12069 
12070 Called By: external programs
12071 
12072 */
12073 
12074 int rs274ngc_line_length()
12075 {
12076   return _setup.line_length;
12077 }
12078 
12079 /***********************************************************************/
12080 
12081 /* rs274ngc_line_text
12082 
12083 Returned Value: none
12084 
12085 Side Effects: See below
12086 
12087 Called By: external programs
12088 
12089 This copies at most (max_size - 1) non-null characters of the most
12090 recently read line into the line_text string and puts a NULL after the
12091 last non-null character.
12092 
12093 */
12094 
12095 void rs274ngc_line_text( /* ARGUMENTS                            */
12096  char * line_text,       /* string: to copy line into            */
12097  int max_size)           /* maximum number of characters to copy */
12098 {
12099   int n;
12100   char * the_text;
12101 
12102   the_text SET_TO _setup.linetext;
12103   for (n SET_TO 0; n < (max_size - 1); n++)
12104     {
12105       if (the_text[n] ISNT 0)
12106         line_text[n] SET_TO the_text[n];
12107       else
12108         break;
12109     }
12110   line_text[n] SET_TO 0;
12111 }
12112 
12113 /***********************************************************************/
12114 
12115 /* rs274ngc_sequence_number
12116 
12117 Returned Value: the current interpreter sequence number (how many
12118 lines read since the last time the sequence number was reset to zero,
12119 which happens only when rs274ngc_init or rs274ngc_open is called).
12120 
12121 Side Effects: none
12122 
12123 Called By: external programs
12124 
12125 */
12126 
12127 int rs274ngc_sequence_number()
12128 {
12129   return _setup.sequence_number;
12130 }
12131 
12132 /***********************************************************************/
12133 
12134 /* rs274ngc_stack_name
12135 
12136 Returned Value: none
12137 
12138 Side Effects: see below
12139 
12140 Called By: external programs
12141 
12142 This copies at most (max_size - 1) non-null characters from the
12143 string whose index in the _setup.stack array is stack_index into the
12144 function_name string and puts a NULL after the last non-null character --
12145 unless the stack_index is an out-of-bounds index, in which case an
12146 empty string is put into the function_name.
12147 
12148 This function is intended to be used several times in a row to get the
12149 stack of function calls that existed when the most recent error
12150 occurred. It should be called first with stack_index equal to 0,
12151 next with stack_index equal to 1, and so on, stopping when an
12152 empty string is returned for the name.
12153 
12154 */
12155 
12156 void rs274ngc_stack_name( /* ARGUMENTS                            */
12157  int stack_index,         /* index into stack of function names   */
12158  char * function_name,    /* string: to copy function name into   */
12159  int max_size)            /* maximum number of characters to copy */
12160 {
12161   int n;
12162   char * the_name;
12163 
12164   if ((stack_index > -1) AND (stack_index < 20))
12165     {
12166       the_name SET_TO _setup.stack[stack_index];
12167       for (n SET_TO 0; n < (max_size - 1); n++)
12168         {
12169           if (the_name[n] ISNT 0)
12170             function_name[n] SET_TO the_name[n];
12171           else
12172             break;
12173         }
12174       function_name[n] SET_TO 0;
12175     }
12176   else
12177     function_name[0] SET_TO 0;
12178 }
12179 
12180 /***********************************************************************/
12181 /***********************************************************************/
12182 /* end of file */

Generated on Sun Dec 2 15:27:43 2001 for EMC by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001