Commit 51f14c29 authored by Fabrice Salvaire's avatar Fabrice Salvaire

improved API, G-code doc

parent 07b48073
......@@ -382,15 +382,26 @@ class Line(MachineMixin):
yield item
def iter_on_gm_word(self):
for item in self:
if isinstance(item, Word) and item.is_gm_gcode:
for item in self.iter_on_word():
if item.is_gm_gcode:
yield item
def iter_on_x_word(self):
for item in self:
if isinstance(item, Word) and not item.is_gm_gcode:
for item in self.iter_on_word():
if not item.is_gm_gcode:
yield item
def iter_on_letter(self, letters):
for item in self.iter_on_word():
if item.letter in letters:
yield item
def iter_on_g_word(self):
return self.iter_on_letter('G')
def iter_on_m_word(self):
return self.iter_on_letter('M')
def iter_on_setting(self):
for item in self:
if isinstance(item, ParameterSetting):
......@@ -421,6 +432,19 @@ class Line(MachineMixin):
##############################################
def check_modal_group(self):
modal_groups = {}
for item in self.iter_on_gm_word():
group = item.modal_group
modal_groups.setdefault(group, 0)
modal_groups[group] += 1
errors = [modal_group for modal_group, count in modal_groups.items() if count > 1]
if errors:
raise ValueError("Modal group errors {}".format(errors))
##############################################
def __repr__(self):
items = []
......@@ -514,6 +538,7 @@ class Word(LineItem):
"""Class to implement word"""
# Fixme: config ???
LETTERS = (
'A', 'B', 'C', 'D',
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', # 'N',
......@@ -594,12 +619,20 @@ class Word(LineItem):
if self._machine is None:
raise NameError('Machine is not defined')
@property
def _machine_config(self):
self._check_machine()
return self._machine.config
##############################################
@property
def is_gm_gcode(self):
self._check_machine()
return self._machine.is_gm_word(self)
return self._machine_config.letters.is_gm_word(self)
@property
def is_axis_gcode(self):
return self._machine_config.letters.is_axis_word(self)
##############################################
......
......@@ -36,9 +36,9 @@ __all__ = [
'ExecutionOrder',
'Gcode',
'GcodeSet',
'Letters',
'LetterSet',
'ModalGroup',
'ModalGroups',
'ModalGroupSet',
'Parameter',
'ParameterSet',
]
......@@ -156,6 +156,11 @@ class Parameter(MeaningMixin):
def default_value(self):
return self._value
##############################################
def __repr__(self):
return '#{0._index}: {0._meaning}'.format(self)
####################################################################################################
class ParameterSet(YamlMixin, RstMixin):
......@@ -210,12 +215,36 @@ class Letter(MeaningMixin):
"""G-code letter (table key)"""
return self._letter
##############################################
def __repr__(self):
return '#{0._letter}: {0._meaning}'.format(self)
####################################################################################################
class Letters(YamlMixin, RstMixin):
class LetterSet(YamlMixin, RstMixin):
"""Class for the table of letters."""
GM_LETTERS = 'GM'
AXIS_LETTERS = 'XYZABC' # 6-axis
##############################################
def is_gm_letter(self, letter):
return letter in self.GM_LETTERS
def is_axis_letter(self, letter):
return letter in self.AXIS_LETTERS
##############################################
def is_gm_word(self, word):
return self.is_gm_letter(word.letter)
def is_axis_word(self, word):
return self.is_axis_letter(word.letter)
##############################################
def __init__(self, yaml_path):
......@@ -251,7 +280,11 @@ class Gcode(MeaningMixin):
##############################################
def __init__(self, gcode, meaning, modal_group=None, execution_order=None):
def __init__(self, gcode, meaning,
modal_group=None,
execution_order=None,
doc=None,
):
MeaningMixin.__init__(self, meaning)
self._gcode = str(gcode)
......@@ -259,6 +292,7 @@ class Gcode(MeaningMixin):
# Those are set later due to the initialisation process
self._modal_group = modal_group
self._execution_order = execution_order
self._doc = doc
##############################################
......@@ -279,6 +313,21 @@ class Gcode(MeaningMixin):
def execution_order_index(self):
return self._execution_order.index
@property
def doc(self):
return self._doc
##############################################
def __str__(self):
return self._gcode
##############################################
def convert_doc(self, format):
import pypandoc
return pypandoc.convert_text(self.doc, 'rst', format=format)
####################################################################################################
class GcodeSet(YamlMixin, RstMixin):
......@@ -295,6 +344,8 @@ class GcodeSet(YamlMixin, RstMixin):
gcode = Gcode(gcode_txt, d['meaning'])
self._gcodes[gcode_txt] = gcode
self._sorted_gcodes = None
##############################################
def __len__(self):
......@@ -311,11 +362,34 @@ class GcodeSet(YamlMixin, RstMixin):
##############################################
def _sort(self):
if self._sorted_gcodes is None:
items = list(self)
items.sort(key=lambda item: str(ord(item.gcode[0])*1000) + item.gcode[1:])
self._sorted_gcodes = items
return self._sorted_gcodes
##############################################
def sorted_iter(self):
return iter(self._sort())
items = list(self)
items.sort(key=lambda item: str(ord(item.gcode[0])*1000) + item.gcode[1:])
return items
##############################################
def iter_on_slice(self, start, stop):
start_index = None
stop_index = None
for i, item in enumerate(self._sort()):
if item.gcode == start:
start_index = i
elif item.gcode == stop:
stop_index = i
if start_index > stop_index:
raise ValueError('{} > {}'.format(start, stop))
return iter(self._sorted_gcodes[start_index:stop_index+1])
##############################################
......@@ -356,6 +430,11 @@ class ExecutionGroup(MeaningMixin):
"""Raw G-Codes list"""
return self._raw_gcodes
##############################################
def __str__(self):
return '#{0._index} Meaning: {0._meaning}'.format(self)
####################################################################################################
class ExecutionOrder(YamlMixin, RstMixin):
......@@ -445,9 +524,14 @@ class ModalGroup(MeaningMixin):
"""G-Codes list"""
return self._gcodes
##############################################
def __repr__(self):
return '#{0._index}: ({1}) Meaning: {0._meaning}'.format(self, ' '.join([str(gcode) for gcode in self._gcodes]))
####################################################################################################
class ModalGroups(YamlMixin, RstMixin):
class ModalGroupSet(YamlMixin, RstMixin):
"""Class for the table of modal groups."""
......@@ -521,13 +605,54 @@ class Config:
self._gcodes = GcodeSet(gcodes)
self._execution_order = ExecutionOrder(execution_order, self._gcodes)
self._modal_groups = ModalGroups(modal_groups, self._gcodes)
self._modal_groups = ModalGroupSet(modal_groups, self._gcodes)
# self._letters = str(letters)
# self._parameters = str(parameters)
self._letters = Letters(letters)
self._letters = LetterSet(letters)
self._parameters = ParameterSet(parameters)
self._load_doc()
##############################################
def _load_doc(self):
from . import GcodeDoc as gcode_doc
for obj in gcode_doc.__dict__.values():
if isinstance(obj, type):
self._load_gcode_doc_cls(obj)
##############################################
def _set_gcode_doc(self, gcode, cls):
rst_doc = cls.__doc__
rst_doc = rst_doc.replace('\n' + ' '*4, '\n')
self._gcodes[gcode]._doc = rst_doc
##############################################
def _load_gcode_doc_cls(self, cls):
cls_name = cls.__name__
for letter in self._letters.GM_LETTERS:
cls_name = cls_name.replace('_' + letter, ' ' + letter)
cls_name = cls_name.replace('_to', '-')
cls_name = cls_name.replace('_', '.')
gcodes = cls_name.split(' ')
i = 0
while i < len(gcodes):
gcode = gcodes[i]
if gcode.endswith('-'):
start = gcode[:-1]
i += 1
stop = gcodes[i]
for _gcode in self._gcodes.iter_on_slice(start, stop):
self._set_gcode_doc(str(_gcode), cls)
else:
self._set_gcode_doc(gcode, cls)
i += 1
##############################################
@property
......@@ -542,14 +667,14 @@ class Config:
@property
def letters(self):
""":class:`Letters` instance"""
""":class:`LetterSet` instance"""
# if isinstance(self._letters, str):
# self._letters = Letters(self._letters)
# self._letters = LetterSet(self._letters)
return self._letters
@property
def modal_groups(self):
""":class:`ModalGroups` instance"""
""":class:`ModalGroupSet` instance"""
return self._modal_groups
@property
......
......@@ -40,8 +40,6 @@ class GcodeMachine:
PARSER_CLS = GcodeParser
GM_LETTERS = 'GM'
##############################################
def __init__(self):
......@@ -63,7 +61,7 @@ class GcodeMachine:
letters=data_path.joinpath('rs274-word-starting-letter.yaml'),
modal_groups=data_path.joinpath('rs274-modal-groups.yaml'),
parameters=data_path.joinpath('rs274-default-parameter-file.yaml'),
)
)
##############################################
......@@ -85,13 +83,3 @@ class GcodeMachine:
def reset():
pass
##############################################
def is_gm_letter(self, letter):
return letter in self.GM_LETTERS
##############################################
def is_gm_word(self, word):
return self.is_gm_letter(word.letter)
......@@ -28,6 +28,8 @@
#r#
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274`
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274.Ast`
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274.Condig`
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274.Machine`
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274.Parser`
####################################################################################################
......@@ -71,6 +73,7 @@ for line in program:
print()
# print(line.ansi_str()) # Fixme: pyterate
print(str(line))
line.check_modal_group()
for word in line.iter_on_word():
if word.is_gm_gcode:
margin = ' '*9
......
#?##################################################################################################
#?#
#?# PythonicGcodeMachine - A Python G-code Toolkit
#?# Copyright (C) 2018 Fabrice Salvaire
#?#
#?# This program is free software: you can redistribute it and/or modify
#?# it under the terms of the GNU General Public License as published by
#?# the Free Software Foundation, either version 3 of the License, or
#?# (at your option) any later version.
#?#
#?# This program is distributed in the hope that it will be useful,
#?# but WITHOUT ANY WARRANTY; without even the implied warranty of
#?# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#?# GNU General Public License for more details.
#?#
#?# You should have received a copy of the GNU General Public License
#?# along with this program. If not, see <http://www.gnu.org/licenses/>.
#?#
#?##################################################################################################
####################################################################################################
#r# ===============
#r# Query G-codes
#r# ===============
#r#
#r# For API see
#r#
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274`
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274.Config`
#r# * :mod:`PythonicGcodeMachine.Gcode.Rs274.Machine`
####################################################################################################
from pathlib import Path
from PythonicGcodeMachine.Gcode.Rs274.Machine import GcodeMachine
####################################################################################################
#r# We build a RS-274 G-code Machine
machine = GcodeMachine()
####################################################################################################
#r# We get G-code information
gcode = machine.config.gcodes['G0']
print('Modal group:', gcode.modal_group)
print('Execution order:', gcode.execution_order)
#o#
print('\nreStructuredText doc:\n')
print(gcode.doc)
#o#
#r# Convert the reStructuredText doc using `pypandoc <https://github.com/bebraw/pypandoc>`_ and
#r# `Pandoc <https://pandoc.org>`_
try:
print('\nMarkdown doc:')
print(gcode.convert_doc('md'))
except (ImportError, RuntimeError):
pass
#o#
try:
print('\nHTML doc:')
print(gcode.convert_doc('html5'))
except (ImportError, RuntimeError):
pass
#o#
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment