1 |
|
/******************************************************************** |
2 |
|
* Description: interp_internal.hh |
3 |
|
* |
4 |
|
* Derived from a work by Thomas Kramer |
5 |
|
* |
6 |
|
* Author: |
7 |
|
* License: GPL Version 2 |
8 |
|
* System: Linux |
9 |
|
* |
10 |
|
* Copyright (c) 2004 All rights reserved. |
11 |
|
* |
12 |
|
********************************************************************/ |
13 |
|
#ifndef INTERP_INTERNAL_HH |
14 |
|
#define INTERP_INTERNAL_HH |
15 |
|
|
16 |
|
#include <algorithm> |
17 |
|
#include "config.h" |
18 |
|
#include <limits.h> |
19 |
|
#include <stdio.h> |
20 |
|
#include <set> |
21 |
|
#include <map> |
22 |
|
#include <bitset> |
23 |
|
#include "canon.hh" |
24 |
|
#include "emcpos.h" |
25 |
|
#include "libintl.h" |
26 |
|
#include <boost/python/object_fwd.hpp> |
27 |
|
#include <cmath> |
28 |
|
|
29 |
|
|
30 |
|
#define _(s) gettext(s) |
31 |
|
|
32 |
|
/**********************/ |
33 |
|
/* COMPILER MACROS */ |
34 |
|
/**********************/ |
35 |
|
|
36 |
|
template<class T> |
37 |
|
T R2D(T r) { return r * (180. / M_PI); } |
38 |
|
template<class T> |
39 |
351 |
T D2R(T r) { return r * (M_PI / 180.); } |
40 |
|
template<class T> |
41 |
78 |
T SQ(T a) { return a*a; } |
42 |
|
|
43 |
|
template<class T> |
44 |
97 |
inline int round_to_int(T x) { |
45 |
97 |
return (int)std::nearbyint(x); |
46 |
|
} |
47 |
|
|
48 |
|
/* how far above hole bottom for rapid return, in inches */ |
49 |
|
#define G83_RAPID_DELTA 0.010 |
50 |
|
|
51 |
|
/* nested remap: a remapped code is found in the body of a subroutine |
52 |
|
* which is executing on behalf of another remapped code |
53 |
|
* example: a user G code command executes a tool change |
54 |
|
*/ |
55 |
|
#define MAX_NESTED_REMAPS 10 |
56 |
|
|
57 |
|
// English - Metric conversion (long number keeps error buildup down) |
58 |
|
#define MM_PER_INCH 25.4 |
59 |
|
//#define INCH_PER_MM 0.039370078740157477 |
60 |
|
|
61 |
|
/* numerical constants */ |
62 |
|
|
63 |
|
/***************************************************************************** |
64 |
|
The default tolerance (if none tighter is specified in the ini file) should be: |
65 |
|
2 * 0.001 * sqrt(2) for inch, and 2 * 0.01 * sqrt(2) for mm. |
66 |
|
This would mean that any valid arc where the endpoints and/or centerpoint |
67 |
|
got rounded or truncated to 0.001 inch or 0.01 mm precision would be accepted. |
68 |
|
|
69 |
|
Tighter tolerance down to a minimum of 1 micron +- also accepted. |
70 |
|
******************************************************************************/ |
71 |
|
|
72 |
|
#define CENTER_ARC_RADIUS_TOLERANCE_INCH (2 * 0.001 * M_SQRT2) |
73 |
|
#define MIN_CENTER_ARC_RADIUS_TOLERANCE_INCH 0.00004 |
74 |
|
|
75 |
|
// Note: started from original tolerance and divided by 10 here (since that was originally done inside the interpreter) |
76 |
|
#define RADIUS_TOLERANCE_INCH 0.00005 |
77 |
|
|
78 |
|
/* Equivalent metric constants */ |
79 |
|
|
80 |
|
#define CENTER_ARC_RADIUS_TOLERANCE_MM (2 * 0.01 * M_SQRT2) |
81 |
|
#define MIN_CENTER_ARC_RADIUS_TOLERANCE_MM 0.001 |
82 |
|
|
83 |
|
#define RADIUS_TOLERANCE_MM (RADIUS_TOLERANCE_INCH * MM_PER_INCH) |
84 |
|
|
85 |
|
// Modest relative error |
86 |
|
#define SPIRAL_RELATIVE_TOLERANCE 0.001 |
87 |
|
|
88 |
|
/* angle threshold for concavity for cutter compensation, in radians */ |
89 |
|
#define TOLERANCE_CONCAVE_CORNER 0.05 |
90 |
|
#define TOLERANCE_EQUAL 0.0001 /* two numbers compare EQ if the |
91 |
|
difference is less than this */ |
92 |
|
|
93 |
|
static inline bool equal(double a, double b) |
94 |
|
{ |
95 |
314 |
return (fabs(a - b) < TOLERANCE_EQUAL); |
96 |
|
} |
97 |
|
|
98 |
|
|
99 |
|
#define TINY 1e-12 /* for arc_data_r */ |
100 |
|
|
101 |
|
// max number of m codes on one line |
102 |
|
#define MAX_EMS 4 |
103 |
|
|
104 |
|
// feed_mode |
105 |
|
enum feed_mode { UNITS_PER_MINUTE=0, INVERSE_TIME=1, UNITS_PER_REVOLUTION=2 }; |
106 |
|
|
107 |
|
// cutter radius compensation mode, 0 or false means none |
108 |
|
// not using CANON_SIDE since interpreter handles cutter radius comp |
109 |
|
#define RIGHT 1 |
110 |
|
#define LEFT 2 |
111 |
|
|
112 |
|
// spindle control modes |
113 |
|
enum SPINDLE_MODE { CONSTANT_RPM, CONSTANT_SURFACE }; |
114 |
|
|
115 |
|
// unary operations |
116 |
|
// These are not enums because the "&" operator is used in |
117 |
|
// reading the operation names and is illegal with an enum |
118 |
|
|
119 |
|
#define ABS 1 |
120 |
|
#define ACOS 2 |
121 |
|
#define ASIN 3 |
122 |
|
#define ATAN 4 |
123 |
|
#define COS 5 |
124 |
|
#define EXP 6 |
125 |
|
#define FIX 7 |
126 |
|
#define FUP 8 |
127 |
|
#define LN 9 |
128 |
|
#define ROUND 10 |
129 |
|
#define SIN 11 |
130 |
|
#define SQRT 12 |
131 |
|
#define TAN 13 |
132 |
|
#define EXISTS 14 |
133 |
|
|
134 |
|
|
135 |
|
// binary operations |
136 |
|
#define NO_OPERATION 0 |
137 |
|
#define DIVIDED_BY 1 |
138 |
|
#define MODULO 2 |
139 |
|
#define POWER 3 |
140 |
|
#define TIMES 4 |
141 |
|
#define AND2 5 |
142 |
|
#define EXCLUSIVE_OR 6 |
143 |
|
#define MINUS 7 |
144 |
|
#define NON_EXCLUSIVE_OR 8 |
145 |
|
#define PLUS 9 |
146 |
|
#define RIGHT_BRACKET 10 |
147 |
|
|
148 |
|
/* relational operators (are binary operators)*/ |
149 |
|
#define LT 11 |
150 |
|
#define EQ 12 |
151 |
|
#define NE 13 |
152 |
|
#define LE 14 |
153 |
|
#define GE 15 |
154 |
|
#define GT 16 |
155 |
|
#define RELATIONAL_OP_FIRST 11 |
156 |
|
#define RELATIONAL_OP_LAST 16 |
157 |
|
|
158 |
|
// O code |
159 |
|
#define O_none 0 |
160 |
|
#define O_sub 1 |
161 |
|
#define O_endsub 2 |
162 |
|
#define O_call 3 |
163 |
|
#define O_do 4 |
164 |
|
#define O_while 5 |
165 |
|
#define O_if 6 |
166 |
|
#define O_elseif 7 |
167 |
|
#define O_else 8 |
168 |
|
#define O_endif 9 |
169 |
|
#define O_break 10 |
170 |
|
#define O_continue 11 |
171 |
|
#define O_endwhile 12 |
172 |
|
#define O_return 13 |
173 |
|
#define O_repeat 14 |
174 |
|
#define O_endrepeat 15 |
175 |
|
|
176 |
|
// G Codes are symbolic to be dialect-independent in source code |
177 |
|
#define G_0 0 |
178 |
|
#define G_1 10 |
179 |
|
#define G_2 20 |
180 |
|
#define G_3 30 |
181 |
|
#define G_4 40 |
182 |
|
#define G_5 50 |
183 |
|
#define G_5_1 51 |
184 |
|
#define G_5_2 52 |
185 |
|
#define G_5_3 53 |
186 |
|
#define G_7 70 |
187 |
|
#define G_8 80 |
188 |
|
#define G_10 100 |
189 |
|
#define G_17 170 |
190 |
|
#define G_17_1 171 |
191 |
|
#define G_18 180 |
192 |
|
#define G_18_1 181 |
193 |
|
#define G_19 190 |
194 |
|
#define G_19_1 191 |
195 |
|
#define G_20 200 |
196 |
|
#define G_21 210 |
197 |
|
#define G_28 280 |
198 |
|
#define G_28_1 281 |
199 |
|
#define G_30 300 |
200 |
|
#define G_30_1 301 |
201 |
|
#define G_33 330 |
202 |
|
#define G_33_1 331 |
203 |
|
#define G_38_2 382 |
204 |
|
#define G_38_3 383 |
205 |
|
#define G_38_4 384 |
206 |
|
#define G_38_5 385 |
207 |
|
#define G_40 400 |
208 |
|
#define G_41 410 |
209 |
|
#define G_41_1 411 |
210 |
|
#define G_42 420 |
211 |
|
#define G_42_1 421 |
212 |
|
#define G_43 430 |
213 |
|
#define G_43_1 431 |
214 |
|
#define G_43_2 432 |
215 |
|
#define G_49 490 |
216 |
|
#define G_50 500 |
217 |
|
#define G_51 510 |
218 |
|
#define G_52 520 |
219 |
|
#define G_53 530 |
220 |
|
#define G_54 540 |
221 |
|
#define G_55 550 |
222 |
|
#define G_56 560 |
223 |
|
#define G_57 570 |
224 |
|
#define G_58 580 |
225 |
|
#define G_59 590 |
226 |
|
#define G_59_1 591 |
227 |
|
#define G_59_2 592 |
228 |
|
#define G_59_3 593 |
229 |
|
#define G_61 610 |
230 |
|
#define G_61_1 611 |
231 |
|
#define G_64 640 |
232 |
|
#define G_73 730 |
233 |
|
#define G_76 760 |
234 |
|
#define G_80 800 |
235 |
|
#define G_81 810 |
236 |
|
#define G_82 820 |
237 |
|
#define G_83 830 |
238 |
|
#define G_84 840 |
239 |
|
#define G_85 850 |
240 |
|
#define G_86 860 |
241 |
|
#define G_87 870 |
242 |
|
#define G_88 880 |
243 |
|
#define G_89 890 |
244 |
|
#define G_90 900 |
245 |
|
#define G_90_1 901 |
246 |
|
#define G_91 910 |
247 |
|
#define G_91_1 911 |
248 |
|
#define G_92 920 |
249 |
|
#define G_92_1 921 |
250 |
|
#define G_92_2 922 |
251 |
|
#define G_92_3 923 |
252 |
|
#define G_93 930 |
253 |
|
#define G_94 940 |
254 |
|
#define G_95 950 |
255 |
|
#define G_96 960 |
256 |
|
#define G_97 970 |
257 |
|
#define G_98 980 |
258 |
|
#define G_99 990 |
259 |
|
|
260 |
|
// name of parameter file for saving/restoring interpreter variables |
261 |
|
#define RS274NGC_PARAMETER_FILE_NAME_DEFAULT "rs274ngc.var" |
262 |
|
#define RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX ".bak" |
263 |
|
|
264 |
|
// number of parameters in parameter table |
265 |
|
|
266 |
|
// leave some room above 5428 for further introspection |
267 |
|
// 5599 = control DEBUG, output, 0=no output; default=1.0 |
268 |
|
// 5600-5601 = toolchanger codes |
269 |
|
#define RS274NGC_MAX_PARAMETERS 5602 |
270 |
|
|
271 |
|
// Subroutine parameters |
272 |
|
#define INTERP_SUB_PARAMS 30 |
273 |
|
#define INTERP_SUB_ROUTINE_LEVELS 10 |
274 |
|
#define INTERP_FIRST_SUBROUTINE_PARAM 1 |
275 |
|
|
276 |
|
// max number of local variables saved (?) |
277 |
|
#define MAX_NAMED_PARAMETERS 50 |
278 |
|
|
279 |
|
/**********************/ |
280 |
|
/* TYPEDEFS */ |
281 |
|
/**********************/ |
282 |
|
|
283 |
|
/* distance_mode */ |
284 |
|
typedef enum |
285 |
|
{ MODE_ABSOLUTE, MODE_INCREMENTAL } |
286 |
|
DISTANCE_MODE; |
287 |
|
|
288 |
|
/* retract_mode for cycles */ |
289 |
|
typedef enum |
290 |
|
{ R_PLANE, OLD_Z } |
291 |
|
RETRACT_MODE; |
292 |
|
|
293 |
|
// string table - to get rid of strdup/free |
294 |
|
const char *strstore(const char *s); |
295 |
|
|
296 |
|
|
297 |
|
// Block execution phases in execution order |
298 |
|
// very carefully check code for sequencing when |
299 |
|
// adding phases! |
300 |
|
|
301 |
|
// used to record execution trail in breadcrumbs |
302 |
|
enum phases { |
303 |
|
NO_REMAPPED_STEPS, |
304 |
|
STEP_COMMENT, |
305 |
|
STEP_SPINDLE_MODE, |
306 |
|
STEP_FEED_MODE, |
307 |
|
STEP_SET_FEED_RATE, |
308 |
|
STEP_SET_SPINDLE_SPEED, |
309 |
|
STEP_PREPARE, |
310 |
|
STEP_M_5, |
311 |
|
STEP_M_6, |
312 |
|
STEP_RETAIN_G43, |
313 |
|
STEP_M_7, |
314 |
|
STEP_M_8, |
315 |
|
STEP_M_9, |
316 |
|
STEP_M_10, |
317 |
|
STEP_DWELL, |
318 |
|
STEP_SET_PLANE, |
319 |
|
STEP_LENGTH_UNITS, |
320 |
|
STEP_LATHE_DIAMETER_MODE, |
321 |
|
STEP_CUTTER_COMP, |
322 |
|
STEP_TOOL_LENGTH_OFFSET, |
323 |
|
STEP_COORD_SYSTEM, |
324 |
|
STEP_CONTROL_MODE, |
325 |
|
STEP_DISTANCE_MODE, |
326 |
|
STEP_IJK_DISTANCE_MODE, |
327 |
|
STEP_RETRACT_MODE, |
328 |
|
STEP_MODAL_0, |
329 |
|
STEP_MOTION, |
330 |
|
STEP_MGROUP4, |
331 |
|
MAX_STEPS |
332 |
|
}; |
333 |
|
|
334 |
|
|
335 |
|
typedef struct remap_struct remap; |
336 |
|
typedef remap *remap_pointer; |
337 |
|
|
338 |
|
// the remap configuration descriptor |
339 |
|
typedef struct remap_struct { |
340 |
|
const char *name; |
341 |
|
const char *argspec; |
342 |
|
// if no modalgroup= was given in the REMAP= line, use these defaults |
343 |
|
#define MCODE_DEFAULT_MODAL_GROUP 10 |
344 |
|
#define GCODE_DEFAULT_MODAL_GROUP 1 |
345 |
|
int modal_group; |
346 |
|
int motion_code; // only for g's - to identify cycles |
347 |
|
const char *prolog_func; // Py function or null |
348 |
|
const char *remap_py; // Py function maybe null, OR |
349 |
|
const char *remap_ngc; // NGC file, maybe null |
350 |
|
const char *epilog_func; // Py function or null |
351 |
|
} remap; |
352 |
|
|
353 |
|
|
354 |
|
// case insensitive compare for std::map etc |
355 |
|
struct nocase_cmp |
356 |
|
{ |
357 |
106139 |
bool operator()(const char* s1, const char* s2) const |
358 |
|
{ |
359 |
106139 |
return strcasecmp(s1, s2) < 0; |
360 |
|
} |
361 |
|
}; |
362 |
|
|
363 |
|
typedef std::map<const char *,remap,nocase_cmp> remap_map; |
364 |
|
typedef remap_map::iterator remap_iterator; |
365 |
|
|
366 |
|
typedef std::map<int, remap_pointer> int_remap_map; |
367 |
|
typedef int_remap_map::iterator int_remap_iterator; |
368 |
|
|
369 |
|
#define REMAP_FUNC(r) (r->remap_ngc ? r->remap_ngc: \ |
370 |
|
(r->remap_py ? r->remap_py : "BUG-no-remap-func")) |
371 |
|
|
372 |
|
typedef struct block_struct |
373 |
|
{ |
374 |
|
block_struct (); |
375 |
|
|
376 |
|
bool a_flag; |
377 |
|
double a_number; |
378 |
|
bool b_flag; |
379 |
|
double b_number; |
380 |
|
bool c_flag; |
381 |
|
double c_number; |
382 |
|
char comment[256]; |
383 |
|
double d_number_float; |
384 |
|
bool d_flag; |
385 |
|
bool e_flag; |
386 |
|
double e_number; |
387 |
|
bool f_flag; |
388 |
|
double f_number; |
389 |
|
|
390 |
|
// Modal groups |
391 |
|
// also indices into g_modes |
392 |
|
// unused: 9,11 |
393 |
|
#define GM_MODAL_0 0 |
394 |
|
#define GM_MOTION 1 |
395 |
|
#define GM_SET_PLANE 2 |
396 |
|
#define GM_DISTANCE_MODE 3 |
397 |
|
#define GM_IJK_DISTANCE_MODE 4 |
398 |
|
#define GM_FEED_MODE 5 |
399 |
|
#define GM_LENGTH_UNITS 6 |
400 |
|
#define GM_CUTTER_COMP 7 |
401 |
|
#define GM_TOOL_LENGTH_OFFSET 8 |
402 |
|
#define GM_RETRACT_MODE 10 |
403 |
|
#define GM_COORD_SYSTEM 12 |
404 |
|
#define GM_CONTROL_MODE 13 |
405 |
|
#define GM_SPINDLE_MODE 14 |
406 |
|
#define GM_LATHE_DIAMETER_MODE 15 |
407 |
|
|
408 |
|
|
409 |
|
int g_modes[16]; |
410 |
|
bool h_flag; |
411 |
|
int h_number; |
412 |
|
bool i_flag; |
413 |
|
double i_number; |
414 |
|
bool j_flag; |
415 |
|
double j_number; |
416 |
|
bool k_flag; |
417 |
|
double k_number; |
418 |
|
int l_number; |
419 |
|
bool l_flag; |
420 |
|
int line_number; |
421 |
|
int saved_line_number; // value of sequence_number when a remap was encountered |
422 |
|
int n_number; |
423 |
|
int motion_to_be; |
424 |
|
int m_count; |
425 |
|
int m_modes[11]; |
426 |
|
int user_m; |
427 |
|
double p_number; |
428 |
|
bool p_flag; |
429 |
|
double q_number; |
430 |
|
bool q_flag; |
431 |
|
bool r_flag; |
432 |
|
double r_number; |
433 |
|
bool s_flag; |
434 |
|
double s_number; |
435 |
|
bool t_flag; |
436 |
|
int t_number; |
437 |
|
bool u_flag; |
438 |
|
double u_number; |
439 |
|
bool v_flag; |
440 |
|
double v_number; |
441 |
|
bool w_flag; |
442 |
|
double w_number; |
443 |
|
bool x_flag; |
444 |
|
double x_number; |
445 |
|
bool y_flag; |
446 |
|
double y_number; |
447 |
|
bool z_flag; |
448 |
|
double z_number; |
449 |
|
|
450 |
|
int radius_flag; |
451 |
|
double radius; |
452 |
|
int theta_flag; |
453 |
|
double theta; |
454 |
|
|
455 |
|
// control (o-word) stuff |
456 |
|
long offset; // start of line in file |
457 |
|
int o_type; |
458 |
|
int call_type; // oword-sub, python oword-sub, remap |
459 |
|
const char *o_name; // !!!KL be sure to free this |
460 |
|
double params[INTERP_SUB_PARAMS]; |
461 |
|
int param_cnt; |
462 |
|
|
463 |
|
// bitmap of phases already executed |
464 |
|
// we have some 31 or so different steps in a block. We must remember |
465 |
|
// which one is done when we reexecute a block after a remap. |
466 |
|
std::bitset<MAX_STEPS> breadcrumbs; |
467 |
|
|
468 |
|
#define TICKOFF(step) block->breadcrumbs[step] = 1 |
469 |
|
#define TODO(step) (block->breadcrumbs[step] == 0) |
470 |
|
#define ONCE(step) (TODO(step) ? TICKOFF(step),1 : 0) |
471 |
|
#define ONCE_M(step) (TODO(STEP_M_ ## step) ? TICKOFF(STEP_M_ ## step),1 : 0) |
472 |
|
|
473 |
|
|
474 |
|
// there might be several remapped items in a block, but at any point |
475 |
|
// in time there's only one excuting |
476 |
|
// conceptually blocks[1..n] are also the 'remap frames' |
477 |
|
remap_pointer executing_remap; // refers to config descriptor |
478 |
|
std::set<int> remappings; // all remappings in this block (enum phases) |
479 |
|
int phase; // current remap execution phase |
480 |
|
|
481 |
|
// the strategy to get the builtin behaviour of a code in a remap procedure is as follows: |
482 |
|
// if recursion is detected in find_remappings() (called by parse_line()), that *step* |
483 |
|
// (roughly the modal group) is NOT added to the set of remapped steps in a block (block->remappings) |
484 |
|
// in the convert_* procedures we test if the step is remapped with the macro below, and wether |
485 |
|
// it is the current code which is remapped (IS_USER_MCODE, IS_USER_GCODE etc). If both |
486 |
|
// are true, we execute the remap procedure; if not, use the builtin code. |
487 |
|
#define STEP_REMAPPED_IN_BLOCK(bp, step) (bp->remappings.find(step) != bp->remappings.end()) |
488 |
|
|
489 |
|
// true if in a remap procedure the code being remapped was |
490 |
|
// referenced, which caused execution of the builtin semantics |
491 |
|
// reason for recording the fact: this permits an epilog to do the |
492 |
|
// right thing depending on wether the builtin was used or not. |
493 |
|
bool builtin_used; |
494 |
|
} |
495 |
|
block; |
496 |
|
|
497 |
|
// indicates which type of Python handler yielded, and needs reexecution |
498 |
|
// post sync/read_inputs |
499 |
|
enum call_states { |
500 |
|
CS_NORMAL, |
501 |
|
CS_REEXEC_PROLOG, |
502 |
|
CS_REEXEC_PYBODY, |
503 |
|
CS_REEXEC_EPILOG, |
504 |
|
CS_REEXEC_PYOSUB, |
505 |
|
}; |
506 |
|
|
507 |
|
// detail for O_call; tags the frame |
508 |
|
enum call_types { |
509 |
|
CT_NGC_OWORD_SUB, // no restartable Python code involved |
510 |
|
CT_PYTHON_OWORD_SUB, // restartable Python code may be involved |
511 |
|
CT_REMAP, // restartable Python code may be involved |
512 |
|
}; |
513 |
|
|
514 |
|
|
515 |
|
enum retopts { RET_NONE, RET_DOUBLE, RET_INT, RET_YIELD, RET_STOPITERATION, RET_ERRORMSG }; |
516 |
|
|
517 |
|
typedef block *block_pointer; |
518 |
|
|
519 |
|
// parameters will go to a std::map<const char *,paramter_value_pointer> |
520 |
|
typedef struct parameter_value_struct { |
521 |
|
double value; |
522 |
|
unsigned attr; |
523 |
|
} parameter_value; |
524 |
|
|
525 |
|
typedef parameter_value *parameter_pointer; |
526 |
|
typedef std::map<const char *, parameter_value, nocase_cmp> parameter_map; |
527 |
|
typedef parameter_map::iterator parameter_map_iterator; |
528 |
|
|
529 |
|
#define PA_READONLY 1 |
530 |
|
#define PA_GLOBAL 2 |
531 |
|
#define PA_UNSET 4 |
532 |
|
#define PA_USE_LOOKUP 8 // use lookup_named_param() to retrieve value |
533 |
|
#define PA_FROM_INI 16 // a variable of the form '_[section]value' was retrieved from the ini file |
534 |
|
#define PA_PYTHON 32 // call namedparams.<varname>() to retrieve the value |
535 |
|
|
536 |
|
// optional 3rd arg to store_named_param() |
537 |
|
// flag initialization of r/o parameter |
538 |
|
#define OVERRIDE_READONLY 1 |
539 |
|
|
540 |
|
#define MAX_REMAPOPTS 20 |
541 |
|
// current implementation limits - legal modal groups |
542 |
|
// for M and G codes |
543 |
|
#define M_MODE_OK(m) ((m > 3) && (m < 11)) |
544 |
|
#define G_MODE_OK(m) (m == 1) |
545 |
|
|
546 |
|
struct pycontext_impl; |
547 |
|
struct pycontext { |
548 |
|
pycontext(); |
549 |
|
pycontext(const struct pycontext &); |
550 |
|
pycontext &operator=(const struct pycontext &); |
551 |
|
~pycontext(); |
552 |
|
pycontext_impl *impl; |
553 |
|
}; |
554 |
|
|
555 |
|
typedef struct context_struct { |
556 |
|
context_struct(); |
557 |
|
|
558 |
|
long position; // location (ftell) in file |
559 |
|
int sequence_number; // location (line number) in file |
560 |
|
const char *filename; // name of file for this context |
561 |
|
const char *subName; // name of the subroutine (oword) |
562 |
|
double saved_params[INTERP_SUB_PARAMS]; |
563 |
|
parameter_map named_params; |
564 |
|
unsigned char context_status; // see CONTEXT_ defines below |
565 |
|
int saved_g_codes[ACTIVE_G_CODES]; // array of active G codes |
566 |
|
int saved_m_codes[ACTIVE_M_CODES]; // array of active M codes |
567 |
|
double saved_settings[ACTIVE_SETTINGS]; // array of feed, speed, etc. |
568 |
|
int call_type; // enum call_types |
569 |
|
pycontext pystuff; |
570 |
|
// Python-related stuff |
571 |
|
} context; |
572 |
|
|
573 |
|
typedef context *context_pointer; |
574 |
|
|
575 |
|
// context.context_status |
576 |
|
#define CONTEXT_VALID 1 // this was stored by M7* |
577 |
|
#define CONTEXT_RESTORE_ON_RETURN 2 // automatically execute M71 on sub return |
578 |
|
#define REMAP_FRAME 4 // a remap call frame |
579 |
|
|
580 |
|
typedef struct offset_struct { |
581 |
|
int type; |
582 |
|
const char *filename; // the name of the file |
583 |
|
long offset; // the offset in the file |
584 |
|
int sequence_number; |
585 |
|
int repeat_count; |
586 |
|
} offset; |
587 |
|
|
588 |
|
typedef std::map<const char *, offset, nocase_cmp> offset_map_type; |
589 |
|
typedef std::map<const char *, offset, nocase_cmp>::iterator offset_map_iterator; |
590 |
|
|
591 |
|
/* |
592 |
|
|
593 |
|
The current_x, current_y, and current_z are the location of the tool |
594 |
|
in the current coordinate system. current_x and current_y differ from |
595 |
|
program_x and program_y when cutter radius compensation is on. |
596 |
|
current_z is the position of the tool tip in program coordinates when |
597 |
|
tool length compensation is using the actual tool length; it is the |
598 |
|
position of the spindle when tool length is zero. |
599 |
|
|
600 |
|
In a setup, the axis_offset values are set by g92 and the origin_offset |
601 |
|
values are set by g54 - g59.3. The net origin offset uses both values |
602 |
|
and is not represented here |
603 |
|
|
604 |
|
*/ |
605 |
|
#define STACK_LEN 50 |
606 |
|
#define STACK_ENTRY_LEN 80 |
607 |
|
#define MAX_SUB_DIRS 10 |
608 |
|
|
609 |
|
struct setup |
610 |
|
{ |
611 |
|
setup(); |
612 |
|
~setup(); |
613 |
|
|
614 |
|
double AA_axis_offset; // A-axis g92 offset |
615 |
|
double AA_current; // current A-axis position |
616 |
|
double AA_origin_offset; // A-axis origin offset |
617 |
|
double BB_axis_offset; // B-axis g92offset |
618 |
|
double BB_current; // current B-axis position |
619 |
|
double BB_origin_offset; // B-axis origin offset |
620 |
|
double CC_axis_offset; // C-axis g92offset |
621 |
|
double CC_current; // current C-axis position |
622 |
|
double CC_origin_offset; // C-axis origin offset |
623 |
|
|
624 |
|
double u_axis_offset, u_current, u_origin_offset; |
625 |
|
double v_axis_offset, v_current, v_origin_offset; |
626 |
|
double w_axis_offset, w_current, w_origin_offset; |
627 |
|
|
628 |
|
int active_g_codes[ACTIVE_G_CODES]; // array of active G codes |
629 |
|
int active_m_codes[ACTIVE_M_CODES]; // array of active M codes |
630 |
|
double active_settings[ACTIVE_SETTINGS]; // array of feed, speed, etc. |
631 |
|
bool arc_not_allowed; // we just exited cutter compensation, so we error if the next move isn't straight |
632 |
|
double axis_offset_x; // X-axis g92 offset |
633 |
|
double axis_offset_y; // Y-axis g92 offset |
634 |
|
double axis_offset_z; // Z-axis g92 offset |
635 |
|
// block block1; // parsed next block |
636 |
|
// stack of controlling blocks for remap execution |
637 |
|
block blocks[MAX_NESTED_REMAPS]; |
638 |
|
// index into blocks, points to currently controlling block |
639 |
|
int remap_level; |
640 |
|
|
641 |
|
#define CONTROLLING_BLOCK(s) ((s).blocks[(s).remap_level]) |
642 |
|
#define EXECUTING_BLOCK(s) ((s).blocks[0]) |
643 |
|
|
644 |
|
char blocktext[LINELEN]; // linetext downcased, white space gone |
645 |
|
CANON_MOTION_MODE control_mode; // exact path or cutting mode |
646 |
|
int current_pocket; // carousel slot number of current tool |
647 |
|
double current_x; // current X-axis position |
648 |
|
double current_y; // current Y-axis position |
649 |
|
double current_z; // current Z-axis position |
650 |
|
double cutter_comp_radius; // current cutter compensation radius |
651 |
|
int cutter_comp_orientation; // current cutter compensation tool orientation |
652 |
|
int cutter_comp_side; // current cutter compensation side |
653 |
|
double cycle_cc; // cc-value (normal) for canned cycles |
654 |
|
double cycle_i; // i-value for canned cycles |
655 |
|
double cycle_j; // j-value for canned cycles |
656 |
|
double cycle_k; // k-value for canned cycles |
657 |
|
int cycle_l; // l-value for canned cycles |
658 |
|
double cycle_p; // p-value (dwell) for canned cycles |
659 |
|
double cycle_q; // q-value for canned cycles |
660 |
|
double cycle_r; // r-value for canned cycles |
661 |
|
double cycle_il; // "initial level" height when switching from non-cycle into cycle, for g98 retract |
662 |
|
int cycle_il_flag; // il is currently valid because we're in a series of cycles |
663 |
|
DISTANCE_MODE distance_mode; // absolute or incremental |
664 |
|
DISTANCE_MODE ijk_distance_mode; // absolute or incremental for IJK in arcs |
665 |
|
int feed_mode; // G_93 (inverse time) or G_94 units/min |
666 |
|
bool feed_override; // whether feed override is enabled |
667 |
|
double feed_rate; // feed rate in current units/min |
668 |
|
char filename[PATH_MAX]; // name of currently open NC code file |
669 |
|
FILE *file_pointer; // file pointer for open NC code file |
670 |
|
bool flood; // whether flood coolant is on |
671 |
|
CANON_UNITS length_units; // millimeters or inches |
672 |
|
double center_arc_radius_tolerance_inch; // modify with ini setting |
673 |
|
double center_arc_radius_tolerance_mm; // modify with ini setting |
674 |
|
int line_length; // length of line last read |
675 |
|
char linetext[LINELEN]; // text of most recent line read |
676 |
|
bool mist; // whether mist coolant is on |
677 |
|
int motion_mode; // active G-code for motion |
678 |
|
int origin_index; // active origin (1=G54 to 9=G59.3) |
679 |
|
double origin_offset_x; // g5x offset x |
680 |
|
double origin_offset_y; // g5x offset y |
681 |
|
double origin_offset_z; // g5x offset z |
682 |
|
double rotation_xy; // rotation of coordinate system around Z, in degrees |
683 |
|
double parameters[RS274NGC_MAX_PARAMETERS]; // system parameters |
684 |
|
int parameter_occurrence; // parameter buffer index |
685 |
|
int parameter_numbers[MAX_NAMED_PARAMETERS]; // parameter number buffer |
686 |
|
double parameter_values[MAX_NAMED_PARAMETERS]; // parameter value buffer |
687 |
|
int named_parameter_occurrence; |
688 |
|
const char *named_parameters[MAX_NAMED_PARAMETERS]; |
689 |
|
double named_parameter_values[MAX_NAMED_PARAMETERS]; |
690 |
|
bool percent_flag; // true means first line was percent sign |
691 |
|
CANON_PLANE plane; // active plane, XY-, YZ-, or XZ-plane |
692 |
|
bool probe_flag; // flag indicating probing done |
693 |
|
bool input_flag; // flag indicating waiting for input done |
694 |
|
bool toolchange_flag; // flag indicating we just had a tool change |
695 |
|
int input_index; // channel queried |
696 |
|
bool input_digital; // input queried was digital (false=analog) |
697 |
|
bool cutter_comp_firstmove; // this is the first comp move |
698 |
|
double program_x; // program x, used when cutter comp on |
699 |
|
double program_y; // program y, used when cutter comp on |
700 |
|
double program_z; // program y, used when cutter comp on |
701 |
|
RETRACT_MODE retract_mode; // for cycles, old_z or r_plane |
702 |
|
int random_toolchanger; // tool changer swaps pockets, and pocket 0 is the spindle instead of "no tool" |
703 |
|
int selected_pocket; // tool slot selected but not active |
704 |
|
int selected_tool; // start switchover to pocket-agnostic interp |
705 |
|
int sequence_number; // sequence number of line last read |
706 |
|
double speed; // current spindle speed in rpm or SxM |
707 |
|
SPINDLE_MODE spindle_mode; // CONSTANT_RPM or CONSTANT_SURFACE |
708 |
|
CANON_SPEED_FEED_MODE speed_feed_mode; // independent or synched |
709 |
|
bool speed_override; // whether speed override is enabled |
710 |
|
CANON_DIRECTION spindle_turning; // direction spindle is turning |
711 |
|
char stack[STACK_LEN][STACK_ENTRY_LEN]; // stack of calls for error reporting |
712 |
|
int stack_index; // index into the stack |
713 |
|
EmcPose tool_offset; // tool length offset |
714 |
|
int pockets_max; // number of pockets in carousel (including pocket 0, the spindle) |
715 |
|
CANON_TOOL_TABLE tool_table[CANON_POCKETS_MAX]; // index is pocket number |
716 |
|
double traverse_rate; // rate for traverse motions |
717 |
|
double orient_offset; // added to M19 R word, from [RS274NGC]ORIENT_OFFSET |
718 |
|
|
719 |
|
/* stuff for subroutines and control structures */ |
720 |
|
int defining_sub; // true if in a subroutine defn |
721 |
|
const char *sub_name; // name of sub we are defining (free this) |
722 |
|
int doing_continue; // true if doing a continue |
723 |
|
int doing_break; // true if doing a break |
724 |
|
int executed_if; // true if executed in current if |
725 |
|
const char *skipping_o; // o_name we are skipping for (or zero) |
726 |
|
const char *skipping_to_sub; // o_name of sub skipping to (or zero) |
727 |
|
int skipping_start; // start of skipping (sequence) |
728 |
|
double test_value; // value for "if", "while", "elseif" |
729 |
|
double return_value; // optional return value for "return", "endsub" |
730 |
|
int value_returned; // the last NGC procedure did/did not return a value |
731 |
|
int call_level; // current subroutine level |
732 |
|
context sub_context[INTERP_SUB_ROUTINE_LEVELS]; |
733 |
|
int call_state; // enum call_states - inidicate Py handler reexecution |
734 |
|
offset_map_type offset_map; // store label x name, file, line |
735 |
|
|
736 |
|
bool adaptive_feed; // adaptive feed is enabled |
737 |
|
bool feed_hold; // feed hold is enabled |
738 |
|
int loggingLevel; // 0 means logging is off |
739 |
|
int debugmask; // from ini EMC/DEBUG |
740 |
|
char log_file[PATH_MAX]; |
741 |
|
char program_prefix[PATH_MAX]; // program directory |
742 |
|
const char *subroutines[MAX_SUB_DIRS]; // subroutines directories |
743 |
|
int use_lazy_close; // wait until next open before closing |
744 |
|
// the input file |
745 |
|
int lazy_closing; // close has been called |
746 |
|
char wizard_root[PATH_MAX]; |
747 |
|
int tool_change_at_g30; |
748 |
|
int tool_change_quill_up; |
749 |
|
int tool_change_with_spindle_on; |
750 |
|
int a_axis_wrapped; |
751 |
|
int b_axis_wrapped; |
752 |
|
int c_axis_wrapped; |
753 |
|
|
754 |
|
int a_indexer_jnum; |
755 |
|
int b_indexer_jnum; |
756 |
|
int c_indexer_jnum; |
757 |
|
|
758 |
|
bool lathe_diameter_mode; //Lathe diameter mode (g07/G08) |
759 |
|
bool mdi_interrupt; |
760 |
|
int feature_set; |
761 |
|
|
762 |
|
int disable_g92_persistence; |
763 |
|
|
764 |
|
#define FEATURE(x) (_setup.feature_set & FEATURE_ ## x) |
765 |
|
#define FEATURE_RETAIN_G43 0x00000001 |
766 |
|
#define FEATURE_OWORD_N_ARGS 0x00000002 |
767 |
|
#define FEATURE_INI_VARS 0x00000004 |
768 |
|
#define FEATURE_HAL_PIN_VARS 0x00000008 |
769 |
|
// do not lowercase named params inside comments - for #<_hal[PinName]> |
770 |
|
#define FEATURE_NO_DOWNCASE_OWORD 0x00000010 |
771 |
|
#define FEATURE_OWORD_WARNONLY 0x00000020 |
772 |
|
|
773 |
|
boost::python::object *pythis; // boost::cref to 'this' |
774 |
|
const char *on_abort_command; |
775 |
|
int_remap_map g_remapped,m_remapped; |
776 |
|
remap_map remaps; |
777 |
|
#define INIT_FUNC "__init__" |
778 |
|
#define DELETE_FUNC "__delete__" |
779 |
|
|
780 |
|
// task calls upon interp.init() repeatedly |
781 |
|
// protect init() operations which are not idempotent |
782 |
|
int init_once; |
783 |
|
}; |
784 |
|
|
785 |
|
typedef setup *setup_pointer; |
786 |
|
// the externally visible singleton instance |
787 |
|
|
788 |
|
extern class PythonPlugin *python_plugin; |
789 |
|
#define PYUSABLE (((python_plugin) != NULL) && (python_plugin->usable())) |
790 |
|
|
791 |
1503 |
inline bool is_a_cycle(int motion) { |
792 |
1503 |
return ((motion > G_80) && (motion < G_90)) || (motion == G_73); |
793 |
|
} |
794 |
|
/* |
795 |
|
|
796 |
|
The _setup model includes a stack array for the names of function |
797 |
|
calls. This stack is written into if an error occurs. Just before each |
798 |
|
function returns an error code, it writes its name in the next |
799 |
|
available string, initializes the following string, and increments |
800 |
|
the array index. The following four macros do the work. |
801 |
|
|
802 |
|
The size of the stack array is 50. An error in the middle of a very |
803 |
|
complex expression would cause the ERP and CHP macros to write past the |
804 |
|
bounds of the array if a check were not provided. No real program |
805 |
|
would contain such a thing, but the check is included to make the |
806 |
|
macros totally crash-proof. If the function call stack is deeper than |
807 |
|
49, the top of the stack will be missing. |
808 |
|
|
809 |
|
*/ |
810 |
|
|
811 |
|
|
812 |
|
// Just set an error string using printf-style formats, do NOT return |
813 |
|
#define ERM(fmt, ...) \ |
814 |
|
do { \ |
815 |
|
setError (fmt, ## __VA_ARGS__); \ |
816 |
|
_setup.stack_index = 0; \ |
817 |
|
strncpy(_setup.stack[_setup.stack_index], __PRETTY_FUNCTION__, STACK_ENTRY_LEN); \ |
818 |
|
_setup.stack[_setup.stack_index][STACK_ENTRY_LEN-1] = 0; \ |
819 |
|
_setup.stack_index++; \ |
820 |
|
_setup.stack[_setup.stack_index][0] = 0; \ |
821 |
|
} while(0) |
822 |
|
|
823 |
|
// Set an error string using printf-style formats and return |
824 |
|
#define ERS(fmt, ...) \ |
825 |
|
do { \ |
826 |
|
setError (fmt, ## __VA_ARGS__); \ |
827 |
|
_setup.stack_index = 0; \ |
828 |
|
strncpy(_setup.stack[_setup.stack_index], __PRETTY_FUNCTION__, STACK_ENTRY_LEN); \ |
829 |
|
_setup.stack[_setup.stack_index][STACK_ENTRY_LEN-1] = 0; \ |
830 |
|
_setup.stack_index++; \ |
831 |
|
_setup.stack[_setup.stack_index][0] = 0; \ |
832 |
|
return INTERP_ERROR; \ |
833 |
|
} while(0) |
834 |
|
|
835 |
|
// Return one of the very few numeric errors |
836 |
|
#define ERN(error_code) \ |
837 |
|
do { \ |
838 |
|
_setup.stack_index = 0; \ |
839 |
|
strncpy(_setup.stack[_setup.stack_index], __PRETTY_FUNCTION__, STACK_ENTRY_LEN); \ |
840 |
|
_setup.stack[_setup.stack_index][STACK_ENTRY_LEN-1] = 0; \ |
841 |
|
_setup.stack_index++; \ |
842 |
|
_setup.stack[_setup.stack_index][0] = 0; \ |
843 |
|
return error_code; \ |
844 |
|
} while(0) |
845 |
|
|
846 |
|
|
847 |
|
// Propagate an error up the stack |
848 |
|
#define ERP(error_code) \ |
849 |
|
do { \ |
850 |
|
if (_setup.stack_index < STACK_LEN - 1) { \ |
851 |
|
strncpy(_setup.stack[_setup.stack_index], __PRETTY_FUNCTION__, STACK_ENTRY_LEN); \ |
852 |
|
_setup.stack[_setup.stack_index][STACK_ENTRY_LEN-1] = 0; \ |
853 |
|
_setup.stack_index++; \ |
854 |
|
_setup.stack[_setup.stack_index][0] = 0; \ |
855 |
|
} \ |
856 |
|
return error_code; \ |
857 |
|
} while(0) |
858 |
|
|
859 |
|
|
860 |
|
// If the condition is true, set an error string as with ERS |
861 |
|
#define CHKS(bad, fmt, ...) \ |
862 |
|
do { \ |
863 |
|
if (bad) { \ |
864 |
|
ERS(fmt, ## __VA_ARGS__); \ |
865 |
|
} \ |
866 |
|
} while(0) |
867 |
|
|
868 |
|
// If the condition is true, return one of the few numeric errors |
869 |
|
#define CHKN(bad, error_code) \ |
870 |
|
do { \ |
871 |
|
if (bad) { \ |
872 |
|
ERN(error_code); \ |
873 |
|
} \ |
874 |
|
} while(0) |
875 |
|
|
876 |
|
|
877 |
|
// Propagate an error up the stack as with ERP if the result of 'call' is not |
878 |
|
// INTERP_OK |
879 |
|
#define CHP(call) \ |
880 |
|
do { \ |
881 |
|
int CHP__status = (call); \ |
882 |
|
if (CHP__status != INTERP_OK) { \ |
883 |
|
ERP(CHP__status); \ |
884 |
|
} \ |
885 |
|
} while(0) |
886 |
|
|
887 |
|
|
888 |
|
// oword warnings |
889 |
|
#define OERR(fmt, ...) \ |
890 |
|
do { \ |
891 |
|
if (FEATURE(OWORD_WARNONLY)) \ |
892 |
|
fprintf(stderr,fmt, ## __VA_ARGS__); \ |
893 |
|
else \ |
894 |
|
ERS(fmt, ## __VA_ARGS__); \ |
895 |
|
} while(0) |
896 |
|
|
897 |
|
|
898 |
|
// |
899 |
|
// The traverse (in the active plane) to the location of the canned cycle |
900 |
|
// is different on the first repeat vs on all the following repeats. |
901 |
|
// |
902 |
|
// The first traverse happens in the CURRENT_CC plane (which was raised to |
903 |
|
// the R plane earlier, if needed), followed by a traverse down to the R |
904 |
|
// plane. |
905 |
|
// |
906 |
|
// All later positioning moves happen in the CLEAR_CC plane, which is |
907 |
|
// either the R plane or the OLD_CC plane depending on G98/G99. |
908 |
|
// |
909 |
|
|
910 |
|
#define CYCLE_MACRO(call) for (repeat = block->l_number; \ |
911 |
|
repeat > 0; \ |
912 |
|
repeat--) \ |
913 |
|
{ \ |
914 |
|
aa = (aa + aa_increment); \ |
915 |
|
bb = (bb + bb_increment); \ |
916 |
|
if(radius_increment) { \ |
917 |
|
double radius, theta; \ |
918 |
|
CHKS((bb == 0 && aa == 0), _("Incremental motion with polar coordinates is indeterminate when at the origin")); \ |
919 |
|
theta = atan2(bb, aa); \ |
920 |
|
radius = hypot(bb, aa) + radius_increment; \ |
921 |
|
aa = radius * cos(theta); \ |
922 |
|
bb = radius * sin(theta); \ |
923 |
|
} \ |
924 |
|
if(theta_increment) { \ |
925 |
|
double radius, theta; \ |
926 |
|
CHKS((bb == 0 && aa == 0), _("Incremental motion with polar coordinates is indeterminate when at the origin")); \ |
927 |
|
theta = atan2(bb, aa) + theta_increment; \ |
928 |
|
radius = hypot(bb, aa); \ |
929 |
|
aa = radius * cos(theta); \ |
930 |
|
bb = radius * sin(theta); \ |
931 |
|
} \ |
932 |
|
if ((repeat == block->l_number) && (current_cc > r)) { \ |
933 |
|
cycle_traverse(block, plane, aa, bb, current_cc); \ |
934 |
|
cycle_traverse(block, plane, aa, bb, r); \ |
935 |
|
} else { \ |
936 |
|
/* we must be at CLEAR_CC already */ \ |
937 |
|
cycle_traverse(block, plane, aa, bb, clear_cc); \ |
938 |
|
if (clear_cc > r) { \ |
939 |
|
cycle_traverse(block, plane, aa, bb, r); \ |
940 |
|
} \ |
941 |
|
} \ |
942 |
|
CHP(call); \ |
943 |
|
} |
944 |
|
|
945 |
|
|
946 |
|
#endif // INTERP_INTERNAL_HH |