Skip to content

Commit 71d3e02

Browse files
committed
start of switchable dialect
1 parent 2dd1a1d commit 71d3e02

File tree

7 files changed

+176
-4
lines changed

7 files changed

+176
-4
lines changed

src/pygcode/block.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,16 @@ class Block(object):
88
def __init__(self, text=None, verify=True):
99
"""
1010
Block Constructor
11-
:param A-Z: gcode parameter values
12-
:param comment: comment text
11+
:param text: gcode line content (including comments) as string
12+
:type text: :class:`str`
13+
:param verify: verify given codes (modal & non-modal are not repeated)
14+
:type verify: :class:`bool`
15+
16+
.. note::
17+
18+
State & machine specific codes cannot be verified at this point;
19+
they must be processed by a virtual machine to be fully verified.
20+
1321
"""
1422

1523
self._raw_text = None

src/pygcode/dialect.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
def gcode_dialect(*names):
3+
"""
4+
GCode class dialect registration decorator
5+
6+
:param names: name of relevant dialects
7+
:type names: :class:`list` of :class:`str` instances
8+
9+
For example::
10+
11+
from pygcode.dialect import gcode_dialect as dialect
12+
from pygcode.gcodes import GCode
13+
14+
@dialect('linuxcnc')
15+
class GCodeRapidMove(GCode):
16+
word_key = Word('G', 0)
17+
18+
def _process(self, machine):
19+
params = self.get_param_dict(letters=machine.axes)
20+
machine.move_to(rapid=True, **params)
21+
22+
@dialect('reprap')
23+
clsas GCodeRapidMove2(GCode): # name changed because scope is the same
24+
word_key = Word('G', 0)
25+
26+
def _process(self, machine):
27+
params = self.get_param_dict(letters=machine.axes)
28+
params = {k: -v for (k, v) in params.items()} # negate parameters
29+
machine.move_to(rapid=True, **params)
30+
31+
When processing a ``linuxcnc`` dialect, the machine coordintes would be
32+
positive. Conversely the coordintes would be negated if processed in the
33+
``reprap`` dialect.
34+
35+
"""
36+
# TODO
37+
38+
def word_dialect(*names):
39+
"""
40+
"""

src/pygcode/dialect/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
__all__ = [
2+
3+
'DEFAULT',
4+
5+
# registration decorators
6+
'gcode_dialect',
7+
'word_dialect',
8+
]
9+
10+
DEFAULT = 'linuxcnc'
11+
12+
# Registration decorators
13+
from .mapping import gcode_dialect
14+
from .mapping import word_dialect

