summaryrefslogtreecommitdiff
path: root/src/emc/rs274ngc/interp_check.cc
blob: 46c6b0f8ede0cabb30ffed5c0606cd73f3924206 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
/********************************************************************
* Description: interp_check.cc
*
*   Derived from a work by Thomas Kramer
*
* Author:
* License: GPL Version 2
* System: Linux
*    
* Copyright (c) 2004 All rights reserved.
*
* Last change:
********************************************************************/
#include <boost/python.hpp>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rs274ngc.hh"
#include "rs274ngc_return.hh"
#include "interp_internal.hh"
#include "rs274ngc_interp.hh"

/****************************************************************************/

/*! check_g_codes

Returned Value: int
   If any of the following errors occur, this returns the error shown.
   Otherwise, it returns INTERP_OK.
   1. NCE_DWELL_TIME_MISSING_WITH_G4
   2. NCE_MUST_USE_G0_OR_G1_WITH_G53
   3. NCE_CANNOT_USE_G53_INCREMENTAL
   4. NCE_LINE_WITH_G10_DOES_NOT_HAVE_L2
   5. NCE_P_VALUE_NOT_AN_INTEGER_WITH_G10_L2
   6. NCE_P_VALUE_OUT_OF_RANGE_WITH_G10_L2
   7. NCE_BUG_BAD_G_CODE_MODAL_GROUP_0

Side effects: none

Called by: check_items

This runs checks on g_codes from a block of RS274/NGC instructions.
Currently, all checks are on g_codes in modal group 0.

The read_g function checks for errors which would foul up the reading.
The enhance_block function checks for logical errors in the use of
axis values by g-codes in modal groups 0 and 1.
This function checks for additional logical errors in g_codes.

[Fanuc, page 45, note 4] says there is no maximum for how many g_codes
may be put on the same line, [NCMS] says nothing one way or the other,
so the test for that is not used.

We are suspending any implicit motion g_code when a g_code from our
group 0 is used.  The implicit motion g_code takes effect again
automatically after the line on which the group 0 g_code occurs.  It
is not clear what the intent of [Fanuc] is in this regard. The
alternative is to require that any implicit motion be explicitly
cancelled.

Not all checks on g_codes are included here. Those checks that are
sensitive to whether other g_codes on the same line have been executed
yet are made by the functions called by convert_g.

Our reference sources differ regarding what codes may be used for
dwell time.  [Fanuc, page 58] says use "p" or "x". [NCMS, page 23] says
use "p", "x", or "u". We are allowing "p" only, since it is consistent
with both sources and "x" would be confusing. However, "p" is also used
with G10, where it must be an integer, so reading "p" values is a bit
more trouble than would be nice.

*/

int Interp::check_g_codes(block_pointer block,   //!< pointer to a block to be checked
                         setup_pointer settings)        //!< pointer to machine settings
{
  int mode0, mode1;
  int p_int;

  mode0 = block->g_modes[0];
  mode1 = block->g_modes[1];
  if (mode0 == -1) {
  } else if (mode0 == G_4) {
    CHKS((block->p_number == -1.0), NCE_DWELL_TIME_MISSING_WITH_G4);
    CHKS((mode1 == G_2 || mode1 == G_3), _("G4 not allowed with G2 or G3 because they both use P"));
  } else if (mode0 == G_10) {
    (block->p_number >= 0) ? p_int = (int) (block->p_number +0.5) :p_int = (int) (block->p_number -0.5);
    CHKS((block->l_number != 2 && block->l_number != 1 && block->l_number != 20 && block->l_number != 10 && block->l_number != 11), _("Line with G10 does not have L1, L10, L11, L2, or L20"));
    CHKS((((block->p_number + 0.0001) - p_int) > 0.0002),  _("P value not an integer with G10"));
    CHKS((((block->l_number == 2 || block->l_number == 20) && ((p_int < 0) || (p_int > 9)))), _("P value out of range (0-9) with G10 L%d"), block->l_number);
    CHKS((((block->l_number == 1 || block->l_number == 10 || block->l_number == 11) && p_int < 1)), _("P value out of range with G10 L%d"), block->l_number);
  } else if (mode0 == G_28) {
  } else if (mode0 == G_30) {
  } else if (mode0 == G_5_3) { 
      CHKS(((mode1 != G_5_2) && (mode1 != -1)), _("Between G5.2 and G5.3 codes, only additional G5.2 codes are allowed."));
  } else if (mode1 == G_5_2){
  } else if (mode0 == G_28_1 || mode0 == G_30_1) {
  } else if (mode0 == G_53) {
    CHKS(((block->motion_to_be != G_0) && (block->motion_to_be != G_1)),
        NCE_MUST_USE_G0_OR_G1_WITH_G53);
    CHKS(((block->g_modes[3] == G_91) ||
         ((block->g_modes[3] != G_90) &&
          (settings->distance_mode == MODE_INCREMENTAL))),
        NCE_CANNOT_USE_G53_INCREMENTAL);
  } else if (mode0 == G_92) {
  } else if ((mode0 == G_92_1) || (mode0 == G_92_2) || (mode0 == G_92_3)) {
  } else
    ERS(NCE_BUG_BAD_G_CODE_MODAL_GROUP_0);
  return INTERP_OK;
}

