Compare commits

..

No commits in common. "master" and "examplecodepr" have entirely different histories.

14 changed files with 216 additions and 398 deletions

View file

@ -1,57 +0,0 @@
name: Build CI
on: [pull_request, push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Translate Repo Name For Build Tools filename_prefix
id: repo-name
run: |
echo ::set-output name=repo-name::$(
echo ${{ github.repository }} |
awk -F '\/' '{ print tolower($2) }' |
tr '_' '-'
)
- name: Set up Python 3.6
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Versions
run: |
python3 --version
- name: Checkout Current Repo
uses: actions/checkout@v1
with:
submodules: true
- name: Checkout tools repo
uses: actions/checkout@v2
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install dependencies
# (e.g. - apt-get: gettext, etc; pip: circuitpython-build-tools, requirements.txt; etc.)
run: |
source actions-ci/install.sh
- name: Pip install pylint, black, & Sphinx
run: |
pip install --force-reinstall pylint black==19.10b0 Sphinx sphinx-rtd-theme
- name: Library version
run: git describe --dirty --always --tags
- name: Check formatting
run: |
black --check --target-version=py35 .
- name: PyLint
run: |
pylint $( find . -path './adafruit*.py' )
([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace $( find . -path "./examples/*.py" ))
- name: Build assets
run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location .
- name: Build docs
working-directory: docs
run: sphinx-build -E -W -b html . _build/html

View file

@ -1,81 +0,0 @@
name: Release Actions
on:
release:
types: [published]
jobs:
upload-release-assets:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Translate Repo Name For Build Tools filename_prefix
id: repo-name
run: |
echo ::set-output name=repo-name::$(
echo ${{ github.repository }} |
awk -F '\/' '{ print tolower($2) }' |
tr '_' '-'
)
- name: Set up Python 3.6
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Versions
run: |
python3 --version
- name: Checkout Current Repo
uses: actions/checkout@v1
with:
submodules: true
- name: Checkout tools repo
uses: actions/checkout@v2
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install deps
run: |
source actions-ci/install.sh
- name: Build assets
run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location .
- name: Upload Release Assets
# the 'official' actions version does not yet support dynamically
# supplying asset names to upload. @csexton's version chosen based on
# discussion in the issue below, as its the simplest to implement and
# allows for selecting files with a pattern.
# https://github.com/actions/upload-release-asset/issues/4
#uses: actions/upload-release-asset@v1.0.1
uses: csexton/release-asset-action@master
with:
pattern: "bundles/*"
github-token: ${{ secrets.GITHUB_TOKEN }}
upload-pypi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Check For setup.py
id: need-pypi
run: |
echo ::set-output name=setup-py::$( find . -wholename './setup.py' )
- name: Set up Python
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
uses: actions/setup-python@v1
with:
python-version: '3.x'
- name: Install dependencies
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
env:
TWINE_USERNAME: ${{ secrets.pypi_username }}
TWINE_PASSWORD: ${{ secrets.pypi_password }}
run: |
python setup.py sdist
twine upload dist/*

7
.gitignore vendored
View file

@ -1,11 +1,6 @@
*.mpy
.idea
__pycache__
_build
*.pyc
.env
build*
bundles
*.DS_Store
.eggs
dist
**/*.egg-info

View file

@ -52,7 +52,7 @@ confidence=
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option

34
.travis.yml Normal file
View file

@ -0,0 +1,34 @@
# This is a common .travis.yml for generating library release zip files for
# CircuitPython library releases using circuitpython-build-tools.
# See https://github.com/adafruit/circuitpython-build-tools for detailed setup
# instructions.
dist: trusty
sudo: false
language: python
python:
- "3.6"
cache:
pip: true
deploy:
provider: releases
api_key: $GITHUB_TOKEN
file_glob: true
file: $TRAVIS_BUILD_DIR/bundles/*
skip_cleanup: true
overwrite: true
on:
tags: true
install:
- pip install -r requirements.txt
- pip install circuitpython-build-tools Sphinx sphinx-rtd-theme
- pip install --force-reinstall pylint==1.9.2
script:
- pylint adafruit_bluefruitspi.py
- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace examples/*.py)
- circuitpython-build-bundles --filename_prefix adafruit-circuitpython-bluefruitspi --library_location .
- cd docs && sphinx-build -E -W -b html . _build/html

View file

@ -34,8 +34,6 @@ Examples of unacceptable behavior by participants include:
* Excessive or unwelcome helping; answering outside the scope of the question
asked
* Trolling, insulting/derogatory comments, and personal or political attacks
* Promoting or spreading disinformation, lies, or conspiracy theories against
a person, group, organisation, project, or community
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
@ -74,10 +72,10 @@ You may report in the following ways:
In any situation, you may send an email to <support@adafruit.com>.
On the Adafruit Discord, you may send an open message from any channel
to all Community Moderators by tagging @community moderators. You may
also send an open message from any channel, or a direct message to
@kattni#1507, @tannewt#4653, @Dan Halbert#1614, @cater#2442,
@sommersoft#0222, @Mr. Certainly#0472 or @Andon#8175.
to all Community Helpers by tagging @community helpers. You may also send an
open message from any channel, or a direct message to @kattni#1507,
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
@Andon#8175.
Email and direct message reports will be kept confidential.

View file

@ -6,11 +6,11 @@ Introduction
:alt: Documentation Status
.. image:: https://img.shields.io/discord/327254708534116352.svg
:target: https://adafru.it/discord
:target: https://discord.gg/nBQh6qu
:alt: Discord
.. image:: https://github.com/adafruit/Adafruit_CircuitPython_BluefruitSPI/workflows/Build%20CI/badge.svg
:target: https://github.com/adafruit/Adafruit_CircuitPython_BluefruitSPI/actions/
.. image:: https://travis-ci.org/adafruit/Adafruit_CircuitPython_BluefruitSPI.svg?branch=master
:target: https://travis-ci.org/adafruit/Adafruit_CircuitPython_BluefruitSPI
:alt: Build Status
Helper class to work with the Adafruit Bluefruit LE SPI Friend.
@ -26,31 +26,6 @@ Please ensure all dependencies are available on the CircuitPython filesystem.
This is easily achieved by downloading
`the Adafruit library and driver bundle <https://github.com/adafruit/Adafruit_CircuitPython_Bundle>`_.
Installing from PyPI
====================
On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
PyPI <https://pypi.org/project/adafruit-circuitpython-bluefruitspi/>`_. To install for current user:
.. code-block:: shell
pip3 install adafruit-circuitpython-bluefruitspi
To install system-wide (this may be required in some cases):
.. code-block:: shell
sudo pip3 install adafruit-circuitpython-bluefruitspi
To install in a virtual environment in your current project:
.. code-block:: shell
mkdir project-name && cd project-name
python3 -m venv .env
source .env/bin/activate
pip3 install adafruit-circuitpython-bluefruitspi
Usage Example
=============
@ -125,7 +100,52 @@ Contributions are welcome! Please read our `Code of Conduct
<https://github.com/adafruit/Adafruit_CircuitPython_BluefruitSPI/blob/master/CODE_OF_CONDUCT.md>`_
before contributing to help this project stay welcoming.
Documentation
=============
Building locally
================
For information on building library documentation, please check out `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.
Zip release files
-----------------
To build this library locally you'll need to install the
`circuitpython-build-tools <https://github.com/adafruit/circuitpython-build-tools>`_ package.
.. code-block:: shell
python3 -m venv .env
source .env/bin/activate
pip install circuitpython-build-tools
Once installed, make sure you are in the virtual environment:
.. code-block:: shell
source .env/bin/activate
Then run the build:
.. code-block:: shell
circuitpython-build-bundles --filename_prefix adafruit-circuitpython-bluefruitspi --library_location .
Sphinx documentation
-----------------------
Sphinx is used to build the documentation based on rST files and comments in the code. First,
install dependencies (feel free to reuse the virtual environment from above):
.. code-block:: shell
python3 -m venv .env
source .env/bin/activate
pip install Sphinx sphinx-rtd-theme
Now, once you have the virtual environment activated:
.. code-block:: shell
cd docs
sphinx-build -E -W -b html . _build/html
This will output the documentation to ``docs/_build/html``. Open the index.html in your browser to
view them. It will also (due to -W) error out on any warning like Travis will. This is a good way to
locally verify it will pass.

View file

@ -52,37 +52,37 @@ from adafruit_bus_device.spi_device import SPIDevice
from micropython import const
# pylint: disable=bad-whitespace
_MSG_COMMAND = const(0x10) # Command message
_MSG_RESPONSE = const(0x20) # Response message
_MSG_ALERT = const(0x40) # Alert message
_MSG_ERROR = const(0x80) # Error message
_MSG_COMMAND = const(0x10) # Command message
_MSG_RESPONSE = const(0x20) # Response message
_MSG_ALERT = const(0x40) # Alert message
_MSG_ERROR = const(0x80) # Error message
_SDEP_INITIALIZE = const(0xBEEF) # Resets the Bluefruit device
_SDEP_ATCOMMAND = const(0x0A00) # AT command wrapper
_SDEP_BLEUART_TX = const(0x0A01) # BLE UART transmit data
_SDEP_BLEUART_RX = const(0x0A02) # BLE UART read data
_SDEP_INITIALIZE = const(0xBEEF) # Resets the Bluefruit device
_SDEP_ATCOMMAND = const(0x0A00) # AT command wrapper
_SDEP_BLEUART_TX = const(0x0A01) # BLE UART transmit data
_SDEP_BLEUART_RX = const(0x0A02) # BLE UART read data
_ARG_STRING = const(0x0100) # String data type
_ARG_BYTEARRAY = const(0x0200) # Byte array data type
_ARG_INT32 = const(0x0300) # Signed 32-bit integer data type
_ARG_UINT32 = const(0x0400) # Unsigned 32-bit integer data type
_ARG_INT16 = const(0x0500) # Signed 16-bit integer data type
_ARG_UINT16 = const(0x0600) # Unsigned 16-bit integer data type
_ARG_INT8 = const(0x0700) # Signed 8-bit integer data type
_ARG_UINT8 = const(0x0800) # Unsigned 8-bit integer data type
_ARG_STRING = const(0x0100) # String data type
_ARG_BYTEARRAY = const(0x0200) # Byte array data type
_ARG_INT32 = const(0x0300) # Signed 32-bit integer data type
_ARG_UINT32 = const(0x0400) # Unsigned 32-bit integer data type
_ARG_INT16 = const(0x0500) # Signed 16-bit integer data type
_ARG_UINT16 = const(0x0600) # Unsigned 16-bit integer data type
_ARG_INT8 = const(0x0700) # Signed 8-bit integer data type
_ARG_UINT8 = const(0x0800) # Unsigned 8-bit integer data type
_ERROR_INVALIDMSGTYPE = const(0x8021) # SDEP: Unexpected SDEP MsgType
_ERROR_INVALIDCMDID = const(0x8022) # SDEP: Unknown command ID
_ERROR_INVALIDPAYLOAD = const(0x8023) # SDEP: Payload problem
_ERROR_INVALIDLEN = const(0x8024) # SDEP: Indicated len too large
_ERROR_INVALIDINPUT = const(0x8060) # AT: Invalid data
_ERROR_UNKNOWNCMD = const(0x8061) # AT: Unknown command name
_ERROR_INVALIDPARAM = const(0x8062) # AT: Invalid param value
_ERROR_UNSUPPORTED = const(0x8063) # AT: Unsupported command
_ERROR_INVALIDMSGTYPE = const(0x8021) # SDEP: Unexpected SDEP MsgType
_ERROR_INVALIDCMDID = const(0x8022) # SDEP: Unknown command ID
_ERROR_INVALIDPAYLOAD = const(0x8023) # SDEP: Payload problem
_ERROR_INVALIDLEN = const(0x8024) # SDEP: Indicated len too large
_ERROR_INVALIDINPUT = const(0x8060) # AT: Invalid data
_ERROR_UNKNOWNCMD = const(0x8061) # AT: Unknown command name
_ERROR_INVALIDPARAM = const(0x8062) # AT: Invalid param value
_ERROR_UNSUPPORTED = const(0x8063) # AT: Unsupported command
# For the Bluefruit Connect packets
_PACKET_BUTTON_LEN = const(5)
_PACKET_COLOR_LEN = const(6)
_PACKET_BUTTON_LEN = const(5)
_PACKET_COLOR_LEN = const(6)
# pylint: enable=bad-whitespace
@ -90,9 +90,7 @@ _PACKET_COLOR_LEN = const(6)
class BluefruitSPI:
"""Helper for the Bluefruit LE SPI Friend"""
def __init__(
self, spi, cs, irq, reset, debug=False
): # pylint: disable=too-many-arguments
def __init__(self, spi, cs, irq, reset, debug=False): # pylint: disable=too-many-arguments
self._irq = irq
self._buf_tx = bytearray(20)
self._buf_rx = bytearray(20)
@ -116,7 +114,8 @@ class BluefruitSPI:
self._irq.direction = Direction.INPUT
self._irq.pull = Pull.DOWN
self._spi_device = SPIDevice(spi, cs, baudrate=4000000, phase=0, polarity=0)
self._spi_device = SPIDevice(spi, cs,
baudrate=4000000, phase=0, polarity=0)
def _cmd(self, cmd): # pylint: disable=too-many-branches
"""
@ -130,9 +129,9 @@ class BluefruitSPI:
if len(cmd) > 127:
if self._debug:
print("ERROR: Command too long.")
raise ValueError("Command too long.")
raise ValueError('Command too long.')
more = 0x80 # More bit is in pos 8, 1 = more data available
more = 0x80 # More bit is in pos 8, 1 = more data available
pos = 0
while len(cmd) - pos:
# Construct the SDEP packet
@ -143,15 +142,9 @@ class BluefruitSPI:
if plen > 16:
plen = 16
# Note the 'more' value in bit 8 of the packet len
struct.pack_into(
"<BHB16s",
self._buf_tx,
0,
_MSG_COMMAND,
_SDEP_ATCOMMAND,
plen | more,
cmd[pos : pos + plen],
)
struct.pack_into("<BHB16s", self._buf_tx, 0,
_MSG_COMMAND, _SDEP_ATCOMMAND,
plen | more, cmd[pos:pos+plen])
if self._debug:
print("Writing: ", [hex(b) for b in self._buf_tx])
else:
@ -162,7 +155,7 @@ class BluefruitSPI:
# Send out the SPI bus
with self._spi_device as spi:
spi.write(self._buf_tx, end=len(cmd) + 4) # pylint: disable=no-member
spi.write(self._buf_tx, end=len(cmd) + 4) # pylint: disable=no-member
# Wait up to 200ms for a response
timeout = 0.2
@ -172,7 +165,7 @@ class BluefruitSPI:
if timeout <= 0:
if self._debug:
print("ERROR: Timed out waiting for a response.")
raise RuntimeError("Timed out waiting for a response.")
raise RuntimeError('Timed out waiting for a response.')
# Retrieve the response message
msgtype = 0
@ -186,11 +179,11 @@ class BluefruitSPI:
spi.readinto(self._buf_rx)
# Read the message envelope and contents
msgtype, rspid, rsplen = struct.unpack(">BHB", self._buf_rx[0:4])
msgtype, rspid, rsplen = struct.unpack('>BHB', self._buf_rx)
if rsplen >= 16:
rsp += self._buf_rx[4:20]
else:
rsp += self._buf_rx[4 : rsplen + 4]
rsp += self._buf_rx[4:rsplen+4]
if self._debug:
print("Reading: ", [hex(b) for b in self._buf_rx])
else:
@ -207,13 +200,14 @@ class BluefruitSPI:
This command should complete in under 1s.
"""
# Construct the SDEP packet
struct.pack_into("<BHB", self._buf_tx, 0, _MSG_COMMAND, _SDEP_INITIALIZE, 0)
struct.pack_into("<BHB", self._buf_tx, 0,
_MSG_COMMAND, _SDEP_INITIALIZE, 0)
if self._debug:
print("Writing: ", [hex(b) for b in self._buf_tx])
# Send out the SPI bus
with self._spi_device as spi:
spi.write(self._buf_tx, end=4) # pylint: disable=no-member
spi.write(self._buf_tx, end=4) # pylint: disable=no-member
# Wait 1 second for the command to complete.
time.sleep(1)
@ -221,20 +215,20 @@ class BluefruitSPI:
@property
def connected(self):
"""Whether the Bluefruit module is connected to the central"""
return int(self.command_check_OK(b"AT+GAPGETCONN")) == 1
return int(self.command_check_OK(b'AT+GAPGETCONN')) == 1
def uart_tx(self, data):
"""
Sends the specific bytestring out over BLE UART.
:param data: The bytestring to send.
"""
return self._cmd(b"AT+BLEUARTTX=" + data + b"\r\n")
return self._cmd(b'AT+BLEUARTTX='+data+b'\r\n')
def uart_rx(self):
"""
Reads byte data from the BLE UART FIFO.
"""
data = self.command_check_OK(b"AT+BLEUARTRX")
data = self.command_check_OK(b'AT+BLEUARTRX')
if data:
# remove \r\n from ending
return data[:-2]
@ -243,29 +237,30 @@ class BluefruitSPI:
def command(self, string):
"""Send a command and check response code"""
try:
msgtype, msgid, rsp = self._cmd(string + "\n")
msgtype, msgid, rsp = self._cmd(string+"\n")
if msgtype == _MSG_ERROR:
raise RuntimeError("Error (id:{0})".format(hex(msgid)))
if msgtype == _MSG_RESPONSE:
return rsp
raise RuntimeError("Unknown response (id:{0})".format(hex(msgid)))
else:
raise RuntimeError("Unknown response (id:{0})".format(hex(msgid)))
except RuntimeError as error:
raise RuntimeError("AT command failure: " + repr(error))
def command_check_OK(self, command, delay=0.0): # pylint: disable=invalid-name
def command_check_OK(self, command, delay=0.0): # pylint: disable=invalid-name
"""Send a fully formed bytestring AT command, and check
whether we got an 'OK' back. Returns payload bytes if there is any"""
ret = self.command(command)
time.sleep(delay)
if not ret or not ret[-4:]:
raise RuntimeError("Not OK")
if ret[-4:] != b"OK\r\n":
if ret[-4:] != b'OK\r\n':
raise RuntimeError("Not OK")
if ret[:-4]:
return ret[:-4]
return None
def read_packet(self): # pylint: disable=too-many-return-statements
def read_packet(self): # pylint: disable=too-many-return-statements
"""
Will read a Bluefruit Connect packet and return it in a parsed format.
Currently supports Button and Color packets only
@ -276,16 +271,16 @@ class BluefruitSPI:
# convert to an array of character bytes
self._buffer += [chr(b) for b in data]
# Find beginning of new packet, starts with a '!'
while self._buffer and self._buffer[0] != "!":
while self._buffer and self._buffer[0] != '!':
self._buffer.pop(0)
# we need at least 2 bytes in the buffer
if len(self._buffer) < 2:
return None
# Packet beginning found
if self._buffer[1] == "B":
if self._buffer[1] == 'B':
plen = _PACKET_BUTTON_LEN
elif self._buffer[1] == "C":
elif self._buffer[1] == 'C':
plen = _PACKET_COLOR_LEN
else:
# unknown packet type
@ -295,16 +290,16 @@ class BluefruitSPI:
# split packet off of buffer cache
packet = self._buffer[0:plen]
self._buffer = self._buffer[plen:] # remove packet from buffer
if sum([ord(x) for x in packet]) % 256 != 255: # check sum
self._buffer = self._buffer[plen:] # remove packet from buffer
if sum([ord(x) for x in packet]) % 256 != 255: # check sum
return None
# OK packet's good!
if packet[1] == "B": # buttons have 2 int args to parse
if packet[1] == 'B': # buttons have 2 int args to parse
# button number & True/False press
return ("B", int(packet[2]), packet[3] == "1")
if packet[1] == "C": # colorpick has 3 int args to parse
return ('B', int(packet[2]), packet[3] == '1')
if packet[1] == 'C': # colorpick has 3 int args to parse
# red, green and blue
return ("C", ord(packet[2]), ord(packet[3]), ord(packet[4]))
return ('C', ord(packet[2]), ord(packet[3]), ord(packet[4]))
# We don't nicely parse this yet
return packet[1:-1]

View file

@ -2,8 +2,7 @@
import os
import sys
sys.path.insert(0, os.path.abspath(".."))
sys.path.insert(0, os.path.abspath('..'))
# -- General configuration ------------------------------------------------
@ -11,10 +10,10 @@ sys.path.insert(0, os.path.abspath(".."))
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx.ext.napoleon",
"sphinx.ext.todo",
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'sphinx.ext.todo',
]
# TODO: Please Read!
@ -24,36 +23,29 @@ extensions = [
# autodoc_mock_imports = ["digitalio", "busio"]
intersphinx_mapping = {
"python": ("https://docs.python.org/3.4", None),
"BusDevice": (
"https://circuitpython.readthedocs.io/projects/busdevice/en/latest/",
None,
),
"CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None),
}
intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'BusDevice': ('https://circuitpython.readthedocs.io/projects/busdevice/en/latest/', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)}
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
templates_path = ['_templates']
source_suffix = ".rst"
source_suffix = '.rst'
# The master toctree document.
master_doc = "index"
master_doc = 'index'
# General information about the project.
project = "Adafruit BluefruitSPI Library"
copyright = "2018 Kevin Townsend"
author = "Kevin Townsend"
project = u'Adafruit BluefruitSPI Library'
copyright = u'2018 Kevin Townsend'
author = u'Kevin Townsend'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = "1.0"
version = u'1.0'
# The full version, including alpha/beta/rc tags.
release = "1.0"
release = u'1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -65,7 +57,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".env", "CODE_OF_CONDUCT.md"]
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.env', 'CODE_OF_CONDUCT.md']
# The reST default role (used for this markup: `text`) to use for all
# documents.
@ -77,7 +69,7 @@ default_role = "any"
add_function_parentheses = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
@ -92,62 +84,59 @@ napoleon_numpy_docstring = False
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd: # only import and set the theme if we're building docs locally
try:
import sphinx_rtd_theme
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."]
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.']
except:
html_theme = "default"
html_theme_path = ["."]
html_theme = 'default'
html_theme_path = ['.']
else:
html_theme_path = ["."]
html_theme_path = ['.']
# 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']
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#
html_favicon = "_static/favicon.ico"
html_favicon = '_static/favicon.ico'
# Output file base name for HTML help builder.
htmlhelp_basename = "AdafruitBluefruitspiLibrarydoc"
htmlhelp_basename = 'AdafruitBluefruitspiLibrarydoc'
# -- 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',
# 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,
"AdafruitBluefruitSPILibrary.tex",
"AdafruitBluefruitSPI Library Documentation",
author,
"manual",
),
(master_doc, 'AdafruitBluefruitSPILibrary.tex', u'AdafruitBluefruitSPI Library Documentation',
author, 'manual'),
]
# -- Options for manual page output ---------------------------------------
@ -155,13 +144,8 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(
master_doc,
"AdafruitBluefruitSPIlibrary",
"Adafruit BluefruitSPI Library Documentation",
[author],
1,
)
(master_doc, 'AdafruitBluefruitSPIlibrary', u'Adafruit BluefruitSPI Library Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
@ -170,13 +154,7 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
master_doc,
"AdafruitBluefruitSPILibrary",
"Adafruit BluefruitSPI Library Documentation",
author,
"AdafruitBluefruitSPILibrary",
"One line description of project.",
"Miscellaneous",
),
(master_doc, 'AdafruitBluefruitSPILibrary', u'Adafruit BluefruitSPI Library Documentation',
author, 'AdafruitBluefruitSPILibrary', 'One line description of project.',
'Miscellaneous'),
]

View file

@ -26,7 +26,7 @@ Table of Contents
.. toctree::
:caption: Related Products
Bluefruit LE SPI Friend <https://www.adafruit.com/product/2633>
Bluefruit LE SPI Friend <https://www.adafruit.com/product/2633)
.. toctree::
:caption: Other Links

View file

@ -8,7 +8,7 @@ from digitalio import DigitalInOut
from adafruit_bluefruitspi import BluefruitSPI
import neopixel
ADVERT_NAME = b"BlinkaNeoLamp"
ADVERT_NAME = b'BlinkaNeoLamp'
# 16 neopixels on a digital pin, adjust as necessary!
pixels = neopixel.NeoPixel(board.D5, 16)
@ -20,17 +20,15 @@ irq = DigitalInOut(board.D7)
rst = DigitalInOut(board.D4)
bluefruit = BluefruitSPI(spi_bus, cs, irq, rst, debug=False)
def init_bluefruit():
# Initialize the device and perform a factory reset
print("Initializing the Bluefruit LE SPI Friend module")
bluefruit.init()
bluefruit.command_check_OK(b"AT+FACTORYRESET", delay=1)
bluefruit.command_check_OK(b'AT+FACTORYRESET', delay=1)
# Print the response to 'ATI' (info request) as a string
print(str(bluefruit.command_check_OK(b"ATI"), "utf-8"))
print(str(bluefruit.command_check_OK(b'ATI'), 'utf-8'))
# Change advertised name
bluefruit.command_check_OK(b"AT+GAPDEVNAME=" + ADVERT_NAME)
bluefruit.command_check_OK(b'AT+GAPDEVNAME='+ADVERT_NAME)
def wait_for_connection():
print("Waiting for a connection to Bluefruit LE Connect ...")
@ -43,14 +41,11 @@ def wait_for_connection():
print("")
time.sleep(0.5)
# This code will check the connection but only query the module if it has been
# at least 'n_sec' seconds. Otherwise it 'caches' the response, to keep from
# hogging the Bluefruit connection with constant queries
connection_timestamp = None
is_connected = None
def check_connection(n_sec):
# pylint: disable=global-statement
global connection_timestamp, is_connected
@ -59,14 +54,13 @@ def check_connection(n_sec):
is_connected = bluefruit.connected
return is_connected
# Unlike most circuitpython code, this runs in two loops
# one outer loop manages reconnecting bluetooth if we lose connection
# then one inner loop for doing what we want when connected!
while True:
# Initialize the module
try: # Wireless connections can have corrupt data or other runtime failures
# This try block will reset the module if that happens
try: # Wireless connections can have corrupt data or other runtime failures
# This try block will reset the module if that happens
init_bluefruit()
wait_for_connection()
print("\n *Connected!*")
@ -79,7 +73,7 @@ while True:
continue # nothin'
print("Read packet", resp)
# Look for a 'C'olor packet
if resp[0] != "C":
if resp[0] != 'C':
continue
# Set the neopixels to the three bytes in the packet
pixels.fill(resp[1:4])

View file

@ -9,7 +9,7 @@ import board
from digitalio import DigitalInOut
from adafruit_bluefruitspi import BluefruitSPI
ADVERT_NAME = b"BlinkaBLE"
ADVERT_NAME = b'BlinkaBLE'
spi_bus = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
cs = DigitalInOut(board.D8)
@ -17,17 +17,15 @@ irq = DigitalInOut(board.D7)
rst = DigitalInOut(board.D4)
bluefruit = BluefruitSPI(spi_bus, cs, irq, rst, debug=False)
def init_bluefruit():
# Initialize the device and perform a factory reset
print("Initializing the Bluefruit LE SPI Friend module")
bluefruit.init()
bluefruit.command_check_OK(b"AT+FACTORYRESET", delay=1)
bluefruit.command_check_OK(b'AT+FACTORYRESET', delay=1)
# Print the response to 'ATI' (info request) as a string
print(str(bluefruit.command_check_OK(b"ATI"), "utf-8"))
print(str(bluefruit.command_check_OK(b'ATI'), 'utf-8'))
# Change advertised name
bluefruit.command_check_OK(b"AT+GAPDEVNAME=" + ADVERT_NAME)
bluefruit.command_check_OK(b'AT+GAPDEVNAME='+ADVERT_NAME)
def wait_for_connection():
print("Waiting for a connection to Bluefruit LE Connect ...")
@ -40,14 +38,11 @@ def wait_for_connection():
print("")
time.sleep(0.5)
# This code will check the connection but only query the module if it has been
# at least 'n_sec' seconds. Otherwise it 'caches' the response, to keep from
# hogging the Bluefruit connection with constant queries
connection_timestamp = None
is_connected = None
def check_connection(n_sec):
# pylint: disable=global-statement
global connection_timestamp, is_connected
@ -56,14 +51,13 @@ def check_connection(n_sec):
is_connected = bluefruit.connected
return is_connected
# Unlike most circuitpython code, this runs in two loops
# one outer loop manages reconnecting bluetooth if we lose connection
# then one inner loop for doing what we want when connected!
while True:
# Initialize the module
try: # Wireless connections can have corrupt data or other runtime failures
# This try block will reset the module if that happens
try: # Wireless connections can have corrupt data or other runtime failures
# This try block will reset the module if that happens
init_bluefruit()
wait_for_connection()
print("\n *Connected!*")
@ -79,7 +73,7 @@ while True:
print("Writing reverse...")
send = []
for i in range(len(resp), 0, -1):
send.append(resp[i - 1])
send.append(resp[i-1])
print(bytes(send))
bluefruit.uart_tx(bytes(send))
print("Connection lost.")

View file

@ -16,13 +16,13 @@ bluefruit = BluefruitSPI(spi_bus, cs, irq, rst, debug=False)
# Initialize the device and perform a factory reset
print("Initializing the Bluefruit LE SPI Friend module")
bluefruit.init()
bluefruit.command_check_OK(b"AT+FACTORYRESET", delay=1)
bluefruit.command_check_OK(b'AT+FACTORYRESET', delay=1)
# Print the response to 'ATI' (info request) as a string
print(str(bluefruit.command_check_OK(b"ATI"), "utf-8"))
print(str(bluefruit.command_check_OK(b'ATI'), 'utf-8'))
# Change advertised name
bluefruit.command_check_OK(b"AT+GAPDEVNAME=BlinkaBLE")
bluefruit.command_check_OK(b'AT+GAPDEVNAME=BlinkaBLE')
while True:
print("Waiting for a connection to Bluefruit LE Connect ...")
@ -54,7 +54,7 @@ while True:
print("Writing reverse...")
send = []
for i in range(len(resp), 0, -1):
send.append(resp[i - 1])
send.append(resp[i-1])
print(bytes(send))
bluefruit.uart_tx(bytes(send))

View file

@ -1,52 +0,0 @@
"""A setuptools based setup module.
See:
https://packaging.python.org/en/latest/distributing.html
https://github.com/pypa/sampleproject
"""
# Always prefer setuptools over distutils
from setuptools import setup, find_packages
# To use a consistent encoding
from codecs import open
from os import path
here = path.abspath(path.dirname(__file__))
# Get the long description from the README file
with open(path.join(here, "README.rst"), encoding="utf-8") as f:
long_description = f.read()
setup(
name="adafruit-circuitpython-bluefruitspi",
use_scm_version=True,
setup_requires=["setuptools_scm"],
description="CircuitPython helper class to work with the Adafruit Bluefruit LE SPI Friend.",
long_description=long_description,
long_description_content_type="text/x-rst",
# The project's main homepage.
url="https://github.com/adafruit/Adafruit_CircuitPython_BluefruitSPI",
# Author details
author="Adafruit Industries",
author_email="circuitpython@adafruit.com",
install_requires=["Adafruit-Blinka", "adafruit-circuitpython-busdevice"],
# Choose your license
license="MIT",
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries",
"Topic :: System :: Hardware",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
],
# What does your project relate to?
keywords="adafruit ble bluetooth bluefruit spi friend hardware micropython circuitpython",
# You can just specify the packages manually here if your project is
# simple. Or you can use find_packages().
py_modules=["adafruit_bluefruitspi"],
)