src/pygcode/dialect/linuxcnc.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""
2+
LinuxCNC
3+
4+
The linuxcnc gcode dialect is typically used for subtractive fabrication, such
5+
as milling.
6+
7+
This dialect is the basis for all other dialects; GCodes and Words in other
8+
dialects either inherit, or directly reference these classes.
9+
10+
**Specification:** http://www.linuxcnc.org
11+
12+
TODO: verify above info before publishing
13+
"""
14+
15+
# ======================== WORDS ========================
16+
17+
18+
# ======================== G-CODES ========================

src/pygcode/dialect/mapping.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
2+
# ---------------- Registration Decorators ----------------
3+
def gcode_dialect(*names):
4+
"""
5+
GCode class dialect registration decorator
6+
7+
:param names: name of relevant dialects
8+
:type names: :class:`list` of :class:`str` instances
9+
10+
For example::
11+
12+
from pygcode.dialect import gcode_dialect as dialect
13+
from pygcode.gcodes import GCode
14+
15+
@dialect('linuxcnc')
16+
class GCodeRapidMove(GCode):
17+
word_key = Word('G', 0)
18+
19+
def _process(self, machine):
20+
params = self.get_param_dict(letters=machine.axes)
21+
machine.move_to(rapid=True, **params)
22+
23+
@dialect('reprap')
24+
clsas GCodeRapidMove2(GCode): # name changed because scope is the same
25+
word_key = Word('G', 0)
26+
27+
def _process(self, machine):
28+
params = self.get_param_dict(letters=machine.axes)
29+
params = {k: -v for (k, v) in params.items()} # negate parameters
30+
machine.move_to(rapid=True, **params)
31+
32+
When processing a ``linuxcnc`` dialect, the machine coordintes would be
33+
positive. Conversely the coordintes would be negated if processed in the
34+
``reprap`` dialect.
35+
36+
"""
37+
# TODO
38+
39+
def word_dialect(*names):
40+
"""
41+
42+
"""
43+
44+
# TODO
45+
46+
47+
# ---------------- Dialect ----------------

src/pygcode/dialect/reprap.py

Whitespace-only changes.

src/pygcode/gcodes.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,7 @@ def word_gcode_class(word, exhaustive=False):
14401440
build_maps()
14411441

14421442
# quickly eliminate parameters
1443+
# TODO: get valid world letters from dialect
14431444
if (not exhaustive) and (word.letter not in 'GMFSTNO'):
14441445
return None
14451446

@@ -1457,9 +1458,16 @@ def word_gcode_class(word, exhaustive=False):
14571458

14581459
def words2gcodes(words):
14591460
"""
1460-
Group words into g-codes (includes both G & M codes)
1461-
:param words: list of Word instances
1461+
Group words into GCodes
1462+
:param words: list of :class:`Word <pygcode.words.Word>` instances
1463+
:type words: :class:`list`
14621464
:return: tuple([<GCode>, <GCode>, ...], list(<unused words>))
1465+
:rtype: :class:`tuple`
1466+
1467+
Returns a 2-tuple:
1468+
1469+
- list of :class:`GCode <pygocde.gcodes.GCode>` instances
1470+
-
14631471
"""
14641472

14651473
gcodes = []
@@ -1536,8 +1544,45 @@ def split_gcodes(gcode_list, splitter_class, sort_list=True):
15361544
"""
15371545
Splits a list of GCode instances into 3, the center list containing the splitter_class gcode
15381546
:param gcode_list: list of GCode instances to split
1547+
:type gcode_list: :class:`list`
15391548
:param splitter_class: class of gcode identifying split from left to right
1549+
:type splitter_class: :class:`GCode`
1550+
:param sort_list: if ``False``, gcodes list is not sorted before processing
1551+
:type sort_list: :class:`bool`
15401552
:return: list of: [[<gcodes before splitter>], [<splitter instance>], [<gcodes after splitter>]]
1553+
:rtype: :class:`list`
1554+
1555+
Returns a list with 3 elements
1556+
1557+
- gcodes before splitter (may be empty)
1558+
- splitter instance (list with a single element)
1559+
- gcodes after splitter (may be empty)
1560+
1561+
For example:
1562+
1563+
.. doctest::
1564+
1565+
>>> from pygcode import Block
1566+
>>> from pygcode.gcodes import split_gcodes, GCodeCoolantOff
1567+
>>> block = Block('G1 X1 Y2 M9 F100 S200')
1568+
1569+
>>> (a, b, c) = split_gcodes(block.gcodes, GCodeCoolantOff)
1570+
>>> a
1571+
[<GCodeFeedRate: F100>, <GCodeSpindleSpeed: S200>]
1572+
>>> b
1573+
[<GCodeCoolantOff: M09>]
1574+
>>> c
1575+
[<GCodeLinearMove: G01{X1, Y2}>]
1576+
1577+
>>> # Line with the M09 code removed
1578+
>>> a + c
1579+
[<GCodeFeedRate: F100>, <GCodeSpindleSpeed: S200>, <GCodeLinearMove: G01{X1, Y2}>]
1580+
1581+
.. note::
1582+
1583+
The above example is sorted in execution order by default, set
1584+
``sort_list=False`` to override this behaviour.
1585+
15411586
"""
15421587
# for example:
15431588
# g_list = sorted([g1, g2, g3, g4])

0 commit comments

Comments
 (0)