Some minor changes before merging the PR

* moved virtual printer into plugin
  * made default serial factory use supplied parameters instead of directly utilizing self._port and similar
  * documented new hook
This commit is contained in:
Gina Häußge 2015-04-16 11:43:30 +02:00
parent 5588deb925
commit 8ac375fc9b
4 changed files with 126 additions and 13 deletions

View file

@ -3,6 +3,9 @@
Available plugin hooks
======================
.. contents::
:local:
.. _sec-plugins-hook-comm-protocol-action:
octoprint.comm.protocol.action
@ -111,4 +114,81 @@ octoprint.comm.protocol.scripts
:param str script_type: The type of the script for which the hook was called, currently only "gcode" is supported here.
:param str script_name: The name of the script for which the hook was called.
:return: A 2-tuple in the form ``(prefix, postfix)`` or None
:rtype: tuple or None
:rtype: tuple or None
.. _sec-plugins-hook-comm-transport-serial-factory:
octoprint.comm.transport.serial.factory
---------------------------------------
.. py:function:: hook(comm_instance, port, baudrate, read_timeout, *args, **kwargs)
Return a serial object to use as serial connection to the printer. If a handler cannot create a serial object
for the specified ``port`` (and ``baudrate``), it should just return ``None``.
If the hook handler needs to perform state switches (e.g. for autodetection) or other operations on the
:class:`~octoprint.util.comm.MachineCom` instance, it can use the supplied ``comm_instance`` to do so. Plugin
authors should keep in mind however that due to a pending change in the communication layer of
OctoPrint, that interface will change in the future. Authors are advised to follow OctoPrint's development
closely if directly utilizing :class:`~octoprint.util.comm.MachineCom` functionality.
A valid serial instance is expected to provide the following methods, analogue to PySerial's
`serial.Serial <https://pythonhosted.org//pyserial/pyserial_api.html#serial.Serial>`_:
readline(size=None, eol='\n')
Reads a line from the serial connection, compare `serial.Filelike.readline <https://pythonhosted.org//pyserial/pyserial_api.html#serial.FileLike.readline>`_.
write(data)
Writes data to the serial connection, compare `serial.Filelike.write <https://pythonhosted.org//pyserial/pyserial_api.html#serial.FileLike.write>`_.
close()
Closes the serial connection, compare `serial.Serial.close <https://pythonhosted.org//pyserial/pyserial_api.html#serial.Serial.close>`_.
Additionally setting the following attributes need to be supported if baudrate detection is supposed to work:
baudrate
An integer describing the baudrate to use for the serial connection, compare `serial.Serial.baudrate <https://pythonhosted.org//pyserial/pyserial_api.html#serial.Serial.baudrate>`_.
timeout
An integer describing the read timeout on the serial connection, compare `serial.Serial.timeout <https://pythonhosted.org//pyserial/pyserial_api.html#serial.Serial.timeout>`_.
**Example:**
Serial factory similar to the default one which performs auto detection of the serial port if ``port`` is ``None``
or ``AUTO``.
.. code-block:: python
:linenos:
def default(comm_instance, port, baudrate, connection_timeout):
if port is None or port == 'AUTO':
# no known port, try auto detection
comm_instance._changeState(comm_instance.STATE_DETECT_SERIAL)
serial_obj = comm_instance._detectPort(False)
if serial_obj is None:
comm_instance._log("Failed to autodetect serial port")
comm_instance._errorValue = 'Failed to autodetect serial port.'
comm_instance._changeState(comm_instance.STATE_ERROR)
eventManager().fire(Events.ERROR, {"error": comm_instance.getErrorString()})
return None
else:
# connect to regular serial port
comm_instance._log("Connecting to: %s" % port)
if baudrate == 0:
serial_obj = serial.Serial(str(port), 115200, timeout=connection_timeout, writeTimeout=10000, parity=serial.PARITY_ODD)
else:
serial_obj = serial.Serial(str(port), baudrate, timeout=connection_timeout, writeTimeout=10000, parity=serial.PARITY_ODD)
serial_obj.close()
serial_obj.parity = serial.PARITY_NONE
serial_obj.open()
return serial_obj
:param MachineCom comm_instance: The :class:`~octoprint.util.comm.MachineCom` instance which triggered the hook.
:param port str: The port for which to construct a serial instance. May be ``None`` or ``AUTO`` in which case port
auto detection is to be performed.
:param baudrate int: The baudrate for which to construct a serial instance. May be 0 in which case baudrate auto
detection is to be performed.
:param read_timeout int: The read timeout to set on the serial port.
:return: The constructed serial object ready for use, or ``None`` if the handler could not construct the object.
:rtype: A serial instance implementing implementing the methods ``readline(...)``, ``write(...)``, ``close()`` and
optionally ``baudrate`` and ``timeout`` attributes as described above.

View file

@ -0,0 +1,38 @@
# coding=utf-8
from __future__ import absolute_import
__author__ = "Gina Häußge <osd@foosel.net>"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
__copyright__ = "Copyright (C) 2015 The OctoPrint Project - Released under terms of the AGPLv3 License"
import octoprint.plugin
class VirtualPrinterPlugin(octoprint.plugin.SettingsPlugin):
def virtual_printer_factory(self, comm_instance, port, baudrate, read_timeout):
if not port == "VIRTUAL":
return None
if not self._settings.global_get_boolean(["devel", "virtualPrinter", "enabled"]):
return None
from . import virtual
serial_obj = virtual.VirtualPrinter(read_timeout=float(read_timeout))
return serial_obj
__plugin_name__ = "Virtual Printer"
__plugin_author__ = "Gina Häußge, based on work by Daid Braam"
__plugin_homepage__ = "https://github.com/foosel/OctoPrint/wiki/Plugin:-Virtual-Printer"
__plugin_license__ = "AGPLv3"
__plugin_description__ = "Provides a virtual printer via a virtual serial port for development and testing purposes"
def __plugin_load__():
plugin = VirtualPrinterPlugin()
global __plugin_implementation__
__plugin_implementation__ = plugin
global __plugin_hooks__
__plugin_hooks__ = {
"octoprint.comm.transport.serial.factory": plugin.virtual_printer_factory
}

View file

@ -25,7 +25,6 @@ from octoprint.events import eventManager, Events
from octoprint.filemanager import valid_file_type
from octoprint.filemanager.destinations import FileDestinations
from octoprint.util import get_exception_string, sanitize_ascii, filter_non_ascii, CountedEvent, RepeatedTimer
from octoprint.util.virtual import VirtualPrinter
try:
import _winreg
@ -174,7 +173,7 @@ class MachineCom(object):
self._gcode_hooks = self._pluginManager.get_hooks("octoprint.comm.protocol.gcode")
self._printer_action_hooks = self._pluginManager.get_hooks("octoprint.comm.protocol.action")
self._gcodescript_hooks = self._pluginManager.get_hooks("octoprint.comm.protocol.scripts")
self._serial_hooks = self._pluginManager.get_hooks("octoprint.comm.protocol.serial")
self._serial_factory_hooks = self._pluginManager.get_hooks("octoprint.comm.transport.serial.factory")
# SD status data
self._sdAvailable = False
@ -1205,8 +1204,8 @@ class MachineCom(object):
return None
def _openSerial(self):
def default(_, port, baudrate, connection_timeout):
if self._port is None or self._port == 'AUTO':
def default(_, port, baudrate, read_timeout):
if port is None or port == 'AUTO':
# no known port, try auto detection
self._changeState(self.STATE_DETECT_SERIAL)
serial_obj = self._detectPort(False)
@ -1217,24 +1216,20 @@ class MachineCom(object):
eventManager().fire(Events.ERROR, {"error": self.getErrorString()})
return None
elif port == "VIRTUAL":
# virtual printer, use that
serial_obj = VirtualPrinter()
else:
# connect to regular serial port
self._log("Connecting to: %s" % self._port)
self._log("Connecting to: %s" % port)
if baudrate == 0:
serial_obj = serial.Serial(str(port), 115200, timeout=connection_timeout, writeTimeout=10000, parity=serial.PARITY_ODD)
serial_obj = serial.Serial(str(port), 115200, timeout=read_timeout, writeTimeout=10000, parity=serial.PARITY_ODD)
else:
serial_obj = serial.Serial(str(port), baudrate, timeout=connection_timeout, writeTimeout=10000, parity=serial.PARITY_ODD)
serial_obj = serial.Serial(str(port), baudrate, timeout=read_timeout, writeTimeout=10000, parity=serial.PARITY_ODD)
serial_obj.close()
serial_obj.parity = serial.PARITY_NONE
serial_obj.open()
return serial_obj
serial_factories = self._serial_hooks.items() + [("default", default)]
serial_factories = self._serial_factory_hooks.items() + [("default", default)]
for name, factory in serial_factories:
try:
serial_obj = factory(self, self._port, self._baudrate, settings().getFloat(["serial", "timeout", "connection"]))