From 1952e721a7257e537dfd4fdb91a8885a005fa226 Mon Sep 17 00:00:00 2001 From: Antonin Date: Sun, 15 Apr 2018 19:51:32 +0200 Subject: [PATCH 01/16] Package for pypi --- .gitignore | 2 ++ README.md | 4 ++-- setup.cfg | 10 ++++++++++ setup.py | 16 +++++++++++++++- 4 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 setup.cfg diff --git a/.gitignore b/.gitignore index 7053d6f..ba48e28 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ dist/ # Python egg metadata, regenerated from source files by setuptools. *.egg-info +dist/ +build/ diff --git a/README.md b/README.md index d29b30d..f853d8d 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,9 @@ Serial communication with an Arduino: [Arduino Source Code](https://github.com/a python -m examples.arduino_serial ``` -### Bluetooth Example +### Bluetooth Example with Two Computers -Dependency: +Dependencies: ``` sudo apt-get install libbluetooth-dev bluez pip install pybluez diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..6acc8ec --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +[metadata] +# This includes the license file in the wheel. +license_file = LICENSE + +[bdist_wheel] +# This flag says to generate wheels that support both Python 2 and Python +# 3. If your code will not run unchanged on both Python 2 and 3, you will +# need to generate separate wheels for each Python version that you +# support. +universal=1 diff --git a/setup.py b/setup.py index c1eafd0..23fa4dd 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,18 @@ from setuptools import setup, find_packages +# Create Package +# rm dist/* +# python setup.py sdist +# python setup.py bdist_wheel +# Upload +# (test) twine upload --repository-url https://test.pypi.org/legacy/ dist/* +# (release) twine upload dist/* + +long_description = """ +Robust Arduino Serial is a simple and robust serial communication protocol. +It was designed to make two arduinos communicate, but can also be useful when you want a computer (e.g. a Raspberry Pi) to communicate with an Arduino. +https://medium.com/@araffin/simple-and-robust-computer-arduino-serial-communication-f91b95596788 +""" setup(name="robust_serial", packages=[package for package in find_packages() @@ -11,8 +24,9 @@ tests_require=['pytest'], author="Antonin RAFFIN", author_email="antonin.raffin@ensta.org", - url="https://github.com/araffin/", + url="https://github.com/araffin/arduino-robust-serial", description="Simple and Robust Serial Communication Protocol", + long_description=long_description, keywords="serial hardware arduino RS232 communication protocol raspberry", license="MIT", version="0.1", From d7a0b30c24ac7e5a38818c200a7d5154c08262bc Mon Sep 17 00:00:00 2001 From: Antonin Date: Thu, 19 Apr 2018 20:51:33 +0200 Subject: [PATCH 02/16] With RFCOMM, the argument is a channel not a port --- examples/bluetooth_example.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/bluetooth_example.py b/examples/bluetooth_example.py index 90ccb9b..713bc08 100644 --- a/examples/bluetooth_example.py +++ b/examples/bluetooth_example.py @@ -6,7 +6,7 @@ from robust_serial import write_i8, write_i32, read_i8, read_i32 -PORT = 4885 +CHANNEL = 1 # show mac address: hciconfig SERVER_ADDR = "B8:27:EB:F1:E4:5F" @@ -16,7 +16,7 @@ def receive_messages(): Receive messages (server side) """ server_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) - server_sock.bind(("", PORT)) + server_sock.bind(("", CHANNEL)) print("Waiting for client...") # Wait for client server_sock.listen(1) @@ -42,7 +42,7 @@ def send_messages(mac_address): :param mac_address: (str) """ socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM) - socket.connect((mac_address, PORT)) + socket.connect((mac_address, CHANNEL)) print("Connected to {}".format(mac_address)) # Rename function to work with the lib From 79f502e654b3d192d23a0db44d18967ccbed5f44 Mon Sep 17 00:00:00 2001 From: Antonin Date: Mon, 23 Apr 2018 17:24:04 +0200 Subject: [PATCH 03/16] Add socket example --- README.md | 14 ++++++ examples/socket_example.py | 87 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 examples/socket_example.py diff --git a/README.md b/README.md index f853d8d..267c749 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,20 @@ Serial communication with an Arduino: [Arduino Source Code](https://github.com/a python -m examples.arduino_serial ``` +### Example: Communication with Sockets + +It can be useful when you want two programs to communicate over a network (e.g. using wifi) or even locally on the same computer (e.g. when you want a python2 script that communicates with a python3 script). + +1. Start the server: +``` +python -m examples.socket_example --server +``` + +2. Run the client: +``` +python -m examples.socket_example --client +``` + ### Bluetooth Example with Two Computers Dependencies: diff --git a/examples/socket_example.py b/examples/socket_example.py new file mode 100644 index 0000000..c7e32c8 --- /dev/null +++ b/examples/socket_example.py @@ -0,0 +1,87 @@ +from __future__ import print_function, division + +import argparse +import socket + +from robust_serial import write_i8, write_i32, read_i8, read_i32 + +PORT = 4444 +SERVER_ADDR = "localhost" + +class SocketAdapter(object): + """ + Wrapper around socket object to use the robust_serial lib + It just renames recv() to read() and send() to write() + """ + + def __init__(self, client_socket): + super(SocketAdapter, self).__init__() + self.client_socket = client_socket + + def read(self, num_bytes): + return self.client_socket.recv(num_bytes) + + def write(self, num_bytes): + return self.client_socket.send(num_bytes) + + def close(self): + return self.client_socket.close() + + +def receive_messages(): + """ + Receive messages (server side) + """ + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_socket.bind(('', PORT)) + print("Waiting for client...") + # Wait for client + server_socket.listen(1) + + client_sock, client_address = server_socket.accept() + print("Accepted connection from {}".format(client_address)) + # Wrap socket to work with the lib + client_sock = SocketAdapter(client_sock) + + for i in range(10): + print("Received (i8): {}".format(read_i8(client_sock))) + big_number = read_i32(client_sock) + + print("Received (i32): {}".format(big_number)) + + print("Server exiting...") + client_sock.close() + server_socket.close() + + +def send_messages(server_address): + """ + Send messages (client side) + :param server_address: (str) + """ + client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + client_socket.connect((server_address, PORT)) + + # Wrap socket to work with the lib + client_socket = SocketAdapter(client_socket) + + print("Connected to {}".format(server_address)) + for i in range(10): + write_i8(client_socket, i) + write_i32(client_socket, 32768) + print("Client exiting...") + client_socket.close() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Test socket server/client connection") + arg_group = parser.add_mutually_exclusive_group(required=True) + arg_group.add_argument("-s", "--server", dest="server", + action='store_true', default=False, help="Create a server") + arg_group.add_argument("-c", "--client", dest="client", + action='store_true', default=False, help="Create a client") + args = parser.parse_args() + if args.server: + receive_messages() + else: + send_messages(SERVER_ADDR) From e68a28e93484b0e820b848a8a4621990530a7fe0 Mon Sep 17 00:00:00 2001 From: Antonin Date: Mon, 23 Apr 2018 17:42:50 +0200 Subject: [PATCH 04/16] [ci skip] Update README Update installation instructions --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 267c749..0f04806 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,12 @@ Implementations are available in various programming languages: ## Installation +Using pip: +``` +pip install robust_serial +``` + +From Source: ``` git clone https://github.com/araffin/python-arduino-serial.git pip install -e . From 861090b7d074e99e3ea6b42a31b820a3d6132c5c Mon Sep 17 00:00:00 2001 From: Antonin RAFFIN Date: Sun, 2 Sep 2018 15:55:32 +0200 Subject: [PATCH 05/16] Add docs --- .gitignore | 2 + docs/Makefile | 20 ++++ docs/_static/css/custom_theme.css | 10 ++ docs/api.rst | 8 ++ docs/conf.py | 171 ++++++++++++++++++++++++++++++ docs/examples.rst | 94 ++++++++++++++++ docs/index.rst | 60 +++++++++++ docs/install.rst | 15 +++ docs/make.bat | 36 +++++++ docs/utils.rst | 14 +++ robust_serial/robust_serial.py | 4 + robust_serial/threads.py | 4 +- robust_serial/utils.py | 7 +- 13 files changed, 442 insertions(+), 3 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/_static/css/custom_theme.css create mode 100644 docs/api.rst create mode 100644 docs/conf.py create mode 100644 docs/examples.rst create mode 100644 docs/index.rst create mode 100644 docs/install.rst create mode 100644 docs/make.bat create mode 100644 docs/utils.rst diff --git a/.gitignore b/.gitignore index ba48e28..d8c170e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ __pycache__/ .cache/ *.x *.pyc +_build/ +.pytest_cache/ # Setuptools distribution folder. dist/ diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..a7780c8 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = RobustArduinoSerialProtocol +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/_static/css/custom_theme.css b/docs/_static/css/custom_theme.css new file mode 100644 index 0000000..77fc220 --- /dev/null +++ b/docs/_static/css/custom_theme.css @@ -0,0 +1,10 @@ +/* Header fonts y */ +h1, h2, .rst-content .toctree-wrapper p.caption, h3, h4, h5, h6, legend, p.caption { + font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; +} + + +/* Make code blocks have a background */ +.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight'] { + background: #f8f8f8;; +} diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..6e860db --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,8 @@ +.. _api: + + +Available Functions +=================== + +.. automodule:: robust_serial.robust_serial + :members: diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..79a3a29 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,171 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('..')) + +import robust_serial + +# -- Project information ----------------------------------------------------- + +project = 'Robust Arduino Serial Protocol' +copyright = '2018, Antonin Raffin' +author = 'Antonin Raffin' + +# The short X.Y version +version = '' +# The full version, including alpha/beta/rc tags +release = robust_serial.__version__ + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.doctest', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +# Fix for read the docs +on_rtd = os.environ.get('READTHEDOCS') == 'True' +if on_rtd: + html_theme = 'default' +else: + html_theme = 'sphinx_rtd_theme' + +def setup(app): + app.add_stylesheet("css/custom_theme.css") + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'RobustArduinoSerialProtocoldoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'RobustArduinoSerialProtocol.tex', 'Robust Arduino Serial Protocol Documentation', + 'Antonin Raffin', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'robustarduinoserialprotocol', 'Robust Arduino Serial Protocol Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'RobustArduinoSerialProtocol', 'Robust Arduino Serial Protocol Documentation', + author, 'RobustArduinoSerialProtocol', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Extension configuration ------------------------------------------------- diff --git a/docs/examples.rst b/docs/examples.rst new file mode 100644 index 0000000..9668ffb --- /dev/null +++ b/docs/examples.rst @@ -0,0 +1,94 @@ +.. _examples: + +Examples +======== + +Examples provided here are also in the ``examples/`` folder of the repo. + +Arduino Serial Communication +---------------------------- + +Serial communication with an Arduino: `Arduino Source Code`_ + +.. _Arduino Source Code: https://github.com/araffin/arduino-robust-serial/tree/master/arduino-board/ + + +.. code-block:: python + + from __future__ import print_function, division, absolute_import + + import time + + from robust_serial import write_order, Order, write_i8, write_i16, read_i8, read_order + from robust_serial.utils import open_serial_port + + + try: + serial_file = open_serial_port(baudrate=115200, timeout=None) + except Exception as e: + raise e + + is_connected = False + # Initialize communication with Arduino + while not is_connected: + print("Waiting for arduino...") + write_order(serial_file, Order.HELLO) + bytes_array = bytearray(serial_file.read(1)) + if not bytes_array: + time.sleep(2) + continue + byte = bytes_array[0] + if byte in [Order.HELLO.value, Order.ALREADY_CONNECTED.value]: + is_connected = True + + print("Connected to Arduino") + + motor_speed = -56 + + # Equivalent to write_i8(serial_file, Order.MOTOR.value) + write_order(serial_file, Order.MOTOR) + write_i8(serial_file, motor_speed) + + write_order(serial_file, Order.SERVO) + write_i16(serial_file, 120) + + for _ in range(10): + order = read_order(serial_file) + print("Ordered received: {:?}", order) + + + +Reading / Writing in a file +--------------------------- + +Read write in a file (WARNING: the file will be deleted when the script exits) + + +.. code-block:: python + + from __future__ import print_function, division, absolute_import + import os + + from robust_serial import Order, write_order, write_i8, write_i16, write_i32, read_i8, read_i16, read_i32, read_order + + test_file = "test.txt" + + with open(test_file, 'wb') as f: + write_order(f, Order.HELLO) + + write_i8(f, Order.MOTOR.value) + write_i16(f, -56) + write_i32(f, 131072) + + with open(test_file, 'rb') as f: + # Equivalent to Order(read_i8(f)) + order = read_order(f) + print(order) + + motor_order = read_order(f) + print(motor_order) + print(read_i16(f)) + print(read_i32(f)) + + # Delete file + os.remove(test_file) diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..8db022a --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,60 @@ +.. Robust Arduino Serial Protocol documentation master file, created by + sphinx-quickstart on Sun Sep 2 15:21:19 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Robust Arduino Serial Protocol's documentation! +========================================================== + +**Robust Arduino Serial** is a simple and robust serial communication +protocol. It was designed to make two arduinos communicate, but can also +be useful when you want a computer (e.g. a Raspberry Pi) to communicate +with an Arduino. + +It supports both Python 2 and 3. + +This repository is part of the Robust Arduino Serial project, main +repository: `https://github.com/araffin/arduino-robust-serial`_ + +.. warning:: + + Please read the `Medium Article`_ to have an overview of this + protocol. + +Implementations are available in various programming languages: + +- `Arduino`_ +- `Python`_ +- `C++`_ +- `Rust`_ + +.. _`https://github.com/araffin/arduino-robust-serial`: https://github.com/araffin/arduino-robust-serial +.. _Medium Article: https://medium.com/@araffin/simple-and-robust-computer-arduino-serial-communication-f91b95596788 +.. _Arduino: https://github.com/araffin/arduino-robust-serial +.. _Python: https://github.com/araffin/python-arduino-serial +.. _C++: https://github.com/araffin/cpp-arduino-serial +.. _Rust: https://github.com/araffin/rust-arduino-serial + +.. toctree:: + :maxdepth: 1 + :caption: User Guide + + install + + +.. toctree:: + :maxdepth: 2 + :caption: Reference + + api + utils + examples + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 0000000..584bba0 --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,15 @@ +Installation +============ + +Using pip: + +.. code-block:: bash + + pip install robust_serial + +From Source: + +.. code-block:: bash + + git clone https://github.com/araffin/python-arduino-serial.git + pip install -e . diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..93a7cb7 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build +set SPHINXPROJ=RobustArduinoSerialProtocol + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/utils.rst b/docs/utils.rst new file mode 100644 index 0000000..9a7cc77 --- /dev/null +++ b/docs/utils.rst @@ -0,0 +1,14 @@ +.. _utils: + +Utils +===== + +.. automodule:: robust_serial.utils + :members: + + +Threads +======= + +.. automodule:: robust_serial.threads + :members: diff --git a/robust_serial/robust_serial.py b/robust_serial/robust_serial.py index f0a0d50..c19298f 100644 --- a/robust_serial/robust_serial.py +++ b/robust_serial/robust_serial.py @@ -6,6 +6,10 @@ class Order(Enum): + """ + Pre-defined orders + """ + HELLO = 0 SERVO = 1 MOTOR = 2 diff --git a/robust_serial/threads.py b/robust_serial/threads.py index d52c1a4..8013766 100644 --- a/robust_serial/threads.py +++ b/robust_serial/threads.py @@ -14,7 +14,8 @@ class CommandThread(threading.Thread): """ Thread that send orders to the arduino - it blocks if there no more send_token left (here it is the n_received_semaphore) + it blocks if there no more send_token left (here it is the n_received_semaphore). + :param serial_file: (Serial object) :param command_queue: (Queue) :param exit_event: (Threading.Event object) @@ -58,6 +59,7 @@ class ListenerThread(threading.Thread): """ Thread that listen to the Arduino It is used to add send_tokens to the n_received_semaphore + :param serial_file: (Serial object) :param exit_event: (threading.Event object) :param n_received_semaphore: (threading.Semaphore) diff --git a/robust_serial/utils.py b/robust_serial/utils.py index ee3d185..3398f6e 100644 --- a/robust_serial/utils.py +++ b/robust_serial/utils.py @@ -36,8 +36,10 @@ def clear(self): # From https://stackoverflow.com/questions/12090503/listing-available-com-ports-with-python def get_serial_ports(): """ - Lists serial ports - :return: [str] A list of available serial ports + Lists serial ports. + + + :return: ([str]) A list of available serial ports """ if sys.platform.startswith('win'): ports = ['COM%s' % (i + 1) for i in range(256)] @@ -64,6 +66,7 @@ def open_serial_port(serial_port=None, baudrate=115200, timeout=0, write_timeout """ Try to open serial port with Arduino If not port is specified, it will be automatically detected + :param serial_port: (str) :param baudrate: (int) :param timeout: (int) None -> blocking mode From 6beccc099167a21595c84286a973347a3a903cbd Mon Sep 17 00:00:00 2001 From: Antonin RAFFIN Date: Sun, 2 Sep 2018 16:05:16 +0200 Subject: [PATCH 06/16] [ci skip] Add badge --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f04806..01d1b93 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Robust Arduino Serial Protocol in Python -[![Build Status](https://travis-ci.org/araffin/python-arduino-serial.svg?branch=master)](https://travis-ci.org/araffin/python-arduino-serial) +[![Build Status](https://travis-ci.org/araffin/python-arduino-serial.svg?branch=master)](https://travis-ci.org/araffin/python-arduino-serial) [![Documentation Status](https://readthedocs.org/projects/python-arduino-serial/badge/?version=latest)](https://python-arduino-serial.readthedocs.io/en/latest/?badge=latest) **Robust Arduino Serial** is a simple and robust serial communication protocol. It was designed to make two arduinos communicate, but can also be useful when you want a computer (e.g. a Raspberry Pi) to communicate with an Arduino. @@ -10,6 +10,8 @@ This repository is part of the Robust Arduino Serial project, main repository: [ **Please read the [Medium Article](https://medium.com/@araffin/simple-and-robust-computer-arduino-serial-communication-f91b95596788) to have an overview of this protocol.** +Documentation: [https://python-arduino-serial.readthedocs.io](https://python-arduino-serial.readthedocs.io) + Implementations are available in various programming languages: - [Arduino](https://github.com/araffin/arduino-robust-serial) From f919d5c3021d1f53aa340b1d7730b30d67ecdd01 Mon Sep 17 00:00:00 2001 From: Antonin Raffin Date: Mon, 10 Apr 2023 18:41:58 +0200 Subject: [PATCH 07/16] Update config files --- .coverage | Bin 0 -> 53248 bytes .github/workflows/ci.yml | 49 ++++++++++++++++++++++++++++++++ .travis.yml | 14 ---------- Makefile | 59 +++++++++++++++++++++++++++++++++++++++ pyproject.toml | 57 +++++++++++++++++++++++++++++++++++++ requirements.txt | 2 -- setup.cfg | 10 ------- setup.py | 14 ++++++++-- 8 files changed, 176 insertions(+), 29 deletions(-) create mode 100644 .coverage create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml create mode 100644 Makefile create mode 100644 pyproject.toml delete mode 100644 requirements.txt delete mode 100644 setup.cfg diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..445cf5296e939ba42e1c13d72d71faffb9c16e05 GIT binary patch literal 53248 zcmeI)TWcI;7zgl~o#}2j$!2P6Swbjz5j2g>W=*{i^+Kb~MX)7SgHQygvor5zr`?%J z=a42BBHM}uLFla_ejUB_BZwF6g&;x|q+a+ubI9(d*-{EiN%9}ElR3P{-@J#N-DEz! zdfAPoXa}KZ#o|rnl%lH2`$8y+Ql(doUd2+O4ZYZ*-|E2jsLiUfWGgk}Gi9p$onm}Z zTQ?e0Kh|EG{B_E!emnV7#j4tL0t*Bn009UbZ-L&`sY-ojM!oZ8Y_+;F4lP@T*}C@O zC#x$Pt72p2gUhQTJ0{Lg2wEBqu_D6Yw%C%PXuDl0T;FkRD|Y=&5qD$}I*Fvi6CE9+ zsg46KrSW;obRCKn%S}pRD|9_8+!Z(F?qV7s&n=caadv z4yc?vaaP+f@S1TTx~`vA(~sQP4SXSYq@BdlIk19@j8-g!H&`1=>pEBHdKNR!Ye1(T z`GA;t@H}#x3g-s}Yd<1qO_9?w`-#^g@*9b_#TSQSWEsc7sFHU^zC2^4M zn{@HbWm-*r{nE)weQr*@cPniu%wx9PINIB&4mFy+!y}pwpC8?BxR(q!67EIat_a#` zm*LnVyExRE2m4I3z_3E@Xd=i1Qb}KEYvaOF8APiaw1(SS+F~L}9fZb$B3L`|ZSE=& z*TD|9WoT{6rTlC*EWGH3L``S8TCT6ojcPi3O~72<+nngllq>bwS@ljeZASUk%70ac znow~i4;V&^Q=YVmoRVNQ;F6SF3dlkJ>KYLc~ zWj%t&C4QY4sstbDcY%Eq!Lt{C%ZfYV$+GidD){_~a{b-2qYBPNFqe5jV^9|uw7(zMFcR`gDBRLpm*h)1DlUbKRsD=j~p8z{zFM0vWANXzi# ztn^+#jcAwC*xa5^%T!D*Jj`!Urz`pwZFrvLJNbOY({Pq5js4s?IiGA0p@?FhI%Py% zbYGf9qWM`Kv5NGUw#bB2^(-gr?tD=OQoP-fPb8PkMwhHu#;zv?2T2Q)HmuuLB&>Z^`h^Q>FUdP&HqMw4P3oRi6g%H74KvI*lvJ>ce5OLaLcY>D^n;!mQjwHtQ=zfqjbk7i-a zd@qUJZbbj~?`V|AmGR^ecjy5C4(D>CM7dlWPcB3CqP(O^d99BpFVl2=H#SYmhQI&U zrya%k!C0F9g*LE200Izz00bZa0SG_<0uX=z1fEmC)_ZH}c00Izz00bZa0SG_<0uX?}5fsq0S~YwA{{zMN*LZLQtB5K=00Izz z00bZa0SG_<0uX=z1dfxysgkZ%Un#x*d-LVfr%!)#|Ni|Gs$Q*5m$T>pKT?dx#-rl| zg1SNg0uX=z1Rwwb2tWV=5P$##j=DgZJ_}GwC7nJ1NWcGAP960cqka&800bZa0SG_< z0uX=z1Rwx`<1N77|KtAuc((!69s&@600bZa0SG_<0uX=z1dhG{|Np;k{K0?!|Bvw( pZD4@_1Rwwb2tWV=5P$##AOHafK;TddXgWRcU( Date: Mon, 10 Apr 2023 18:42:26 +0200 Subject: [PATCH 08/16] Reformat --- docs/conf.py | 70 +++++++++++++++++++--------------- examples/arduino_serial.py | 7 ++-- examples/arduino_threads.py | 17 +++++---- examples/bluetooth_example.py | 12 +++--- examples/file_read_write.py | 17 ++++----- examples/socket_example.py | 15 ++++---- robust_serial/__init__.py | 1 + robust_serial/robust_serial.py | 19 ++++----- robust_serial/threads.py | 4 +- robust_serial/utils.py | 20 +++++----- setup.py | 36 ++++++++--------- tests/test_read_write.py | 5 ++- 12 files changed, 115 insertions(+), 108 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 79a3a29..f90a2db 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,18 +14,19 @@ # import os import sys -sys.path.insert(0, os.path.abspath('..')) + +sys.path.insert(0, os.path.abspath("..")) import robust_serial # -- Project information ----------------------------------------------------- -project = 'Robust Arduino Serial Protocol' -copyright = '2018, Antonin Raffin' -author = 'Antonin Raffin' +project = "Robust Arduino Serial Protocol" +copyright = "2018, Antonin Raffin" +author = "Antonin Raffin" # The short X.Y version -version = '' +version = "" # The full version, including alpha/beta/rc tags release = robust_serial.__version__ @@ -40,23 +41,23 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.autosummary', - 'sphinx.ext.doctest', - 'sphinx.ext.viewcode', + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.doctest", + "sphinx.ext.viewcode", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -68,10 +69,10 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # -- Options for HTML output ------------------------------------------------- @@ -80,15 +81,17 @@ # a list of builtin themes. # # Fix for read the docs -on_rtd = os.environ.get('READTHEDOCS') == 'True' +on_rtd = os.environ.get("READTHEDOCS") == "True" if on_rtd: - html_theme = 'default' + html_theme = "default" else: - html_theme = 'sphinx_rtd_theme' + html_theme = "sphinx_rtd_theme" + def setup(app): app.add_stylesheet("css/custom_theme.css") + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. @@ -98,7 +101,7 @@ def setup(app): # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -114,7 +117,7 @@ def setup(app): # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'RobustArduinoSerialProtocoldoc' +htmlhelp_basename = "RobustArduinoSerialProtocoldoc" # -- Options for LaTeX output ------------------------------------------------ @@ -123,15 +126,12 @@ def setup(app): # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -141,8 +141,13 @@ def setup(app): # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'RobustArduinoSerialProtocol.tex', 'Robust Arduino Serial Protocol Documentation', - 'Antonin Raffin', 'manual'), + ( + master_doc, + "RobustArduinoSerialProtocol.tex", + "Robust Arduino Serial Protocol Documentation", + "Antonin Raffin", + "manual", + ), ] @@ -150,10 +155,7 @@ def setup(app): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'robustarduinoserialprotocol', 'Robust Arduino Serial Protocol Documentation', - [author], 1) -] +man_pages = [(master_doc, "robustarduinoserialprotocol", "Robust Arduino Serial Protocol Documentation", [author], 1)] # -- Options for Texinfo output ---------------------------------------------- @@ -162,9 +164,15 @@ def setup(app): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'RobustArduinoSerialProtocol', 'Robust Arduino Serial Protocol Documentation', - author, 'RobustArduinoSerialProtocol', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "RobustArduinoSerialProtocol", + "Robust Arduino Serial Protocol Documentation", + author, + "RobustArduinoSerialProtocol", + "One line description of project.", + "Miscellaneous", + ), ] diff --git a/examples/arduino_serial.py b/examples/arduino_serial.py index 3829478..a80b0e8 100644 --- a/examples/arduino_serial.py +++ b/examples/arduino_serial.py @@ -1,12 +1,11 @@ -from __future__ import print_function, division, absolute_import +from __future__ import absolute_import, division, print_function import time -from robust_serial import write_order, Order, write_i8, write_i16, read_i8, read_order +from robust_serial import Order, read_i8, read_order, write_i8, write_i16, write_order from robust_serial.utils import open_serial_port - -if __name__ == '__main__': +if __name__ == "__main__": try: serial_file = open_serial_port(baudrate=115200, timeout=None) except Exception as e: diff --git a/examples/arduino_threads.py b/examples/arduino_threads.py index 6e7d869..f4b03da 100644 --- a/examples/arduino_threads.py +++ b/examples/arduino_threads.py @@ -1,12 +1,11 @@ -from __future__ import print_function, division, absolute_import +from __future__ import absolute_import, division, print_function -import time import threading +import time -from robust_serial import write_order, Order +from robust_serial import Order, write_order from robust_serial.threads import CommandThread, ListenerThread - -from robust_serial.utils import open_serial_port, CustomQueue +from robust_serial.utils import CustomQueue, open_serial_port def reset_command_queue(): @@ -16,7 +15,7 @@ def reset_command_queue(): command_queue.clear() -if __name__ == '__main__': +if __name__ == "__main__": try: serial_file = open_serial_port(baudrate=115200) except Exception as e: @@ -50,8 +49,10 @@ def reset_command_queue(): print("Starting Communication Threads") # Threads for arduino communication - threads = [CommandThread(serial_file, command_queue, exit_event, n_received_semaphore, serial_lock), - ListenerThread(serial_file, exit_event, n_received_semaphore, serial_lock)] + threads = [ + CommandThread(serial_file, command_queue, exit_event, n_received_semaphore, serial_lock), + ListenerThread(serial_file, exit_event, n_received_semaphore, serial_lock), + ] for t in threads: t.start() diff --git a/examples/bluetooth_example.py b/examples/bluetooth_example.py index 713bc08..9c42c35 100644 --- a/examples/bluetooth_example.py +++ b/examples/bluetooth_example.py @@ -1,10 +1,10 @@ -from __future__ import print_function, division +from __future__ import division, print_function import argparse import bluetooth -from robust_serial import write_i8, write_i32, read_i8, read_i32 +from robust_serial import read_i8, read_i32, write_i8, write_i32 CHANNEL = 1 # show mac address: hciconfig @@ -62,13 +62,11 @@ def discover_devices(): print("{} + [{}]".format(bluetooth.lookup_name(bdaddr), bdaddr)) -if __name__ == '__main__': +if __name__ == "__main__": parser = argparse.ArgumentParser(description="Test bluetooth server/client connection") arg_group = parser.add_mutually_exclusive_group(required=True) - arg_group.add_argument("-s", "--server", dest="server", - action='store_true', default=False, help="Create a server") - arg_group.add_argument("-c", "--client", dest="client", - action='store_true', default=False, help="Create a client") + arg_group.add_argument("-s", "--server", dest="server", action="store_true", default=False, help="Create a server") + arg_group.add_argument("-c", "--client", dest="client", action="store_true", default=False, help="Create a client") args = parser.parse_args() if args.server: receive_messages() diff --git a/examples/file_read_write.py b/examples/file_read_write.py index 18f9bf8..3566e65 100644 --- a/examples/file_read_write.py +++ b/examples/file_read_write.py @@ -1,24 +1,23 @@ -from __future__ import print_function, division, absolute_import +from __future__ import absolute_import, division, print_function + import argparse import os -from robust_serial import Order, write_order, write_i8, write_i16, write_i32, read_i8, read_i16, read_i32, read_order - - -if __name__ == '__main__': +from robust_serial import Order, read_i8, read_i16, read_i32, read_order, write_i8, write_i16, write_i32, write_order - parser = argparse.ArgumentParser(description='Reading / Writing a file') - parser.add_argument('-f', '--test_file', help='Test file name', default="test.txt", type=str) +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Reading / Writing a file") + parser.add_argument("-f", "--test_file", help="Test file name", default="test.txt", type=str) args = parser.parse_args() - with open(args.test_file, 'wb') as f: + with open(args.test_file, "wb") as f: write_order(f, Order.HELLO) write_i8(f, Order.MOTOR.value) write_i16(f, -56) write_i32(f, 131072) - with open(args.test_file, 'rb') as f: + with open(args.test_file, "rb") as f: # Equivalent to Order(read_i8(f)) order = read_order(f) print(order) diff --git a/examples/socket_example.py b/examples/socket_example.py index c7e32c8..84f4de9 100644 --- a/examples/socket_example.py +++ b/examples/socket_example.py @@ -1,13 +1,14 @@ -from __future__ import print_function, division +from __future__ import division, print_function import argparse import socket -from robust_serial import write_i8, write_i32, read_i8, read_i32 +from robust_serial import read_i8, read_i32, write_i8, write_i32 PORT = 4444 SERVER_ADDR = "localhost" + class SocketAdapter(object): """ Wrapper around socket object to use the robust_serial lib @@ -33,7 +34,7 @@ def receive_messages(): Receive messages (server side) """ server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.bind(('', PORT)) + server_socket.bind(("", PORT)) print("Waiting for client...") # Wait for client server_socket.listen(1) @@ -73,13 +74,11 @@ def send_messages(server_address): client_socket.close() -if __name__ == '__main__': +if __name__ == "__main__": parser = argparse.ArgumentParser(description="Test socket server/client connection") arg_group = parser.add_mutually_exclusive_group(required=True) - arg_group.add_argument("-s", "--server", dest="server", - action='store_true', default=False, help="Create a server") - arg_group.add_argument("-c", "--client", dest="client", - action='store_true', default=False, help="Create a client") + arg_group.add_argument("-s", "--server", dest="server", action="store_true", default=False, help="Create a server") + arg_group.add_argument("-c", "--client", dest="client", action="store_true", default=False, help="Create a client") args = parser.parse_args() if args.server: receive_messages() diff --git a/robust_serial/__init__.py b/robust_serial/__init__.py index 6a23d8e..12e0b61 100644 --- a/robust_serial/__init__.py +++ b/robust_serial/__init__.py @@ -1,2 +1,3 @@ from .robust_serial import * + __version__ = "0.1" diff --git a/robust_serial/robust_serial.py b/robust_serial/robust_serial.py index c19298f..9d2c26a 100644 --- a/robust_serial/robust_serial.py +++ b/robust_serial/robust_serial.py @@ -1,7 +1,6 @@ -from __future__ import print_function, division, unicode_literals, absolute_import +from __future__ import absolute_import, division, print_function, unicode_literals import struct - from enum import Enum @@ -18,6 +17,7 @@ class Order(Enum): RECEIVED = 5 STOP = 6 + def read_order(f): """ :param f: file handler or serial file @@ -25,12 +25,13 @@ def read_order(f): """ return Order(read_i8(f)) + def read_i8(f): """ :param f: file handler or serial file :return: (int8_t) """ - return struct.unpack(' Date: Mon, 10 Apr 2023 18:43:14 +0200 Subject: [PATCH 09/16] Upgrade to python 3.7 --- docs/conf.py | 1 - examples/arduino_serial.py | 1 - examples/arduino_threads.py | 1 - examples/bluetooth_example.py | 11 +++++------ examples/file_read_write.py | 1 - examples/socket_example.py | 13 ++++++------- robust_serial/robust_serial.py | 13 ++++++------- robust_serial/threads.py | 1 - robust_serial/utils.py | 3 +-- tests/test_read_write.py | 3 +-- 10 files changed, 19 insertions(+), 29 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f90a2db..f1a6729 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # diff --git a/examples/arduino_serial.py b/examples/arduino_serial.py index a80b0e8..0d1e2a6 100644 --- a/examples/arduino_serial.py +++ b/examples/arduino_serial.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import, division, print_function import time diff --git a/examples/arduino_threads.py b/examples/arduino_threads.py index f4b03da..3c732aa 100644 --- a/examples/arduino_threads.py +++ b/examples/arduino_threads.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import, division, print_function import threading import time diff --git a/examples/bluetooth_example.py b/examples/bluetooth_example.py index 9c42c35..2b6d9be 100644 --- a/examples/bluetooth_example.py +++ b/examples/bluetooth_example.py @@ -1,4 +1,3 @@ -from __future__ import division, print_function import argparse @@ -22,15 +21,15 @@ def receive_messages(): server_sock.listen(1) client_sock, client_address = server_sock.accept() - print("Accepted connection from {}".format(client_address)) + print(f"Accepted connection from {client_address}") # Rename function to work with the lib client_sock.read = client_sock.recv for i in range(10): - print("Received (i8): {}".format(read_i8(client_sock))) + print(f"Received (i8): {read_i8(client_sock)}") big_number = read_i32(client_sock) - print("Received (i32): {}".format(big_number)) + print(f"Received (i32): {big_number}") client_sock.close() server_sock.close() @@ -44,7 +43,7 @@ def send_messages(mac_address): socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM) socket.connect((mac_address, CHANNEL)) - print("Connected to {}".format(mac_address)) + print(f"Connected to {mac_address}") # Rename function to work with the lib socket.write = socket.send for i in range(10): @@ -59,7 +58,7 @@ def discover_devices(): """ nearby_devices = bluetooth.discover_devices() for bdaddr in nearby_devices: - print("{} + [{}]".format(bluetooth.lookup_name(bdaddr), bdaddr)) + print(f"{bluetooth.lookup_name(bdaddr)} + [{bdaddr}]") if __name__ == "__main__": diff --git a/examples/file_read_write.py b/examples/file_read_write.py index 3566e65..db497e1 100644 --- a/examples/file_read_write.py +++ b/examples/file_read_write.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import, division, print_function import argparse import os diff --git a/examples/socket_example.py b/examples/socket_example.py index 84f4de9..6d13d91 100644 --- a/examples/socket_example.py +++ b/examples/socket_example.py @@ -1,4 +1,3 @@ -from __future__ import division, print_function import argparse import socket @@ -9,14 +8,14 @@ SERVER_ADDR = "localhost" -class SocketAdapter(object): +class SocketAdapter: """ Wrapper around socket object to use the robust_serial lib It just renames recv() to read() and send() to write() """ def __init__(self, client_socket): - super(SocketAdapter, self).__init__() + super().__init__() self.client_socket = client_socket def read(self, num_bytes): @@ -40,15 +39,15 @@ def receive_messages(): server_socket.listen(1) client_sock, client_address = server_socket.accept() - print("Accepted connection from {}".format(client_address)) + print(f"Accepted connection from {client_address}") # Wrap socket to work with the lib client_sock = SocketAdapter(client_sock) for i in range(10): - print("Received (i8): {}".format(read_i8(client_sock))) + print(f"Received (i8): {read_i8(client_sock)}") big_number = read_i32(client_sock) - print("Received (i32): {}".format(big_number)) + print(f"Received (i32): {big_number}") print("Server exiting...") client_sock.close() @@ -66,7 +65,7 @@ def send_messages(server_address): # Wrap socket to work with the lib client_socket = SocketAdapter(client_socket) - print("Connected to {}".format(server_address)) + print(f"Connected to {server_address}") for i in range(10): write_i8(client_socket, i) write_i32(client_socket, 32768) diff --git a/robust_serial/robust_serial.py b/robust_serial/robust_serial.py index 9d2c26a..ff5a44d 100644 --- a/robust_serial/robust_serial.py +++ b/robust_serial/robust_serial.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import, division, print_function, unicode_literals import struct from enum import Enum @@ -58,7 +57,7 @@ def write_i8(f, value): if -128 <= value <= 127: f.write(struct.pack(" Date: Mon, 10 Apr 2023 19:02:21 +0200 Subject: [PATCH 10/16] Upgrade to python 3.8+ --- .coverage | Bin 53248 -> 53248 bytes .github/workflows/ci.yml | 2 +- README.md | 4 ++-- docs/conf.py | 12 ++++++------ docs/index.rst | 2 +- examples/arduino_serial.py | 3 +-- examples/arduino_threads.py | 1 - examples/bluetooth_example.py | 3 +-- examples/file_read_write.py | 3 +-- examples/socket_example.py | 3 +-- pyproject.toml | 4 ++-- robust_serial/__init__.py | 28 ++++++++++++++++++++++++++-- robust_serial/robust_serial.py | 18 +++++++++--------- robust_serial/threads.py | 1 - robust_serial/utils.py | 29 +++++++++++++++-------------- setup.py | 14 +++----------- tests/test_read_write.py | 1 - 17 files changed, 69 insertions(+), 59 deletions(-) diff --git a/.coverage b/.coverage index 445cf5296e939ba42e1c13d72d71faffb9c16e05..bffb90ebdfa092effca71e96838e961ef75476c8 100644 GIT binary patch delta 52 zcmZozz}&Eac>`Mm+fxSq@BB|U3kuximlj}RVdPX|I`>0Z2ngCHOqjsV$im4f#N@!Z HXo3R(wCfJJ delta 50 zcmZozz}&Eac>`Mm+j9o~pZw1^3kuxkmlR-PVdPX|(t4~fA|xc#Hetd9Rz?<1PCm9p G6C41IhYjHX diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b58ce54..eb651d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10"] + python-version: ["3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v3 diff --git a/README.md b/README.md index 01d1b93..859bd96 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **Robust Arduino Serial** is a simple and robust serial communication protocol. It was designed to make two arduinos communicate, but can also be useful when you want a computer (e.g. a Raspberry Pi) to communicate with an Arduino. -It supports both Python 2 and 3. +It supports Python 3.8+. This repository is part of the Robust Arduino Serial project, main repository: [https://github.com/araffin/arduino-robust-serial](https://github.com/araffin/arduino-robust-serial) @@ -35,7 +35,7 @@ pip install -e . ## Tests Run the tests (require pytest): ``` -pytest +make pytest ``` ## Examples diff --git a/docs/conf.py b/docs/conf.py index f1a6729..c5e39df 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -13,15 +13,16 @@ # import os import sys +from typing import Dict sys.path.insert(0, os.path.abspath("..")) -import robust_serial +import robust_serial # noqa: E402 # -- Project information ----------------------------------------------------- project = "Robust Arduino Serial Protocol" -copyright = "2018, Antonin Raffin" +copyright = "2018-2023, Antonin Raffin" author = "Antonin Raffin" # The short X.Y version @@ -29,7 +30,6 @@ # The full version, including alpha/beta/rc tags release = robust_serial.__version__ - # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. @@ -63,7 +63,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -88,7 +88,7 @@ def setup(app): - app.add_stylesheet("css/custom_theme.css") + app.add_css_file("css/custom_theme.css") # Theme options are theme-specific and customize the look and feel of a theme @@ -121,7 +121,7 @@ def setup(app): # -- Options for LaTeX output ------------------------------------------------ -latex_elements = { +latex_elements: Dict[str, str] = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', diff --git a/docs/index.rst b/docs/index.rst index 8db022a..6c41c77 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -11,7 +11,7 @@ protocol. It was designed to make two arduinos communicate, but can also be useful when you want a computer (e.g. a Raspberry Pi) to communicate with an Arduino. -It supports both Python 2 and 3. +It supports both Python 3.8+. This repository is part of the Robust Arduino Serial project, main repository: `https://github.com/araffin/arduino-robust-serial`_ diff --git a/examples/arduino_serial.py b/examples/arduino_serial.py index 0d1e2a6..6390e0a 100644 --- a/examples/arduino_serial.py +++ b/examples/arduino_serial.py @@ -1,7 +1,6 @@ - import time -from robust_serial import Order, read_i8, read_order, write_i8, write_i16, write_order +from robust_serial import Order, read_order, write_i8, write_i16, write_order from robust_serial.utils import open_serial_port if __name__ == "__main__": diff --git a/examples/arduino_threads.py b/examples/arduino_threads.py index 3c732aa..fe10eb1 100644 --- a/examples/arduino_threads.py +++ b/examples/arduino_threads.py @@ -1,4 +1,3 @@ - import threading import time diff --git a/examples/bluetooth_example.py b/examples/bluetooth_example.py index 2b6d9be..d0f43f1 100644 --- a/examples/bluetooth_example.py +++ b/examples/bluetooth_example.py @@ -1,4 +1,3 @@ - import argparse import bluetooth @@ -25,7 +24,7 @@ def receive_messages(): # Rename function to work with the lib client_sock.read = client_sock.recv - for i in range(10): + for _ in range(10): print(f"Received (i8): {read_i8(client_sock)}") big_number = read_i32(client_sock) diff --git a/examples/file_read_write.py b/examples/file_read_write.py index db497e1..e862ed7 100644 --- a/examples/file_read_write.py +++ b/examples/file_read_write.py @@ -1,8 +1,7 @@ - import argparse import os -from robust_serial import Order, read_i8, read_i16, read_i32, read_order, write_i8, write_i16, write_i32, write_order +from robust_serial import Order, read_i16, read_i32, read_order, write_i8, write_i16, write_i32, write_order if __name__ == "__main__": parser = argparse.ArgumentParser(description="Reading / Writing a file") diff --git a/examples/socket_example.py b/examples/socket_example.py index 6d13d91..1e6c1cf 100644 --- a/examples/socket_example.py +++ b/examples/socket_example.py @@ -1,4 +1,3 @@ - import argparse import socket @@ -43,7 +42,7 @@ def receive_messages(): # Wrap socket to work with the lib client_sock = SocketAdapter(client_sock) - for i in range(10): + for _ in range(10): print(f"Received (i8): {read_i8(client_sock)}") big_number = read_i32(client_sock) diff --git a/pyproject.toml b/pyproject.toml index 1f2b430..849fbc9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,8 @@ [tool.ruff] # Same as Black. line-length = 127 -# Assume Python 3.7 -target-version = "py37" +# Assume Python 3.8 +target-version = "py38" # See https://beta.ruff.rs/docs/rules/ select = ["E", "F", "B", "UP", "C90", "RUF"] # Ignore explicit stacklevel` diff --git a/robust_serial/__init__.py b/robust_serial/__init__.py index 12e0b61..a8d6dca 100644 --- a/robust_serial/__init__.py +++ b/robust_serial/__init__.py @@ -1,3 +1,27 @@ -from .robust_serial import * +from robust_serial.robust_serial import ( + Order, + decode_order, + read_i8, + read_i16, + read_i32, + read_order, + write_i8, + write_i16, + write_i32, + write_order, +) -__version__ = "0.1" +__version__ = "0.2" + +__all__ = [ + "Order", + "read_order", + "read_i8", + "read_i16", + "read_i32", + "write_i8", + "write_order", + "write_i16", + "write_i32", + "decode_order", +] diff --git a/robust_serial/robust_serial.py b/robust_serial/robust_serial.py index ff5a44d..ad98a7b 100644 --- a/robust_serial/robust_serial.py +++ b/robust_serial/robust_serial.py @@ -1,6 +1,6 @@ - import struct from enum import Enum +from typing import BinaryIO class Order(Enum): @@ -17,7 +17,7 @@ class Order(Enum): STOP = 6 -def read_order(f): +def read_order(f: BinaryIO) -> Order: """ :param f: file handler or serial file :return: (Order Enum Object) @@ -25,7 +25,7 @@ def read_order(f): return Order(read_i8(f)) -def read_i8(f): +def read_i8(f: BinaryIO) -> Order: """ :param f: file handler or serial file :return: (int8_t) @@ -33,7 +33,7 @@ def read_i8(f): return struct.unpack(" Order: """ :param f: file handler or serial file :return: (int16_t) @@ -49,7 +49,7 @@ def read_i32(f): return struct.unpack(" None: """ :param f: file handler or serial file :param value: (int8_t) @@ -60,7 +60,7 @@ def write_i8(f, value): print(f"Value error:{value}") -def write_order(f, order): +def write_order(f: BinaryIO, order: Order) -> None: """ :param f: file handler or serial file :param order: (Order Enum Object) @@ -68,7 +68,7 @@ def write_order(f, order): write_i8(f, order.value) -def write_i16(f, value): +def write_i16(f: BinaryIO, value: int) -> None: """ :param f: file handler or serial file :param value: (int16_t) @@ -76,7 +76,7 @@ def write_i16(f, value): f.write(struct.pack(" None: """ :param f: file handler or serial file :param value: (int32_t) @@ -84,7 +84,7 @@ def write_i32(f, value): f.write(struct.pack(" None: """ :param f: file handler or serial file :param byte: (int8_t) diff --git a/robust_serial/threads.py b/robust_serial/threads.py index a158f9f..4db8906 100644 --- a/robust_serial/threads.py +++ b/robust_serial/threads.py @@ -1,4 +1,3 @@ - import threading import time diff --git a/robust_serial/utils.py b/robust_serial/utils.py index 8cb248a..67a02dd 100644 --- a/robust_serial/utils.py +++ b/robust_serial/utils.py @@ -1,11 +1,7 @@ - import glob +import queue import sys - -try: - import queue -except ImportError: - import Queue as queue +from typing import List, Optional import serial @@ -16,7 +12,7 @@ class CustomQueue(queue.Queue): A custom queue subclass that provides a :meth:`clear` method. """ - def clear(self): + def clear(self) -> None: """ Clears all items from the queue. """ @@ -33,12 +29,12 @@ def clear(self): # From https://stackoverflow.com/questions/12090503/listing-available-com-ports-with-python -def get_serial_ports(): +def get_serial_ports() -> List[str]: """ Lists serial ports. - :return: ([str]) A list of available serial ports + :return: A list of available serial ports """ if sys.platform.startswith("win"): ports = ["COM%s" % (i + 1) for i in range(256)] @@ -61,15 +57,20 @@ def get_serial_ports(): return results -def open_serial_port(serial_port=None, baudrate=115200, timeout=0, write_timeout=0): +def open_serial_port( + serial_port: Optional[str] = None, + baudrate: int = 115200, + timeout: Optional[int] = 0, + write_timeout: int = 0, +) -> serial.Serial: """ Try to open serial port with Arduino If not port is specified, it will be automatically detected - :param serial_port: (str) - :param baudrate: (int) - :param timeout: (int) None -> blocking mode - :param write_timeout: (int) + :param serial_port: + :param baudrate: + :param timeout: None -> blocking mode + :param write_timeout: :return: (Serial Object) """ # Open serial port (for communication with Arduino) diff --git a/setup.py b/setup.py index c125038..cdf793a 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,9 @@ from setuptools import find_packages, setup -# Create Package -# rm dist/* -# python setup.py sdist -# python setup.py bdist_wheel -# Upload -# (test) twine upload --repository-url https://test.pypi.org/legacy/ dist/* -# (release) twine upload dist/* - long_description = """ Robust Arduino Serial is a simple and robust serial communication protocol. -It was designed to make two arduinos communicate, but can also be useful when you want a computer (e.g. a Raspberry Pi) to communicate with an Arduino. +It was designed to make two arduinos communicate, +but can also be useful when you want a computer (e.g. a Raspberry Pi) to communicate with an Arduino. https://medium.com/@araffin/simple-and-robust-computer-arduino-serial-communication-f91b95596788 """ @@ -29,10 +22,9 @@ keywords="serial hardware arduino RS232 communication protocol raspberry", license="MIT", version="0.2", - python_requires=">=3.7", + python_requires=">=3.8", classifiers=[ "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", diff --git a/tests/test_read_write.py b/tests/test_read_write.py index f74a6c0..0d2ea2c 100644 --- a/tests/test_read_write.py +++ b/tests/test_read_write.py @@ -1,4 +1,3 @@ - from tempfile import TemporaryFile from robust_serial import Order, read_i8, read_i16, read_i32, read_order, write_i8, write_i16, write_i32, write_order From ecd8bbc898d059871d4d5de7bfd40866b191d11f Mon Sep 17 00:00:00 2001 From: Antonin Raffin Date: Mon, 10 Apr 2023 19:04:28 +0200 Subject: [PATCH 11/16] Update badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 859bd96..1e2549d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Robust Arduino Serial Protocol in Python -[![Build Status](https://travis-ci.org/araffin/python-arduino-serial.svg?branch=master)](https://travis-ci.org/araffin/python-arduino-serial) [![Documentation Status](https://readthedocs.org/projects/python-arduino-serial/badge/?version=latest)](https://python-arduino-serial.readthedocs.io/en/latest/?badge=latest) +![CI](https://github.com/araffin/python-arduino-serial/workflows/CI/badge.svg) [![Documentation Status](https://readthedocs.org/projects/python-arduino-serial/badge/?version=latest)](https://python-arduino-serial.readthedocs.io/en/latest/?badge=latest) **Robust Arduino Serial** is a simple and robust serial communication protocol. It was designed to make two arduinos communicate, but can also be useful when you want a computer (e.g. a Raspberry Pi) to communicate with an Arduino. From c2ab090902822c51a343aa9a561036ef30fce360 Mon Sep 17 00:00:00 2001 From: Antonin Raffin Date: Mon, 10 Apr 2023 19:06:30 +0200 Subject: [PATCH 12/16] Add missing test dep --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index cdf793a..cb2dde9 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ install_requires=[ "pyserial", ], - tests_require=["pytest", "pytest-cov", "mypy"], + tests_require=["pytest", "pytest-cov", "mypy", "ruff", "black", "isort"], author="Antonin RAFFIN", author_email="antonin.raffin@ensta.org", url="https://github.com/araffin/arduino-robust-serial", From bebe66012e5b6ebfc1cab77a1530bad40a50a69a Mon Sep 17 00:00:00 2001 From: Antonin Raffin Date: Mon, 10 Apr 2023 19:09:10 +0200 Subject: [PATCH 13/16] Fix extras --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb651d4..77bbb56 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install .[tests] + pip install .[test] - name: Lint with ruff run: | make lint From b624fa868c5801f29f4f522062fbe9c7472c3937 Mon Sep 17 00:00:00 2001 From: Antonin Raffin Date: Mon, 10 Apr 2023 19:10:48 +0200 Subject: [PATCH 14/16] Use extra requires --- .github/workflows/ci.yml | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 77bbb56..eb651d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install .[test] + pip install .[tests] - name: Lint with ruff run: | make lint diff --git a/setup.py b/setup.py index cb2dde9..0ae678e 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ install_requires=[ "pyserial", ], - tests_require=["pytest", "pytest-cov", "mypy", "ruff", "black", "isort"], + extras_require={"tests": ["pytest", "pytest-cov", "mypy", "ruff", "black", "isort"]}, author="Antonin RAFFIN", author_email="antonin.raffin@ensta.org", url="https://github.com/araffin/arduino-robust-serial", From d5842417377daac96a7ed9be544b0b6929ec654e Mon Sep 17 00:00:00 2001 From: Antonin Raffin Date: Mon, 10 Apr 2023 19:13:48 +0200 Subject: [PATCH 15/16] Add doc extras --- setup.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0ae678e..5345abe 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,10 @@ install_requires=[ "pyserial", ], - extras_require={"tests": ["pytest", "pytest-cov", "mypy", "ruff", "black", "isort"]}, + extras_require={ + "tests": ["pytest", "pytest-cov", "mypy", "ruff", "black", "isort"], + "docs": ["sphinx", "sphinx_rtd_theme", "sphinx-autodoc-typehints"], + }, author="Antonin RAFFIN", author_email="antonin.raffin@ensta.org", url="https://github.com/araffin/arduino-robust-serial", From 6f823e33a2439cad952aa3dd1941c660480de468 Mon Sep 17 00:00:00 2001 From: Antonin Raffin Date: Mon, 10 Apr 2023 19:14:49 +0200 Subject: [PATCH 16/16] Fix CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb651d4..6d0a4b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install .[tests] + pip install .[tests,docs] - name: Lint with ruff run: | make lint