/****************************************************************************/

/*! check_items

Returned Value: int
   If any one of check_g_codes, check_m_codes, and check_other_codes
   returns an error code, this returns that code.
   Otherwise, it returns INTERP_OK.

Side effects: none

Called by: parse_line

This runs checks on a block of RS274 code.

The functions named read_XXXX check for errors which would foul up the
reading. This function checks for additional logical errors.

A block has an array of g_codes, which are initialized to -1
(meaning no code). This calls check_g_codes to check the g_codes.

A block has an array of m_codes, which are initialized to -1
(meaning no code). This calls check_m_codes to check the m_codes.

Items in the block which are not m or g codes are checked by
check_other_codes.

*/

int Interp::check_items(block_pointer block,     //!< pointer to a block to be checked
                       setup_pointer settings)  //!< pointer to machine settings
{

  CHP(check_g_codes(block, settings));
  CHP(check_m_codes(block));
  CHP(check_other_codes(block));
  return INTERP_OK;
}

/****************************************************************************/

/*! check_m_codes

Returned Value: int
   If any of the following errors occur, this returns the error code shown.
   Otherwise, it returns INTERP_OK.
   1. There are too many m codes in the block: NCE_TOO_MANY_M_CODES_ON_LINE

Side effects: none

Called by: check_items

This runs checks on m_codes from a block of RS274/NGC instructions.

The read_m function checks for errors which would foul up the
reading. This function checks for additional errors in m_codes.

*/

int Interp::check_m_codes(block_pointer block)   //!< pointer to a block to be checked
{

  CHKS((block->m_count > MAX_EMS), NCE_TOO_MANY_M_CODES_ON_LINE);
  return INTERP_OK;
}

/****************************************************************************/

/*! check_other_codes

Returned Value: int
   If any of the following errors occur, this returns the error code shown.
   Otherwise, it returns INTERP_OK.
   1. An A-axis value is given with a canned cycle (g80 to g89):
      NCE_CANNOT_PUT_AN_A_IN_CANNED_CYCLE
   2. A B-axis value is given with a canned cycle (g80 to g89):
      NCE_CANNOT_PUT_A_B_IN_CANNED_CYCLE
   3. A C-axis value is given with a canned cycle (g80 to g89):
      NCE_CANNOT_PUT_A_C_IN_CANNED_CYCLE
   4. A d word is in a block with no cutter_radius_compensation_on command:
      NCE_D_WORD_WITH_NO_G41_OR_G42
   5. An h_number is in a block with no tool length offset setting:
      NCE_H_WORD_WITH_NO_G43
   6. An i_number is in a block with no G code that uses it:
      NCE_I_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT
   7. A j_number is in a block with no G code that uses it:
      NCE_J_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT
   8. A k_number is in a block with no G code that uses it:
      NCE_K_WORD_WITH_NO_G2_OR_G3_OR_G87_TO_USE_IT
   9. A l_number is in a block with no G code that uses it:
      NCE_L_WORD_WITH_NO_CANNED_CYCLE_OR_G10
  10. A p_number is in a block with no G code that uses it:
      NCE_P_WORD_WITH_NO_G4_G10_G64_G82_G86_G88_G89
  11. A q_number is in a block with no G code that uses it:
      NCE_Q_WORD_WITH_NO_G83_OR_M66
  12. An r_number is in a block with no G code that uses it:
      NCE_R_WORD_WITH_NO_G_CODE_THAT_USES_IT
  13. A k word is missing from a G33 block:
      NCE_K_WORD_MISSING_WITH_G33
  14. An e word is in a block with no G76 or M66 to use it:
      NCE_E_WORD_WITH_NO_G76_OR_M66_TO_USE_IT

Side effects: none

Called by: check_items

This runs checks on codes from a block of RS274/NGC code which are
not m or g codes.

The functions named read_XXXX check for errors which would foul up the
reading. This function checks for additional logical errors in codes.

*/

