Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OS independent board autoloading #53

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion pyfirmata/pyfirmata.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ class NoInputWarning(RuntimeWarning):
pass


class BoardSetupError(Exception):
pass


class Board(object):
"""The Base class for any board."""
firmata_version = None
Expand All @@ -92,6 +96,7 @@ def __init__(self, port, layout=None, baudrate=57600, name=None, timeout=None):
# For 2.3, even 5 seconds might not be enough.
# TODO Find a more reliable way to wait until the board is ready
self.pass_time(BOARD_SETUP_WAIT_TIME)
self.port = port
self.name = name
self._layout = layout
if not self.name:
Expand Down Expand Up @@ -178,7 +183,7 @@ def auto_setup(self):
if self._layout:
self.setup_layout(self._layout)
else:
raise IOError("Board detection failed.")
raise BoardSetupError("Board detection failed.")

def add_cmd_handler(self, cmd, func):
"""Adds a command handler for a command."""
Expand Down
63 changes: 45 additions & 18 deletions pyfirmata/util.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Helper functioons for pyFirmata."""
from __future__ import division, unicode_literals

import os
Expand All @@ -6,36 +7,62 @@
import time

import serial
import serial.tools.list_ports

from .boards import BOARDS


def get_the_board(layout=BOARDS['arduino'], base_dir='/dev/', identifier='tty.usbserial',):
def autoload_board(layout=None, ports=None, ports_filter='Arduino'):
"""
Helper function to get the one and only board connected to the computer
running this. It assumes a normal arduino layout, but this can be
overriden by passing a different layout dict as the ``layout`` parameter.
``base_dir`` and ``identifier`` are overridable as well. It will raise an
IOError if it can't find a board, on a serial, or if it finds more than
one.
Helper function to get the one and only board connected to the computer.

It loads board layout from board auto setup, but layout could be specified
by setting ``layout`` parameter.
By default it loads active ports list by OS independent call, but specific
ports to scan could be set by ``ports`` parameter. When autoloading ports
they could be filtered by description starting by specific string (default
"Arduino"). Filtering could be disabled by setting ``ports_filter`` to None.

It will raise an IOError if it can't find a board, on a serial, or if it
finds more than one.
"""
from .pyfirmata import Board # prevent a circular import
from .pyfirmata import Board, BoardSetupError # prevent a circular import

# OS independent ports scan
if ports is None:
ports = [
port.device for port
in serial.tools.list_ports.comports()
if ports_filter is None or port.description.startswith(ports_filter)
]

boards = []
for device in os.listdir(base_dir):
if device.startswith(identifier):
try:
board = Board(os.path.join(base_dir, device), layout)
except serial.SerialException:
pass
else:
boards.append(board)
for port in ports:
try:
board = Board(port, layout)
except (serial.SerialException, BoardSetupError):
pass
else:
boards.append(board)

if len(boards) == 0:
raise IOError("No boards found in {0} with identifier {1}".format(base_dir, identifier))
raise IOError("No boards connected to {0} found".format(ports))
elif len(boards) > 1:
raise IOError("More than one board found!")
raise IOError("Multiple boards found!")
print("Initialized board on port", boards[0].port)
return boards[0]


def get_the_board(layout=BOARDS['arduino'], base_dir='/dev/', identifier='tty.usbserial'):
"""Deprecated function for backward compatibility, Linux-only ports scan."""
ports = []

for device in os.listdir(base_dir):
if device.startswith(identifier):
ports.append(os.path.join(base_dir, device))
return autoload_board(layout=layout, ports=ports)


class Iterator(threading.Thread):
def __init__(self, board):
super(Iterator, self).__init__()
Expand Down