1 |
|
/******************************************************************** |
2 |
|
* Description: interp_remap.cc |
3 |
|
* |
4 |
|
* Remapping support |
5 |
|
* |
6 |
|
* Author: Michael Haberler |
7 |
|
* License: GPL Version 2 |
8 |
|
* System: Linux |
9 |
|
* |
10 |
|
* Copyright (c) 2011 All rights reserved. |
11 |
|
* |
12 |
|
********************************************************************/ |
13 |
|
#ifndef _GNU_SOURCE |
14 |
|
#define _GNU_SOURCE |
15 |
|
#endif |
16 |
|
#include "python_plugin.hh" |
17 |
|
#include "interp_python.hh" |
18 |
|
#include <boost/python/list.hpp> |
19 |
|
namespace bp = boost::python; |
20 |
|
|
21 |
|
#include <unistd.h> |
22 |
|
#include <stdio.h> |
23 |
|
#include <stdlib.h> |
24 |
|
#include <string.h> |
25 |
|
#include <ctype.h> |
26 |
|
#include <sys/types.h> |
27 |
|
#include <sys/stat.h> |
28 |
|
#include "rs274ngc.hh" |
29 |
|
#include "rs274ngc_return.hh" |
30 |
|
#include "rs274ngc_interp.hh" |
31 |
|
#include "interp_internal.hh" |
32 |
|
|
33 |
|
|
34 |
|
|
35 |
6553 |
bool Interp::has_user_mcode(setup_pointer settings,block_pointer block) |
36 |
|
{ |
37 |
|
unsigned i; |
38 |
78636 |
for(i = 0; i < sizeof(block->m_modes)/sizeof(int); i++) { |
39 |
72083 |
if (block->m_modes[i] == -1) |
40 |
|
continue; |
41 |
78 |
if (M_REMAPPABLE(block->m_modes[i]) && |
42 |
11 |
settings->m_remapped[block->m_modes[i]]) |
43 |
|
return true; |
44 |
|
} |
45 |
|
return false; |
46 |
|
} |
47 |
|
|
48 |
|
bool Interp::remap_in_progress(const char *code) |
49 |
|
{ |
50 |
|
remap_pointer rp = remapping(code); |
51 |
|
if (rp == NULL) |
52 |
|
return false; |
53 |
|
for (int i = _setup.remap_level; i > 0; i--) { |
54 |
|
if (_setup.blocks[i].executing_remap == rp) { |
55 |
|
// printf("---------------- remap_in_progress(%s): TRUE level=%d\n",code,i); |
56 |
|
return true; |
57 |
|
} |
58 |
|
} |
59 |
|
// printf("---------------- remap_in_progress(%s): FALSE\n",code); |
60 |
|
return false; |
61 |
|
} |
62 |
|
|
63 |
|
|
64 |
|
int Interp::convert_remapped_code(block_pointer block, |
65 |
|
setup_pointer settings, |
66 |
|
int phase, |
67 |
|
char letter, |
68 |
|
int number) |
69 |
|
{ |
70 |
|
remap_pointer remap; |
71 |
|
char key[2]; |
72 |
|
int status; |
73 |
|
block_pointer cblock; |
74 |
|
bp::list plist; |
75 |
|
char cmd[LINELEN]; |
76 |
|
|
77 |
|
if (number == -1) |
78 |
|
logRemap("convert_remapped_code '%c'", letter); |
79 |
|
else |
80 |
|
logRemap("convert_remapped_code '%c%d'", letter, number); |
81 |
|
|
82 |
|
switch (toupper(letter)) { |
83 |
|
case 'M': |
84 |
|
remap = settings->m_remapped[number]; |
85 |
|
break; |
86 |
|
case 'G': |
87 |
|
remap = settings->g_remapped[number]; |
88 |
|
break; |
89 |
|
default: |
90 |
|
key[0] = letter; |
91 |
|
key[1] = '\0'; |
92 |
|
remap = remapping((const char *)key); |
93 |
|
} |
94 |
|
CHKS((remap == NULL), "BUG: convert_remapped_code: no remapping"); |
95 |
|
|
96 |
|
// remapped handlers may use Python code to |
97 |
|
// setup environment before, and finish work after doing theirs. |
98 |
|
// That's what prolog and epilog functions are for. |
99 |
|
// These are described in the remap descriptor as read from ini. |
100 |
|
|
101 |
|
// Since a remap is always executed in the context of a controlling block, |
102 |
|
// this block now contains fields which hold dynamic remap information, like |
103 |
|
// the breadcrumbs execution trail. |
104 |
|
// Some of these fields are initialized here - |
105 |
|
// conceptually the block stack is also a 'remap frame stack'. |
106 |
|
|
107 |
|
// the O_call code will pick up the static descriptor and |
108 |
|
// dynamic information through the block and call any prolog |
109 |
|
// function before passing control to the actual handler procedure. |
110 |
|
|
111 |
|
// On the corresponding O_endsub/O_return, any epilog function |
112 |
|
// will be executed, doing any work not doable in an NGC file. |
113 |
|
|
114 |
|
// Note that even Python-remapped execution is pulled through the |
115 |
|
// oword mechanism - so no duplication of handler calling code |
116 |
|
// is needed. |
117 |
|
|
118 |
|
snprintf(cmd, sizeof(cmd),"O <%s> call ", REMAP_FUNC(remap)); |
119 |
|
|
120 |
|
// the controlling block holds all dynamic remap information. |
121 |
|
cblock = &CONTROLLING_BLOCK(*settings); |
122 |
|
cblock->executing_remap = remap; // the current descriptor |
123 |
|
cblock->param_cnt = 0; |
124 |
|
|
125 |
|
if (remap->argspec && (strchr(remap->argspec, '@') != NULL)) { |
126 |
|
// append a positional argument list instead of local variables |
127 |
|
// if user specified '@' |
128 |
|
// named local params are dealt with in execute_call() when |
129 |
|
// the new call frame is fully established |
130 |
|
CHP(add_parameters(settings, cblock, &cmd[strlen(cmd)])); |
131 |
|
} |
132 |
|
|
133 |
|
if ((_setup.debugmask & EMC_DEBUG_REMAP) && |
134 |
|
(_setup.loggingLevel > 2)) { |
135 |
|
logRemap("convert_remapped_code(%s)", cmd); |
136 |
|
} |
137 |
|
|
138 |
|
// good to go, pass to o-word call handling mechanism |
139 |
|
status = read(cmd); |
140 |
|
block_pointer eblock = &EXECUTING_BLOCK(*settings); |
141 |
|
eblock->call_type = CT_REMAP; |
142 |
|
CHKS(status != INTERP_OK, |
143 |
|
"convert_remapped_code: inital read returned %s", |
144 |
|
interp_status(status)); |
145 |
|
return(- phase); |
146 |
|
} |
147 |
|
|
148 |
|
|
149 |
|
// add_parameters - a built-in prolog function |
150 |
|
// |
151 |
|
// handles argspec and extracts required and optional items from the |
152 |
|
// controlling block. |
153 |
|
// |
154 |
|
// if preparing for an NGC file, add local variables to |
155 |
|
// the current oword subroutine call frame |
156 |
|
// |
157 |
|
// if posargs == NULL: |
158 |
|
// add the named parameters as local variables to the current call frame |
159 |
|
// if posargs != NULL: |
160 |
|
// create a positional argument list as per argspec order |
161 |
|
// instead of adding local variables |
162 |
|
// |
163 |
|
// also, generate a kwargs style dictionary of required and optional items |
164 |
|
// in case a Python prolog is called |
165 |
|
// |
166 |
|
// 1. add all requried and present optional words. |
167 |
|
// 2. error on missing but required words. |
168 |
|
// 4. handle '>' as to require a positive feed. |
169 |
|
// 5. handle '^' as to require a positive speed. |
170 |
|
// 6. handle 'N' as to add the line number. |
171 |
|
// |
172 |
|
// return INTERP_ERROR and propagate appropriate message if any errors so far |
173 |
|
// else return INTERP_OK |
174 |
|
// |
175 |
|
// handling '@' (positional params) is dealt with in the calling procedure |
176 |
|
|
177 |
|
int Interp::add_parameters(setup_pointer settings, |
178 |
|
block_pointer cblock, |
179 |
|
char *posarglist) |
180 |
|
{ |
181 |
|
const char *s,*argspec, *code; |
182 |
|
block_pointer block; |
183 |
|
char missing[30],optional[30],required[30]; |
184 |
|
char *m = missing; |
185 |
|
char *o = optional; |
186 |
|
char *r = required; |
187 |
|
char msg[LINELEN], tail[LINELEN]; |
188 |
|
bool errored = false; |
189 |
|
remap_pointer rptr = cblock->executing_remap; |
190 |
|
context_pointer active_frame = &settings->sub_context[settings->call_level]; |
191 |
|
|
192 |
|
if (!rptr) { |
193 |
|
ERS("BUG: add_parameters: remap_frame: executing_remap == NULL "); |
194 |
|
} |
195 |
|
code = rptr->name; |
196 |
|
|
197 |
|
// if any Python handlers are present, create a kwargs dict |
198 |
|
bool pydict = rptr->remap_py || rptr->prolog_func || rptr->epilog_func; |
199 |
|
|
200 |
|
std::fill(missing, std::end(missing), 0); |
201 |
|
std::fill(optional, std::end(optional), 0); |
202 |
|
std::fill(required, std::end(required), 0); |
203 |
|
std::fill(msg, std::end(msg), 0); |
204 |
|
std::fill(tail, std::end(tail), 0); |
205 |
|
|
206 |
|
s = argspec = rptr->argspec; |
207 |
|
CHKS((argspec == NULL),"BUG: add_parameters: argspec = NULL"); |
208 |
|
|
209 |
|
while (*s) { |
210 |
|
if (isupper(*s) && !strchr(required,*s)) *r++ = tolower(*s); |
211 |
|
if (islower(*s) && !strchr(optional,*s)) *o++ = *s; |
212 |
|
if (strchr(">^Nn",*s) && !strchr(required,*s)) *r++ = *s; |
213 |
|
s++; |
214 |
|
} |
215 |
|
block = &CONTROLLING_BLOCK((*settings)); |
216 |
|
|
217 |
|
logNP("add_parameters code=%s argspec=%s call_level=%d r=%s o=%s pydict=%d\n", |
218 |
|
code,argspec,settings->call_level,required,optional,pydict); |
219 |
|
|
220 |
|
#define STORE(name,value) \ |
221 |
|
if (pydict) { \ |
222 |
|
try { \ |
223 |
|
active_frame->pystuff.impl->kwargs[name] = value; \ |
224 |
|
} \ |
225 |
|
catch (bp::error_already_set) { \ |
226 |
|
PyErr_Print(); \ |
227 |
|
PyErr_Clear(); \ |
228 |
|
ERS("add_parameters: cant add '%s' to args",name); \ |
229 |
|
} \ |
230 |
|
} \ |
231 |
|
if (posarglist) { \ |
232 |
|
char actual[LINELEN]; \ |
233 |
|
snprintf(actual, sizeof(actual),"[%.4lf]", value); \ |
234 |
|
strcat(posarglist, actual); \ |
235 |
|
cblock->param_cnt++; \ |
236 |
|
} else { \ |
237 |
|
add_named_param(name,0); \ |
238 |
|
store_named_param(settings,name,value,0); \ |
239 |
|
} |
240 |
|
|
241 |
|
|
242 |
|
#define PARAM(spec,name,flag,value) \ |
243 |
|
if ((flag)) { /* present */ \ |
244 |
|
/* required or optional */ \ |
245 |
|
if (strchr(required,spec) || strchr(optional,spec)) { \ |
246 |
|
STORE(name,value); \ |
247 |
|
} \ |
248 |
|
} else { \ |
249 |
|
if (strchr(required,spec)) { /* missing */ \ |
250 |
|
*m++ = spec; \ |
251 |
|
errored = true; \ |
252 |
|
} \ |
253 |
|
} |
254 |
|
|
255 |
|
s = rptr->argspec; |
256 |
|
// step through argspec in order so positional args are built |
257 |
|
// in the correct order |
258 |
|
while (*s) { |
259 |
|
switch (tolower(*s)) { |
260 |
|
case 'a' : PARAM('a',"a",block->a_flag,block->a_number); break; |
261 |
|
case 'b' : PARAM('b',"b",block->b_flag,block->b_number); break; |
262 |
|
case 'c' : PARAM('c',"c",block->c_flag,block->c_number); break; |
263 |
|
case 'd' : PARAM('d',"d",block->d_flag,block->d_number_float); break; |
264 |
|
case 'e' : PARAM('e',"e",block->e_flag,block->e_number); break; |
265 |
|
case 'f' : PARAM('f',"f",block->f_flag,block->f_number); break; |
266 |
|
case 'h' : PARAM('h',"h",block->h_flag,(double) block->h_number); break; |
267 |
|
case 'i' : PARAM('i',"i",block->i_flag,block->i_number); break; |
268 |
|
case 'j' : PARAM('j',"j",block->j_flag,block->j_number); break; |
269 |
|
case 'k' : PARAM('k',"k",block->k_flag,block->k_number); break; |
270 |
|
case 'l' : PARAM('l',"l",block->l_flag,(double) block->l_number); break; |
271 |
|
case 'p' : PARAM('p',"p",block->p_flag,block->p_number); break; |
272 |
|
case 'q' : PARAM('q',"q",block->q_flag,block->q_number); break; |
273 |
|
case 'r' : PARAM('r',"r",block->r_flag,block->r_number); break; |
274 |
|
case 's' : PARAM('s',"s",block->s_flag,block->s_number); break; |
275 |
|
case 't' : PARAM('t',"t",block->t_flag, (double) block->t_number); break; |
276 |
|
case 'u' : PARAM('u',"u",block->u_flag,block->u_number); break; |
277 |
|
case 'v' : PARAM('v',"v",block->v_flag,block->v_number); break; |
278 |
|
case 'w' : PARAM('w',"w",block->w_flag,block->w_number); break; |
279 |
|
case 'x' : PARAM('x',"x",block->x_flag,block->x_number); break; |
280 |
|
case 'y' : PARAM('y',"y",block->y_flag,block->y_number); break; |
281 |
|
case 'z' : PARAM('z',"z",block->z_flag,block->z_number); break; |
282 |
|
case '-' : break; // ignore - backwards compatibility |
283 |
|
default: ; |
284 |
|
} |
285 |
|
s++; |
286 |
|
} |
287 |
|
|
288 |
|
s = missing; |
289 |
|
if (*s) { |
290 |
|
strcat(tail," missing: "); |
291 |
|
} |
292 |
|
while (*s) { |
293 |
|
errored = true; |
294 |
|
char c = toupper(*s); |
295 |
|
strncat(tail,&c,1); |
296 |
|
if (*(s+1)) strcat(tail,","); |
297 |
|
s++; |
298 |
|
} |
299 |
|
// special cases: |
300 |
|
// N...add line number |
301 |
|
if (strchr(required,'n') || strchr(required,'N')) { |
302 |
|
STORE("n",(double) cblock->saved_line_number); |
303 |
|
} |
304 |
|
|
305 |
|
// >...require positive feed |
306 |
|
if (strchr(required,'>')) { |
307 |
|
if (settings->feed_rate > 0.0) { |
308 |
|
STORE("f",settings->feed_rate); |
309 |
|
} else { |
310 |
|
strcat(tail,"F>0,"); |
311 |
|
errored = true; |
312 |
|
} |
313 |
|
} |
314 |
|
// ^...require positive speed |
315 |
|
if (strchr(required,'^')) { |
316 |
|
if (settings->speed > 0.0) { |
317 |
|
STORE("s",settings->speed); |
318 |
|
} else { |
319 |
|
strcat(tail,"S>0,"); |
320 |
|
errored = true; |
321 |
|
} |
322 |
|
} |
323 |
|
|
324 |
|
if (errored) { |
325 |
|
ERS("user-defined %s:%s", |
326 |
|
code, tail); |
327 |
|
} |
328 |
|
return INTERP_OK; |
329 |
|
} |
330 |
|
|
331 |
|
|
332 |
|
// this looks up a remapping by unnormalized code (like G88.1) |
333 |
600 |
remap_pointer Interp::remapping(const char *code) |
334 |
|
{ |
335 |
1200 |
remap_iterator n = _setup.remaps.find(code); |
336 |
1200 |
if (n != _setup.remaps.end()) |
337 |
|
return &n->second; |
338 |
|
else |
339 |
|
return NULL; |
340 |
|
} |
341 |
|
|
342 |
|
// parse options of the form: |
343 |
|
// REMAP= M420 modalgroup=6 argspec=pq prolog=setnamedvars ngc=m43.ngc epilog=ignore_retvalue |
344 |
|
// REMAP= M421 modalgroup=6 argspec=- prolog=setnamedvars python=m43func epilog=ignore_retvalue |
345 |
|
|
346 |
|
int Interp::parse_remap(const char *inistring, int lineno) |
347 |
|
{ |
348 |
|
|
349 |
|
char iniline[LINELEN]; |
350 |
|
char *argv[MAX_REMAPOPTS]; |
351 |
|
int argc = 0; |
352 |
|
const char *code; |
353 |
|
remap r; |
354 |
|
bool errored = false; |
355 |
|
int g1 = 0, g2 = 0; |
356 |
|
int mcode = -1; |
357 |
|
int gcode = -1; |
358 |
|
char *s; |
359 |
|
|
360 |
|
memset((void *)&r, 0, sizeof(remap)); |
361 |
|
r.modal_group = -1; // mark as unset, required param for m/g |
362 |
|
r.motion_code = INT_MIN; |
363 |
|
strcpy(iniline, inistring); |
364 |
|
// strip trailing comments |
365 |
|
if ((s = strchr(iniline, '#')) != NULL) { |
366 |
|
*s = '\0'; |
367 |
|
} |
368 |
|
s = strtok((char *) iniline, " \t"); |
369 |
|
|
370 |
|
while( s != NULL && argc < MAX_REMAPOPTS - 1) { |
371 |
|
argv[argc++] = s; |
372 |
|
s = strtok( NULL, " \t" ); |
373 |
|
} |
374 |
|
if (argc == MAX_REMAPOPTS) { |
375 |
|
Error("parse_remap: too many arguments (max %d)", MAX_REMAPOPTS); |
376 |
|
goto fail; |
377 |
|
} |
378 |
|
argv[argc] = NULL; |
379 |
|
code = strstore(argv[0]); |
380 |
|
r.name = code; |
381 |
|
|
382 |
|
for (int i = 1; i < argc; i++) { |
383 |
|
int kwlen = 0; |
384 |
|
char *kw = argv[i]; |
385 |
|
char *arg = strchr(argv[i],'='); |
386 |
|
if (arg != NULL) { |
387 |
|
kwlen = arg - argv[i]; |
388 |
|
arg++; |
389 |
|
if (!strlen(arg)) { // 'kw=' |
390 |
|
Error("option '%s' - zero length value: %d:REMAP = %s", |
391 |
|
kw,lineno,inistring); |
392 |
|
errored = true; |
393 |
|
continue; |
394 |
|
} |
395 |
|
} else { // 'kw' |
396 |
|
Error("option '%s' - missing '=<value>: %d:REMAP = %s", |
397 |
|
kw,lineno,inistring); |
398 |
|
errored = true; |
399 |
|
continue;; |
400 |
|
} |
401 |
|
if (!strncasecmp(kw,"modalgroup",kwlen)) { |
402 |
|
r.modal_group = atoi(arg); |
403 |
|
continue; |
404 |
|
} |
405 |
|
if (!strncasecmp(kw,"argspec",kwlen)) { |
406 |
|
size_t pos = strspn (arg, |
407 |
|
"ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijklmnpqrstuvwxyz>^@"); |
408 |
|
if (pos != strlen(arg)) { |
409 |
|
Error("argspec: illegal word '%c' - %d:REMAP = %s", |
410 |
|
arg[pos],lineno,inistring); |
411 |
|
errored = true; |
412 |
|
continue; |
413 |
|
} |
414 |
|
r.argspec = strstore(arg); |
415 |
|
continue; |
416 |
|
} |
417 |
|
if (!strncasecmp(kw,"prolog",kwlen)) { |
418 |
|
if (PYUSABLE) { |
419 |
|
r.prolog_func = strstore(arg); |
420 |
|
} else { |
421 |
|
Error("Python plugin required for prolog=, but not available: %d:REMAP = %s", |
422 |
|
lineno,inistring); |
423 |
|
errored = true; |
424 |
|
continue; |
425 |
|
} |
426 |
|
continue; |
427 |
|
} |
428 |
|
if (!strncasecmp(kw,"epilog",kwlen)) { |
429 |
|
if (PYUSABLE) { |
430 |
|
r.epilog_func = strstore(arg); |
431 |
|
} else { |
432 |
|
Error("Python plugin required for epilog=, but not available: %d:REMAP = %s", |
433 |
|
lineno,inistring); |
434 |
|
errored = true; |
435 |
|
continue; |
436 |
|
} |
437 |
|
continue; |
438 |
|
} |
439 |
|
if (!strncasecmp(kw,"ngc",kwlen)) { |
440 |
|
if (r.remap_py) { |
441 |
|
Error("cant remap to an ngc file and a Python function: - %d:REMAP = %s", |
442 |
|
lineno,inistring); |
443 |
|
errored = true; |
444 |
|
continue; |
445 |
|
} |
446 |
|
FILE *fp = find_ngc_file(&_setup,arg); |
447 |
|
if (fp) { |
448 |
|
r.remap_ngc = strstore(arg); |
449 |
|
fclose(fp); |
450 |
|
} else { |
451 |
|
Error("NGC file not found: ngc=%s - %d:REMAP = %s", |
452 |
|
arg, lineno,inistring); |
453 |
|
errored = true; |
454 |
|
} |
455 |
|
continue; |
456 |
|
} |
457 |
|
if (!strncasecmp(kw,"python",kwlen)) { |
458 |
|
if (r.remap_ngc ) { |
459 |
|
Error("cant remap to an ngc file and a Python function: - %d:REMAP = %s", |
460 |
|
lineno,inistring); |
461 |
|
errored = true; |
462 |
|
continue; |
463 |
|
} |
464 |
|
if (!PYUSABLE) { |
465 |
|
Error("Python plugin required for python=, but not available: %d:REMAP = %s", |
466 |
|
lineno,inistring); |
467 |
|
errored = true; |
468 |
|
continue; |
469 |
|
} |
470 |
|
if (!is_pycallable(&_setup, REMAP_MODULE, arg)) { |
471 |
|
Error("'%s' is not a Python callable function - %d:REMAP = %s", |
472 |
|
arg,lineno,inistring); |
473 |
|
errored = true; |
474 |
|
continue; |
475 |
|
} |
476 |
|
r.remap_py = strstore(arg); |
477 |
|
continue; |
478 |
|
} |
479 |
|
Error("unrecognized option '%*s' in %d:REMAP = %s", |
480 |
|
kwlen,kw,lineno,inistring); |
481 |
|
} |
482 |
|
if (errored) { |
483 |
|
goto fail; |
484 |
|
} |
485 |
|
|
486 |
|
if (remapping(code)) { |
487 |
|
Error("code '%s' already remapped : %d:REMAP = %s", |
488 |
|
code,lineno,inistring); |
489 |
|
goto fail; |
490 |
|
} |
491 |
|
|
492 |
|
// it is an error not to define a remap function to call. |
493 |
|
if ((r.remap_ngc == NULL) && (r.remap_py == NULL)) { |
494 |
|
Error("code '%s' - no remap function given, use either 'python=<function>' or 'ngc=<basename>' : %d:REMAP = %s", |
495 |
|
code,lineno,inistring); |
496 |
|
goto fail; |
497 |
|
} |
498 |
|
|
499 |
|
#define CHECK(bad, fmt, ...) \ |
500 |
|
do { \ |
501 |
|
if (bad) { \ |
502 |
|
Log(fmt, ## __VA_ARGS__); \ |
503 |
|
goto fail; \ |
504 |
|
} \ |
505 |
|
} while(0) |
506 |
|
|
507 |
|
switch (towlower(*code)) { |
508 |
|
|
509 |
|
case 't': |
510 |
|
case 's': |
511 |
|
case 'f': |
512 |
|
CHECK((strlen(code) > 1),"%d: %c remap - only single letter code allowed", lineno, *code); |
513 |
|
CHECK((r.modal_group != -1), "%d: %c remap - modal group setting ignored - fixed sequencing", lineno, *code); |
514 |
|
_setup.remaps[code] = r; |
515 |
|
break; |
516 |
|
|
517 |
|
case 'm': |
518 |
|
if (sscanf(code + 1, "%d", &mcode) == 1) { |
519 |
|
_setup.remaps[code] = r; |
520 |
|
_setup.m_remapped[mcode] = &_setup.remaps[code]; |
521 |
|
} else { |
522 |
|
Error("parsing M-code: expecting integer like 'M420', got '%s' : %d:REMAP = %s", |
523 |
|
code,lineno,inistring); |
524 |
|
goto fail; |
525 |
|
} |
526 |
|
if (r.modal_group == -1) { |
527 |
|
Error("warning: code '%s' : no modalgroup=<int> given, using default group %d : %d:REMAP = %s", |
528 |
|
code, MCODE_DEFAULT_MODAL_GROUP,lineno,inistring); |
529 |
|
r.modal_group = MCODE_DEFAULT_MODAL_GROUP; |
530 |
|
} |
531 |
|
if (!M_MODE_OK(r.modal_group)) { |
532 |
|
Error("error: code '%s' : invalid modalgroup=<int> given (currently valid: 4..10) : %d:REMAP = %s", |
533 |
|
code,lineno,inistring); |
534 |
|
goto fail; |
535 |
|
} |
536 |
|
break; |
537 |
|
case 'g': |
538 |
|
|
539 |
|
// code may be G88.1 or so - normalize to use 'G881' instead |
540 |
|
// (multiply by 10, no dots) |
541 |
|
if (sscanf(code + 1, "%d.%d", &g1, &g2) == 2) { |
542 |
|
gcode = g1 * 10 + g2; |
543 |
|
} |
544 |
|
if ( gcode == -1) { |
545 |
|
if (sscanf(code + 1, "%d", &gcode) != 1) { |
546 |
|
Error("code '%s' : cant parse G-code : %d:REMAP = %s", |
547 |
|
code, lineno, inistring); |
548 |
|
goto fail; |
549 |
|
} |
550 |
|
gcode *= 10; |
551 |
|
} |
552 |
|
r.motion_code = gcode; |
553 |
|
if (r.modal_group == -1) { |
554 |
|
Error("warning: code '%s' : no modalgroup=<int> given, using default group %d : %d:REMAP = %s", |
555 |
|
code, GCODE_DEFAULT_MODAL_GROUP, lineno, inistring); |
556 |
|
r.modal_group = GCODE_DEFAULT_MODAL_GROUP; |
557 |
|
break; |
558 |
|
} |
559 |
|
if (!G_MODE_OK(r.modal_group)) { |
560 |
|
Error("error: code '%s' : %s modalgroup=<int> given : %d:REMAP = %s", |
561 |
|
argv[0], |
562 |
|
r.modal_group == -1 ? "no" : "invalid", |
563 |
|
lineno, |
564 |
|
inistring); |
565 |
|
goto fail; |
566 |
|
} |
567 |
|
_setup.remaps[code] = r; |
568 |
|
_setup.g_remapped[gcode] = &_setup.remaps[code]; |
569 |
|
break; |
570 |
|
|
571 |
|
default: |
572 |
|
// make sure the python plugin is in a usable state if needed |
573 |
|
if ((r.prolog_func || r.remap_py || r.epilog_func) && |
574 |
|
(!PYUSABLE)) { |
575 |
|
fprintf(stderr, "fatal: REMAP requires the Python plugin, which did not initialize\n"); |
576 |
|
break; |
577 |
|
} |
578 |
|
Log("REMAP BUG=%s %d:REMAP = %s", |
579 |
|
code,lineno,inistring); |
580 |
|
} |
581 |
|
return INTERP_OK; |
582 |
|
|
583 |
|
fail: |
584 |
|
return INTERP_ERROR; |
585 |
207 |
} |