int Interp::check_other_codes(block_pointer block)       //!< pointer to a block of RS274/NGC instructions
{
  int motion;

  motion = block->motion_to_be;

  // bypass ALL checks, argspec takes care of that
  if (IS_USER_GCODE(motion)) {
      return INTERP_OK;
  }
  // bypass ALL checks, argspec takes care of that
  if (has_user_mcode(&(_setup),block)) {
      return INTERP_OK;
    }
  if (block->a_flag) {
    CHKS(is_a_cycle(motion), NCE_CANNOT_PUT_AN_A_IN_CANNED_CYCLE);
  }
  if (block->b_flag) {
    CHKS(is_a_cycle(motion), NCE_CANNOT_PUT_A_B_IN_CANNED_CYCLE);
  }
  if (block->c_flag) {
    CHKS(is_a_cycle(motion), NCE_CANNOT_PUT_A_C_IN_CANNED_CYCLE);
  }
  if (block->d_flag) {
    CHKS(((block->g_modes[7] != G_41) && (block->g_modes[7] != G_42) &&
        (block->g_modes[7] != G_41_1) && (block->g_modes[7] != G_42_1) &&
	(block->g_modes[14] != G_96)),
        _("D word with no G41, G41.1, G42, G42.1, or G96 to use it"));
  }

  if (block->e_flag) {
    CHKS(((motion != G_76) && (block->m_modes[5] != 66) && 
      (block->m_modes[5] != 67) && (block->m_modes[5] != 68)),
       _("E word with no G76, M66, M67 or M68 to use it"));
  }

  if (block->h_flag) {
    CHKS((block->g_modes[8] != G_43 && motion != G_76),
      _("H word with no G43 or G76 to use it"));
  }

  if (block->i_flag) {    /* could still be useless if yz_plane arc */
    CHKS(((motion != G_2) && (motion != G_3) && (motion != G_5) && (motion != G_5_1) &&
          (motion != G_76) && (motion != G_87) && (block->g_modes[0] != G_10)),
        _("I word with no G2, G3, G5, G5.1, G10, G76, or G87 to use it"));
  }

  if (block->j_flag) {    /* could still be useless if xz_plane arc */
    CHKS(((motion != G_2) && (motion != G_3) && (motion != G_5) && (motion != G_5_1) && 
          (motion != G_76) && (motion != G_87) && (block->g_modes[0] != G_10)),
        _("J word with no G2, G3, G5, G5.1, G10, G76 or G87 to use it"));
  }

  if (block->k_flag) {    /* could still be useless if xy_plane arc */
    CHKS(((motion != G_2) && (motion != G_3) && (motion != G_33) &&
        (motion != G_33_1) && (motion != G_76) && (motion != G_87)),
        _("K word with no G2, G3, G33, G33.1, G76, or G87 to use it"));
  }

  if (block->l_number != -1) {
    CHKS((((motion < G_81) || (motion > G_89)) && (motion != G_76) &&
         (motion != G_5_2) && (motion != G_73) &&
         (block->g_modes[0] != G_10) &&
         (block->g_modes[7] != G_41) && (block->g_modes[7] != G_41_1) &&
         (block->g_modes[7] != G_42) && (block->g_modes[7] != G_42_1) &&
	 (block->m_modes[5] != 66)),
         _("L word with no G10, cutter compensation, canned cycle, digital/analog input, or NURBS code"));
  }

  if (block->p_flag) {
      CHKS(((block->g_modes[0] != G_10) && (block->g_modes[0] != G_4) && (block->g_modes[13] != G_64) &&
          (motion != G_76) && (motion != G_82) && (motion != G_86) && (motion != G_88) && 
          (motion != G_89) && (motion != G_5) && (motion != G_5_2) &&
          (motion != G_2) && (motion != G_3) &&
          (block->m_modes[9] != 50) && (block->m_modes[9] != 51) && (block->m_modes[9] != 52) &&
          (block->m_modes[9] != 53) && (block->m_modes[5] != 62) && (block->m_modes[5] != 63) &&
          (block->m_modes[5] != 64) && (block->m_modes[5] != 65) && (block->m_modes[5] != 66) &&
          (block->m_modes[7] != 19) && (block->user_m != 1)),
          _("P word with no G2 G3 G4 G10 G64 G5 G5.2 G76 G82 G86 G88 G89"
            " or M50 M51 M52 M53 M62 M63 M64 M65 M66 or user M code to use it"));
      int p_value = round_to_int(block->p_number);
      CHKS(((motion == G_2 || motion == G_3 || (block->m_modes[7] == 19)) && 
	    fabs(p_value - block->p_number) > 0.001),
	   _("P value not an integer with M19 G2 or G3"));
      CHKS((block->m_modes[7] == 19) && ((p_value > 2) || p_value < 0),
	   _("P value must be 0,1,or 2 with M19"));
      CHKS(((motion == G_2 || motion == G_3) && round_to_int(block->p_number) < 1),
          _("P value should be 1 or greater with G2 or G3"));
  }

  if (block->q_number != -1.0) {
      CHKS((motion != G_83) && (motion != G_73) && (motion != G_5) && (block->user_m != 1) && (motion != G_76) &&
	   (block->m_modes[5] != 66) && (block->m_modes[5] != 67) && (block->m_modes[5] != 68) && 
	   (block->g_modes[0] != G_10) && (block->m_modes[6] != 61) && (block->g_modes[13] != G_64) && 
	   (block->m_modes[7] != 19), 
	   _("Q word with no G5, G10, G64, G73, G76, G83, M19, M66, M67, M68 or user M code that uses it"));
  }

  if (block->r_flag) {
    CHKS(((motion != G_2) && (motion != G_3) && (motion != G_76) &&
         ((motion < G_81) || (motion > G_89)) && (motion != G_73) && 
         (block->g_modes[7] != G_41_1) && (block->g_modes[7] != G_42_1) &&
         (block->g_modes[0] != G_10) && (block->m_modes[7] != 19) ),
        NCE_R_WORD_WITH_NO_G_CODE_THAT_USES_IT);
    CHKS((block->m_modes[7] == 19) && ((block->r_number > 360.0) || (block->r_number < 0.0)),
	   _("R value must be within 0..360 with M19"));
  }

  if (!block->s_flag) {
    CHKS((block->g_modes[14] == G_96), NCE_S_WORD_MISSING_WITH_G96);
  }

  if (motion == G_33 || motion == G_33_1) {
    CHKS((!block->k_flag), NCE_K_WORD_MISSING_WITH_G33);
    CHKS((block->f_flag), NCE_F_WORD_USED_WITH_G33);
  }

  if (motion == G_76) {
    // pitch
    CHKS((block->p_number == -1), NCE_P_WORD_MISSING_WITH_G76);

    CHKS((!block->i_flag || !block->j_flag || !block->k_flag),
            NCE_I_J_OR_K_WORDS_MISSING_WITH_G76);
  }

  return INTERP_OK;
}