diff --git a/src/pygcode/block.py b/src/pygcode/block.py index d664176..ab9e774 100644 --- a/src/pygcode/block.py +++ b/src/pygcode/block.py @@ -8,8 +8,16 @@ class Block(object): def __init__(self, text=None, verify=True): """ Block Constructor - :param A-Z: gcode parameter values - :param comment: comment text + :param text: gcode line content (including comments) as string + :type text: :class:`str` + :param verify: verify given codes (modal & non-modal are not repeated) + :type verify: :class:`bool` + + .. note:: + + State & machine specific codes cannot be verified at this point; + they must be processed by a virtual machine to be fully verified. + """ self._raw_text = None diff --git a/src/pygcode/dialect.py b/src/pygcode/dialect.py new file mode 100644 index 0000000..10745cc --- /dev/null +++ b/src/pygcode/dialect.py @@ -0,0 +1,40 @@ + +def gcode_dialect(*names): + """ + GCode class dialect registration decorator + + :param names: name of relevant dialects + :type names: :class:`list` of :class:`str` instances + + For example:: + + from pygcode.dialect import gcode_dialect as dialect + from pygcode.gcodes import GCode + + @dialect('linuxcnc') + class GCodeRapidMove(GCode): + word_key = Word('G', 0) + + def _process(self, machine): + params = self.get_param_dict(letters=machine.axes) + machine.move_to(rapid=True, **params) + + @dialect('reprap') + clsas GCodeRapidMove2(GCode): # name changed because scope is the same + word_key = Word('G', 0) + + def _process(self, machine): + params = self.get_param_dict(letters=machine.axes) + params = {k: -v for (k, v) in params.items()} # negate parameters + machine.move_to(rapid=True, **params) + + When processing a ``linuxcnc`` dialect, the machine coordintes would be + positive. Conversely the coordintes would be negated if processed in the + ``reprap`` dialect. + + """ + # TODO + +def word_dialect(*names): + """ + """ diff --git a/src/pygcode/dialect/__init__.py b/src/pygcode/dialect/__init__.py new file mode 100644 index 0000000..9b083bc --- /dev/null +++ b/src/pygcode/dialect/__init__.py @@ -0,0 +1,14 @@ +__all__ = [ + + 'DEFAULT', + + # registration decorators + 'gcode_dialect', + 'word_dialect', +] + +DEFAULT = 'linuxcnc' + +# Registration decorators +from .mapping import gcode_dialect +from .mapping import word_dialect diff --git a/src/pygcode/dialect/linuxcnc.py b/src/pygcode/dialect/linuxcnc.py new file mode 100644 index 0000000..6c564ff --- /dev/null +++ b/src/pygcode/dialect/linuxcnc.py @@ -0,0 +1,18 @@ +""" +LinuxCNC + +The linuxcnc gcode dialect is typically used for subtractive fabrication, such +as milling. + +This dialect is the basis for all other dialects; GCodes and Words in other +dialects either inherit, or directly reference these classes. + +**Specification:** http://www.linuxcnc.org + +TODO: verify above info before publishing +""" + +# ======================== WORDS ======================== + + +# ======================== G-CODES ======================== diff --git a/src/pygcode/dialect/mapping.py b/src/pygcode/dialect/mapping.py new file mode 100644 index 0000000..ced90c4 --- /dev/null +++ b/src/pygcode/dialect/mapping.py @@ -0,0 +1,47 @@ + +# ---------------- Registration Decorators ---------------- +def gcode_dialect(*names): + """ + GCode class dialect registration decorator + + :param names: name of relevant dialects + :type names: :class:`list` of :class:`str` instances + + For example:: + + from pygcode.dialect import gcode_dialect as dialect + from pygcode.gcodes import GCode + + @dialect('linuxcnc') + class GCodeRapidMove(GCode): + word_key = Word('G', 0) + + def _process(self, machine): + params = self.get_param_dict(letters=machine.axes) + machine.move_to(rapid=True, **params) + + @dialect('reprap') + clsas GCodeRapidMove2(GCode): # name changed because scope is the same + word_key = Word('G', 0) + + def _process(self, machine): + params = self.get_param_dict(letters=machine.axes) + params = {k: -v for (k, v) in params.items()} # negate parameters + machine.move_to(rapid=True, **params) + + When processing a ``linuxcnc`` dialect, the machine coordintes would be + positive. Conversely the coordintes would be negated if processed in the + ``reprap`` dialect. + + """ + # TODO + +def word_dialect(*names): + """ + + """ + + # TODO + + +# ---------------- Dialect ---------------- diff --git a/src/pygcode/dialect/reprap.py b/src/pygcode/dialect/reprap.py new file mode 100644 index 0000000..e69de29 diff --git a/src/pygcode/gcodes.py b/src/pygcode/gcodes.py index 45c7078..a2e5f34 100644 --- a/src/pygcode/gcodes.py +++ b/src/pygcode/gcodes.py @@ -1440,6 +1440,7 @@ def word_gcode_class(word, exhaustive=False): build_maps() # quickly eliminate parameters + # TODO: get valid world letters from dialect if (not exhaustive) and (word.letter not in 'GMFSTNO'): return None @@ -1457,9 +1458,16 @@ def word_gcode_class(word, exhaustive=False): def words2gcodes(words): """ - Group words into g-codes (includes both G & M codes) - :param words: list of Word instances + Group words into GCodes + :param words: list of :class:`Word ` instances + :type words: :class:`list` :return: tuple([, , ...], list()) + :rtype: :class:`tuple` + + Returns a 2-tuple: + + - list of :class:`GCode ` instances + - """ gcodes = [] @@ -1536,8 +1544,45 @@ def split_gcodes(gcode_list, splitter_class, sort_list=True): """ Splits a list of GCode instances into 3, the center list containing the splitter_class gcode :param gcode_list: list of GCode instances to split + :type gcode_list: :class:`list` :param splitter_class: class of gcode identifying split from left to right + :type splitter_class: :class:`GCode` + :param sort_list: if ``False``, gcodes list is not sorted before processing + :type sort_list: :class:`bool` :return: list of: [[], [], []] + :rtype: :class:`list` + + Returns a list with 3 elements + + - gcodes before splitter (may be empty) + - splitter instance (list with a single element) + - gcodes after splitter (may be empty) + + For example: + + .. doctest:: + + >>> from pygcode import Block + >>> from pygcode.gcodes import split_gcodes, GCodeCoolantOff + >>> block = Block('G1 X1 Y2 M9 F100 S200') + + >>> (a, b, c) = split_gcodes(block.gcodes, GCodeCoolantOff) + >>> a + [, ] + >>> b + [] + >>> c + [] + + >>> # Line with the M09 code removed + >>> a + c + [, , ] + + .. note:: + + The above example is sorted in execution order by default, set + ``sort_list=False`` to override this behaviour. + """ # for example: # g_list = sorted([g1, g2, g3, g4])