diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 699adec..2c84b88 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,58 +1,141 @@
name: Build CI
-on: [pull_request, push]
+on:
+ pull_request:
+ types: [opened, reopened]
+ push:
jobs:
- test:
+ build-wheel:
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: Pip install pylint & Sphinx
- run: |
- pip install --force-reinstall pylint==2.4.1 Sphinx sphinx-rtd-theme
- - name: Library version
- run: git describe --dirty --always --tags
- - name: PyLint
- run: |
- pylint --disable=too-many-arguments circuitpython_cirque_pinnacle/*.py
- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace,too-few-public-methods $( find . -path "./examples/*.py" ))
- - name: Build assets
- run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location . --package_folder_prefix circuitpython_cirque_pinnacle
- - name: Archive bundles
- uses: actions/upload-artifact@v2
- with:
- name: bundles
- path: ${{ github.workspace }}/bundles/
- - name: Build docs
- working-directory: docs
- run: sphinx-build -E -W -b html . _build/html
+ - uses: actions/setup-python@v4
+ with:
+ python-version: "3.x"
+
+ - uses: actions/checkout@v3
+
+ - name: Build wheel
+ run: pip wheel -w dist --no-deps .
+
+ - name: check dist
+ run: pipx run twine check dist/*
+
+ - name: Archive wheel
+ uses: actions/upload-artifact@v3
+ with:
+ name: wheel
+ path: ${{ github.workspace }}/dist/
+
+ linters:
+ runs-on: ubuntu-latest
+ steps:
+
+ - uses: actions/setup-python@v4
+ with:
+ python-version: "3.x"
+
+ - uses: actions/checkout@v3
+
+ - name: Install pre-commit and deps
+ run: pip install pre-commit -r requirements.txt
+
+ - name: Setup problem matchers
+ uses: adafruit/circuitpython-action-library-ci-problem-matchers@v1
+
+ - name: Pre-commit hooks
+ run: pre-commit run --all-files
+
+ # test-coverage:
+ # runs-on: ubuntu-latest
+ # steps:
+ # - uses: actions/checkout@v3
+
+ # - uses: actions/setup-python@v4
+ # with:
+ # python-version: "3.x"
+
+ # - name: Install testing tools
+ # run: pip install -r requirements.txt -r tests/requirements.txt
+
+ # - name: Collect coverage
+ # run: |
+ # coverage run -m pytest
+ # coverage report
+ # coverage xml
+
+ # - name: Upload coverage reports to Codecov
+ # uses: codecov/codecov-action@v3
+ # with:
+ # files: ./coverage.xml
+ # verbose: true # optional (default = false)
+
+ build-bundles:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Translate Repo Name For Build Tools filename_prefix
+ id: repo-name
+ run: |
+ echo repo-name=$(
+ echo ${{ github.repository }} |
+ awk -F '\/' '{ print tolower($2) }' |
+ tr '_' '-'
+ ) >> $GITHUB_OUTPUT
+
+ - name: Translate Repo Name For Build Tools package_prefix
+ id: pkg-name
+ run: |
+ echo pkg-name=$(
+ echo ${{ github.repository }} |
+ awk -F '\/' '{ print tolower($2) }'
+ ) >> $GITHUB_OUTPUT
+
+ - uses: actions/checkout@v3
+
+ - name: Set up Python 3.x
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.x"
+
+ - name: Checkout tools repo
+ uses: actions/checkout@v3
+ 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 }} --package_folder_prefix ${{ steps.pkg-name.outputs.pkg-name }} --library_location .
+
+ - name: Archive bundles
+ uses: actions/upload-artifact@v3
+ with:
+ name: bundles
+ path: ${{ github.workspace }}/bundles/
+
+ build-docs:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up Python 3.x
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.x"
+
+ - name: Install deps
+ run: |
+ pip install -r docs/requirements.txt -r requirements.txt
+
+ - name: Build docs
+ working-directory: docs
+ run: sphinx-build -E -W -b html . _build/html
+
+ - name: Archive docs
+ uses: actions/upload-artifact@v3
+ with:
+ name: docs
+ path: ${{ github.workspace }}/docs/_build/html
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 1d77b82..1ca8b0b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -3,79 +3,98 @@ name: Release Actions
on:
release:
types: [published]
+ workflow_dispatch:
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 . --package_folder_prefix circuitpython_cirque_pinnacle
- - 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 }}
+ - name: Translate Repo Name For Build Tools filename_prefix
+ id: repo-name
+ run: |
+ echo repo-name=$(
+ echo ${{ github.repository }} |
+ awk -F '\/' '{ print tolower($2) }' |
+ tr '_' '-'
+ ) >> $GITHUB_OUTPUT
+
+ - name: Translate Repo Name For Build Tools package_prefix
+ id: pkg-name
+ run: |
+ echo pkg-name=$(
+ echo ${{ github.repository }} |
+ awk -F '\/' '{ print tolower($2) }'
+ ) >> $GITHUB_OUTPUT
+
+ - name: Set up Python 3.x
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.x"
+
+ - name: Checkout Current Repo
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Checkout tools repo
+ uses: actions/checkout@v3
+ 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 }} --package_folder_prefix ${{ steps.pkg-name.outputs.pkg-name }} --library_location .
+
+ - name: Archive bundles
+ if: github.event_name == 'workflow_dispatch'
+ uses: actions/upload-artifact@v3
+ with:
+ name: bundles
+ path: ${{ github.workspace }}/bundles/
+
+ - name: Upload Release Assets
+ if: github.event_name == 'release'
+ uses: shogo82148/actions-upload-release-asset@v1
+ with:
+ upload_url: ${{ github.event.release.upload_url }}
+ asset_path: "bundles/*"
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: __token__
- TWINE_PASSWORD: ${{ secrets.pypi_token }}
- run: |
- python setup.py sdist
- twine upload dist/*
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+
+ - name: Install build tools
+ run: |
+ python -m pip install --upgrade pip
+ pip install build twine
+
+ - name: Build distributions
+ run: python -m build
+
+ - name: Check distributions
+ run: twine check dist/*
+
+ - name: Publish package (to TestPyPI)
+ if: github.event_name == 'workflow_dispatch' && github.repository == '2bndy5/CircuitPython_Cirque_Pinnacle'
+ env:
+ TWINE_USERNAME: __token__
+ TWINE_PASSWORD: ${{ secrets.TEST_PYPI_TOKEN }}
+ run: twine upload --repository testpypi dist/*
+
+ - name: Publish package (to PyPI)
+ if: github.event_name != 'workflow_dispatch' && github.repository == '2bndy5/CircuitPython_Cirque_Pinnacle'
+ env:
+ TWINE_USERNAME: __token__
+ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
+ run: twine upload dist/*
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..529b734
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,43 @@
+repos:
+ - repo: https://github.com/python/black
+ rev: 22.8.0
+ hooks:
+ - id: black
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.3.0
+ hooks:
+ - id: check-yaml
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
+ - repo: https://github.com/pycqa/pylint
+ rev: v2.15.3
+ hooks:
+ - id: pylint
+ name: pylint (library code)
+ types: [python]
+ args:
+ - --disable=consider-using-f-string,duplicate-code,too-many-public-methods,too-few-public-methods
+ exclude: "^(docs/|examples/|tests/|setup.py$)"
+ additional_dependencies: ["adafruit-circuitpython-busdevice"]
+ - id: pylint
+ name: pylint (example code)
+ description: Run pylint rules on "examples/*.py" files
+ types: [python]
+ files: "^examples/"
+ args:
+ - --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code,import-error
+ - id: pylint
+ name: pylint (test code)
+ description: Run pylint rules on "tests/*.py" files
+ types: [python]
+ additional_dependencies: [pytest]
+ files: "^tests/"
+ args:
+ - --disable=import-error,invalid-name,protected-access,too-few-public-methods
+ - repo: https://github.com/pre-commit/mirrors-mypy
+ rev: v0.981
+ hooks:
+ - id: mypy
+ name: mypy (library code)
+ exclude: "^(docs/|examples/|tests/|setup.py$)"
+ types: [python]
diff --git a/.pylintrc b/.pylintrc
deleted file mode 100644
index a95e6a0..0000000
--- a/.pylintrc
+++ /dev/null
@@ -1,433 +0,0 @@
-[MASTER]
-
-# A comma-separated list of package or module names from where C extensions may
-# be loaded. Extensions are loading into the active Python interpreter and may
-# run arbitrary code
-extension-pkg-whitelist=
-
-# Add files or directories to the blacklist. They should be base names, not
-# paths.
-ignore=CVS
-
-# Add files or directories matching the regex patterns to the blacklist. The
-# regex matches against base names, not paths.
-ignore-patterns=
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Use multiple processes to speed up Pylint.
-# jobs=1
-jobs=2
-
-# List of plugins (as comma separated values of python modules names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-# Pickle collected data for later comparisons.
-persistent=yes
-
-# Specify a configuration file.
-#rcfile=
-
-# Allow loading of arbitrary C extensions. Extensions are imported into the
-# active Python interpreter and may run arbitrary code.
-unsafe-load-any-extension=no
-
-
-[MESSAGES CONTROL]
-
-# Only show warnings with the listed confidence levels. Leave empty to show
-# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
-confidence=
-
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifiers separated by comma (,) or put this
-# option multiple times (only on the command line, not in the configuration
-# file where it should appear only once).You can also use "--disable=all" to
-# disable everything first and then reenable specific checks. For example, if
-# you want to run only the similarities checker, you can use "--disable=all
-# --enable=similarities". If you want to run only the classes checker, but have
-# 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
-
-# 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
-# multiple time (only on the command line, not in the configuration file where
-# it should appear only once). See also the "--disable" option for examples.
-enable=
-
-
-[REPORTS]
-
-# Python expression which should return a note less than 10 (10 is the highest
-# note). You have access to the variables errors warning, statement which
-# respectively contain the number of errors / warnings messages and the total
-# number of statements analyzed. This is used by the global evaluation report
-# (RP0004).
-evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
-
-# Template used to display messages. This is a python new-style format string
-# used to format the message information. See doc for all details
-#msg-template=
-
-# Set the output format. Available formats are text, parseable, colorized, json
-# and msvs (visual studio).You can also give a reporter class, eg
-# mypackage.mymodule.MyReporterClass.
-output-format=text
-
-# Tells whether to display a full report or only the messages
-reports=no
-
-# Activate the evaluation score.
-score=yes
-
-
-[REFACTORING]
-
-# Maximum number of nested blocks for function / method body
-max-nested-blocks=5
-
-
-[LOGGING]
-
-# Logging modules to check that the string format arguments are in logging
-# function parameter format
-logging-modules=logging
-
-
-[SPELLING]
-
-# Spelling dictionary name. Available dictionaries: none. To make it working
-# install python-enchant package.
-spelling-dict=
-
-# List of comma separated words that should not be checked.
-spelling-ignore-words=
-
-# A path to a file that contains private dictionary; one word per line.
-spelling-private-dict-file=
-
-# Tells whether to store unknown words to indicated private dictionary in
-# --spelling-private-dict-file option instead of raising a message.
-spelling-store-unknown-words=no
-
-
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-# notes=FIXME,XXX,TODO
-notes=FIXME,XXX
-
-
-[TYPECHECK]
-
-# List of decorators that produce context managers, such as
-# contextlib.contextmanager. Add to this list to register other decorators that
-# produce valid context managers.
-contextmanager-decorators=contextlib.contextmanager
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E1101 when accessed. Python regular
-# expressions are accepted.
-generated-members=
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# This flag controls whether pylint should warn about no-member and similar
-# checks whenever an opaque object is returned when inferring. The inference
-# can return multiple potential results while evaluating a Python object, but
-# some branches might not be evaluated, which results in partial inference. In
-# that case, it might be useful to still emit no-member and other checks for
-# the rest of the inferred objects.
-ignore-on-opaque-inference=yes
-
-# List of class names for which member attributes should not be checked (useful
-# for classes with dynamically set attributes). This supports the use of
-# qualified names.
-ignored-classes=optparse.Values,thread._local,_thread._local
-
-# List of module names for which member attributes should not be checked
-# (useful for modules/projects where namespaces are manipulated during runtime
-# and thus existing member attributes cannot be deduced by static analysis. It
-# supports qualified module names, as well as Unix pattern matching.
-ignored-modules=board
-
-# Show a hint with possible names when a member name was not found. The aspect
-# of finding the hint is based on edit distance.
-missing-member-hint=yes
-
-# The minimum edit distance a name should have in order to be considered a
-# similar match for a missing member name.
-missing-member-hint-distance=1
-
-# The total number of similar names that should be taken in consideration when
-# showing a hint for a missing member.
-missing-member-max-choices=1
-
-
-[VARIABLES]
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
-
-# Tells whether unused global variables should be treated as a violation.
-allow-global-unused-variables=yes
-
-# List of strings which can identify a callback function by name. A callback
-# name must start or end with one of those strings.
-callbacks=cb_,_cb
-
-# A regular expression matching the name of dummy variables (i.e. expectedly
-# not used).
-dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore
-ignored-argument-names=_.*|^ignored_|^unused_
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# List of qualified module names which can have objects that can redefine
-# builtins.
-redefining-builtins-modules=six.moves,future.builtins
-
-
-[FORMAT]
-
-# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
-# expected-line-ending-format=
-expected-line-ending-format=LF
-
-# Regexp for a line that is allowed to be longer than the limit.
-ignore-long-lines=^\s*(# )??$
-
-# Number of spaces of indent required inside a hanging or continued line.
-indent-after-paren=4
-
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-indent-string=' '
-
-# Maximum number of characters on a single line.
-max-line-length=100
-
-# Maximum number of lines in a module
-max-module-lines=1000
-
-# List of optional constructs for which whitespace checking is disabled. `dict-
-# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
-# `trailing-comma` allows a space between comma and closing bracket: (a, ).
-# `empty-line` allows space-only lines.
-no-space-check=trailing-comma,dict-separator
-
-# Allow the body of a class to be on the same line as the declaration if body
-# contains single statement.
-single-line-class-stmt=no
-
-# Allow the body of an if to be on the same line as the test if there is no
-# else.
-single-line-if-stmt=no
-
-
-[SIMILARITIES]
-
-# Ignore comments when computing similarities.
-ignore-comments=yes
-
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
-
-# Ignore imports when computing similarities.
-ignore-imports=no
-
-# Minimum lines number of a similarity.
-min-similarity-lines=4
-
-
-[BASIC]
-
-# Naming hint for argument names
-argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
-
-# Regular expression matching correct argument names
-argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
-
-# Naming hint for attribute names
-attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
-
-# Regular expression matching correct attribute names
-attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
-
-# Bad variable names which should always be refused, separated by a comma
-bad-names=foo,bar,baz,toto,tutu,tata
-
-# Naming hint for class attribute names
-class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
-
-# Regular expression matching correct class attribute names
-class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
-
-# Naming hint for class names
-# class-name-hint=[A-Z_][a-zA-Z0-9]+$
-class-name-hint=[A-Z_][a-zA-Z0-9_]+$
-
-# Regular expression matching correct class names
-# class-rgx=[A-Z_][a-zA-Z0-9]+$
-class-rgx=[A-Z_][a-zA-Z0-9_]+$
-
-# Naming hint for constant names
-const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-
-# Regular expression matching correct constant names
-const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-
-# Minimum line length for functions/classes that require docstrings, shorter
-# ones are exempt.
-docstring-min-length=-1
-
-# Naming hint for function names
-function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
-
-# Regular expression matching correct function names
-function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
-
-# Good variable names which should always be accepted, separated by a comma
-# good-names=i,j,k,ex,Run,_
-good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_
-
-# Include a hint for the correct naming format with invalid-name
-include-naming-hint=no
-
-# Naming hint for inline iteration names
-inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
-
-# Regular expression matching correct inline iteration names
-inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
-
-# Naming hint for method names
-method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
-
-# Regular expression matching correct method names
-method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
-
-# Naming hint for module names
-module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-
-# Regular expression matching correct module names
-module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-
-# Colon-delimited sets of names that determine each other's naming style when
-# the name regexes allow several styles.
-name-group=
-
-# Regular expression which should only match function or class names that do
-# not require a docstring.
-no-docstring-rgx=^_
-
-# List of decorators that produce properties, such as abc.abstractproperty. Add
-# to this list to register other decorators that produce valid properties.
-property-classes=abc.abstractproperty
-
-# Naming hint for variable names
-variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
-
-# Regular expression matching correct variable names
-variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
-
-
-[IMPORTS]
-
-# Allow wildcard imports from modules that define __all__.
-allow-wildcard-with-all=no
-
-# Analyse import fallback blocks. This can be used to support both Python 2 and
-# 3 compatible code, which means that the block might have code that exists
-# only in one or another interpreter, leading to false positives when analysed.
-analyse-fallback-blocks=no
-
-# Deprecated modules which should not be used, separated by a comma
-deprecated-modules=optparse,tkinter.tix
-
-# Create a graph of external dependencies in the given file (report RP0402 must
-# not be disabled)
-ext-import-graph=
-
-# Create a graph of every (i.e. internal and external) dependencies in the
-# given file (report RP0402 must not be disabled)
-import-graph=
-
-# Create a graph of internal dependencies in the given file (report RP0402 must
-# not be disabled)
-int-import-graph=
-
-# Force import order to recognize a module as part of the standard
-# compatibility libraries.
-known-standard-library=
-
-# Force import order to recognize a module as part of a third party library.
-known-third-party=enchant
-
-
-[CLASSES]
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,__new__,setUp
-
-# List of member names, which should be excluded from the protected access
-# warning.
-exclude-protected=_asdict,_fields,_replace,_source,_make
-
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
-
-# List of valid names for the first argument in a metaclass class method.
-valid-metaclass-classmethod-first-arg=mcs
-
-
-[DESIGN]
-
-# Maximum number of arguments for function / method
-max-args=5
-
-# Maximum number of attributes for a class (see R0902).
-# max-attributes=7
-max-attributes=11
-
-# Maximum number of boolean expressions in a if statement
-max-bool-expr=5
-
-# Maximum number of branch for function / method body
-max-branches=12
-
-# Maximum number of locals for function / method body
-max-locals=15
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
-
-# Maximum number of return / yield for function / method body
-max-returns=6
-
-# Maximum number of statements in function / method body
-max-statements=50
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=1
-
-
-[EXCEPTIONS]
-
-# Exceptions that will emit a warning when being caught. Defaults to
-# "Exception"
-overgeneral-exceptions=Exception
diff --git a/.readthedocs.yml b/.readthedocs.yml
index e311bcb..2ed8c42 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -1,3 +1,8 @@
+version: 2
+
python:
- version: 3
-requirements_file: requirements.txt
+ version: 3
+ install:
+ - requirements: docs/requirements.txt
+ - method: pip
+ path: .
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
new file mode 100644
index 0000000..e63668a
--- /dev/null
+++ b/CONTRIBUTING.rst
@@ -0,0 +1,50 @@
+
+Contributing Guidelines
+=======================
+
+Linting the source code
+-----------------------
+
+.. _pre-commit: https://pre-commit.com/
+
+This library uses pre-commit_ for some linting tools like
+
+- `black `_
+- `pylint `_
+- `mypy `_
+
+To use pre-commit_, you must install it and create the cached environments that it needs.
+
+.. code-block:: shell
+
+ pip install pre-commit
+ pre-commit install
+
+Now, every time you commit something it will run pre-commit_ on the changed files. You can also
+run pre-commit_ on staged files:
+
+.. code-block:: shell
+
+ pre-commit run
+
+.. note::
+ Use the ``--all-files`` argument to run pre-commit on all files in the repository.
+
+
+Building the Documentation
+--------------------------
+
+To build library documentation, you need to install the documentation dependencies.
+
+.. code-block:: shell
+
+ pip install -r docs/requirements.txt
+
+Finally, build the documentation with Sphinx:
+
+.. code-block:: shell
+
+ sphinx-build -E -W docs docs/_build/html
+
+The rendered HTML files should now be located in the ``docs/_build/html`` folder. Point your
+internet browser to this path and check the changes have been rendered properly.
diff --git a/README.rst b/README.rst
index 735714c..ddc252c 100644
--- a/README.rst
+++ b/README.rst
@@ -11,162 +11,10 @@
:alt: latest version on PyPI
:target: https://pypi.python.org/pypi/circuitpython-cirque-pinnacle
-.. image:: https://pepy.tech/badge/circuitpython-cirque-pinnacle
+.. image:: https://static.pepy.tech/personalized-badge/circuitpython-cirque-pinnacle?period=total&units=international_system&left_color=grey&right_color=blue&left_text=Pypi%20Downloads
:alt: Total PyPI downloads
:target: https://pepy.tech/project/circuitpython-cirque-pinnacle
+A circuitpython library for using the Cirque Glidepoint circle trackpads (as seen in the Steam Controller and Valve\HTC Vive VR controllers).
-Introduction
-============
-
-A CircuitPython driver library that implements the Adafruit_BusDevice library
-for interfacing with the Cirque Pinnacle (1CA027) touch controller used in Cirque Circle Trackpads.
-
-Supported Features
-------------------
-
-* Use SPI or I2C bus protocols to interface with the Pinnacle touch controller ASIC (Application
- Specific Integrated Circuit).
-* Relative mode data reporting (AKA Mouse mode) with optional tap detection.
-* Absolute mode data reporting (x, y, & z axis positions).
-* AnyMeas mode data reporting. This mode exposes the ADC (Analog to Digital Converter) values and is
- not well documented in the numerous datasheets provided by the Cirque corporation about the
- Pinnacle (1CA027), thus this is a rather experimental mode.
-* Hardware input buttons' states included in data reports. There are 3 button input lines on
- the Cirque circle trackpads -- see `Pinout`_ section.
-* Configure measurements for finger or stylus (or automatically detirmine either) touch
- events. The Cirque circle trackpads are natively capable of measuring only 1 touch
- point per event.
-* Download/upload the underlying compensation matrix for ADC measurements.
-* Adjust the ADC matrix gain (sensitivity).
-
-.. tip:: The SPI protocol is the preferred method for interfacing with more than 1 Cirque circle
- trackpad from the same MCU (microcontroller). The Cirque Pinnacle does not allow
- changing the I2C slave device address (via software); this means only 1 Cirque circle trackpad
- can be accessed over the I2C bus in the lifecycle of an application. That said, you could change
- the I2C address from ``0x2A`` to ``0x2C`` by soldering a 470K ohm resistor at the junction
- labeled "ADR" (see picture in `Pinout`_ section), although this is untested.
-
-Unsupported Features
---------------------
-
-* The legacy PS\\2 interface is pretty limited and not accessible by some CircuitPython MCUs.
- Therefore, it has been neglected in this library.
-* Cirque's circle trackpads ship with the newer non-AG (Advanced Gestures) variant of the
- Pinnacle touch controller ASIC. Thus, this library focuses on the the non-AG variant's
- functionality via testing, and it does not provide access to the older AG variant's features
- (register addresses slightly differ which breaks compatibility).
-
-Pinout
-======
-
-.. image:: https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle/raw/master/docs/_static/Cirque_GlidePoint-Circle-Trackpad.png
- :target: https://www.mouser.com/new/cirque/glidepoint-circle-trackpads/
-
-The above picture is an example of the Cirque GlidePoint circle trackpad. This picture
-is chosen as the test pads (larger copper circular pads) are clearly labeled. The test pads
-are extended to the `12-pin FFC/FPC cable `_ connector (the white block near the
-bottom). The following table shows how the pins are connected in the `examples `_ (tested on an `ItsyBitys M4 `_)
-
-.. csv-table:: pinout (ordered the same as the FFC/FPC cable connector)
- :header: Label,"MCU pin",Description
- :widths: 5,5,13
-
- SCK,SCK,"SPI clock line"
- SO,MISO,"Master Input Slave Output"
- SS,D7,"Slave Select (AKA Chip Select)"
- DR,D2,"""data ready"" interrupt"
- SI,MOSI,"SPI Master Output Slave Input"
- B2,N/A,"Hardware input button #2"
- B3,N/A,"Hardware input button #3"
- B1,N/A,"Hardware input button #1"
- SCL,SCL,"I2C clock line"
- SDA,SDA,"I2C data line"
- GND,GND,"Ground"
- VDD,3V,"3V power supply"
-
-.. tip:: Of course, you can capture button data manually (if your application utilizes more
- than 3 buttons), but if you connect the pins B1, B2, B3 to momentary push buttons that
- (when pressed) provide a path to ground, the Pinnacle touch controller will report all 3
- buttons' states for each touch (or even button only) events.
-
-Model Labeling Scheme
----------------------
-
- TM\ [yyyxxx]_\ -202\ [i]_\ -\ [cc]_\ [o]_
-
- .. [yyyxxx] stands for the vertical & horizontal width of the trackpad, respectively.
- .. [i] stands for the hardwired interface protocol (3 = I2C, 4 = SPI). Notice, if there is a
- resistor populated at the R1 (470K ohm) junction (located just above the Pinnacle ASIC), it
- is configured for SPI, otherwise it is configured for I2C.
- .. [cc] stands for Custom Configuration which describes if a 470K ohm resistor is populated at
- junction R4. "30" (resistor at R4 exists) means that the hardware is configured to disable
- certain features despite what this library does. "00" (no resistor at R4) means that the
- hardware is configured to allow certain features to be manipulated by this library. These
- features include "secondary tap" (thought of as "right mouse button" in relative data mode),
- Intellimouse scrolling (Microsoft patented scroll wheel behavior -- a throw back to when
- scroll wheels were first introduced), and 180 degree orientation (your application can invert
- the axis data anyway).
- .. [o] stands for the overlay type (0 = none, 1 = adhesive, 2 = flat, 3 = curved)
-
-Dependencies
-=============
-This driver depends on:
-
-* `Adafruit CircuitPython `_
-* `Bus Device `_
-
-Please ensure all dependencies are available on the CircuitPython filesystem.
-This is easily achieved by downloading `the Adafruit library and driver bundle
-`_.
-
-How to Install
-=====================
-This library is deployed to pypi.org, so you can easily install this library
-using ``pip3 install circuitpython-cirque-pinnacle`` or use the following
-commands:
-
-.. code-block:: shell
-
- git clone https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle.git
- cd CircuitPython_Cirque_Pinnacle
- python3 setup.py install
-
-To install globally, prefix the last command with ``sudo``.
-
-Usage Example
-=============
-
-Ensure you've connected the TMyyyxxx correctly by running the `examples/` located in the `examples
-folder of this library `_.
-
-Contributing
-============
-
-Contributions are welcome! Please read our `Code of Conduct
-`_
-before contributing to help this project stay welcoming.
-
-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.
+Read the `Documentation at ReadTheDocs.org `_
diff --git a/circuitpython_cirque_pinnacle/glidepoint.py b/circuitpython_cirque_pinnacle/glidepoint.py
index e4fbb92..784db8d 100644
--- a/circuitpython_cirque_pinnacle/glidepoint.py
+++ b/circuitpython_cirque_pinnacle/glidepoint.py
@@ -1,49 +1,72 @@
"""
-A driver class for the Cirque Pinnacle ASIC on the Cirque capacitve touch
+A driver class for the Cirque Pinnacle ASIC on the Cirque capacitive touch
based circular trackpads.
"""
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle.git"
import time
-from struct import pack, unpack
-from micropython import const
+import struct
+
try:
- from ubus_device import SPIDevice, I2CDevice
+ from typing import Optional, List, Union
except ImportError:
- from adafruit_bus_device.spi_device import SPIDevice
- from adafruit_bus_device.i2c_device import I2CDevice
-
-RELATIVE = const(0x00)
-ANYMEAS = const(0x01)
-ABSOLUTE = const(0x02)
-GAIN_100 = const(0xC0)
-GAIN_133 = const(0x80)
-GAIN_166 = const(0x40)
-GAIN_200 = const(0x00)
-FREQ_0 = const(0x02)
-FREQ_1 = const(0x03)
-FREQ_2 = const(0x04)
-FREQ_3 = const(0x05)
-FREQ_4 = const(0x06)
-FREQ_5 = const(0x07)
-FREQ_6 = const(0x09)
-FREQ_7 = const(0x0B)
-MUX_REF1 = const(0x10)
-MUX_REF0 = const(0x08)
-MUX_PNP = const(0x04)
-MUX_NPN = const(0x01)
-CRTL_REPEAT = const(0x80)
-CRTL_PWR_IDLE = const(0x40)
+ pass
+
+from micropython import const
+import digitalio
+import busio
+from adafruit_bus_device.spi_device import SPIDevice
+from adafruit_bus_device.i2c_device import I2CDevice
+
+RELATIVE: int = const(0x00)
+ANYMEAS: int = const(0x01)
+ABSOLUTE: int = const(0x02)
+GAIN_100: int = const(0xC0) #: around 100% gain
+GAIN_133: int = const(0x80) #: around 133% gain
+GAIN_166: int = const(0x40) #: around 166% gain
+GAIN_200: int = const(0x00) #: around 200% gain
+FREQ_0: int = const(0x02) #: frequency around 500,000Hz
+FREQ_1: int = const(0x03) #: frequency around 444,444Hz
+FREQ_2: int = const(0x04) #: frequency around 400,000Hz
+FREQ_3: int = const(0x05) #: frequency around 363,636Hz
+FREQ_4: int = const(0x06) #: frequency around 333,333Hz
+FREQ_5: int = const(0x07) #: frequency around 307,692Hz
+FREQ_6: int = const(0x09) #: frequency around 267,000Hz
+FREQ_7: int = const(0x0B) #: frequency around 235,000Hz
+MUX_REF1: int = const(0x10) #: enables a builtin capacitor (~0.5pF).
+MUX_REF0: int = const(0x08) #: enables a builtin capacitor (~0.25pF).
+MUX_PNP: int = const(0x04) #: enable PNP sense line
+MUX_NPN: int = const(0x01) #: enable NPN sense line
+CRTL_REPEAT: int = const(0x80) #: required for more than 1 measurement
+CRTL_PWR_IDLE: int = const(
+ 0x40
+) #: triggers low power mode (sleep) after completing measurements
+
class PinnacleTouch:
- """The abstract base class for driving the Pinnacle ASIC."""
- def __init__(self, dr_pin=None):
+ """The abstract base class for driving the Pinnacle ASIC.
+
+ :param ~digitalio.DigitalInOut dr_pin: |dr_pin_parameter|
+
+ .. important:: |dr_pin_note|
+
+ .. |dr_pin_parameter| replace:: The input pin connected to the Pinnacle ASIC's "Data
+ Ready" pin. If this parameter is not specified, then the SW_DR (software data ready) flag
+ of the STATUS register is used to determine if the data being reported is new.
+
+ .. |dr_pin_note| replace:: This parameter must be specified if your application is
+ going to use the Pinnacle ASIC's
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` mode (a rather
+ experimental measuring of raw ADC values).
+ """
+
+ def __init__(self, dr_pin: Optional[digitalio.DigitalInOut] = None):
self.dr_pin = dr_pin
- if dr_pin is not None:
+ if self.dr_pin is not None:
self.dr_pin.switch_to_input()
firmware_id, firmware_ver = self._rap_read_bytes(0, 2)
if firmware_id != 7 or firmware_ver != 0x3A:
- raise OSError("Cirque Pinnacle ASIC not responding")
+ raise RuntimeError("Cirque Pinnacle ASIC not responding")
# init internal attributes w/ factory defaults after power-on-reset
self._mode = 0 # 0 means relative mode which is factory default
self.detect_finger_stylus()
@@ -53,29 +76,54 @@ def __init__(self, dr_pin=None):
self.calibrate(True) # enables all compensations
@property
- def feed_enable(self):
+ def feed_enable(self) -> bool:
"""This `bool` attribute controls if the touch/button event data is
- reported (`True`) or not (`False`)."""
+ reported (`True`) or not (`False`).
+
+ This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`
+ or :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` mode. Otherwise if
+ `data_mode` is set to :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`,
+ then this attribute will have no effect.
+ """
return bool(self._rap_read(4) & 1)
@feed_enable.setter
- def feed_enable(self, is_on):
+ def feed_enable(self, is_on: bool):
is_enabled = self._rap_read(4)
- if is_enabled & 1 != is_on:
+ if bool(is_enabled & 1) != is_on:
# save ourselves the unnecessary transaction
is_enabled = (is_enabled & 0xFE) | is_on
self._rap_write(4, is_enabled)
@property
- def data_mode(self):
- """This attribute controls which mode the data report is configured
- for."""
+ def data_mode(self) -> int:
+ """This attribute controls which mode the data reports are configured
+ for.
+
+ Valid input values are :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE` for
+ relative/mouse mode, :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` for
+ absolute positioning mode, or :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`
+ (referred to as "AnyMeas" in specification sheets) mode for reading ADC values.
+
+ :Returns:
+
+ - ``0`` for Relative mode (AKA mouse mode)
+ - ``1`` for AnyMeas mode (raw ADC measurements)
+ - ``2`` for Absolute mode (X & Y axis positions)
+
+ .. important::
+ When switching from :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` to
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE` or
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` all
+ configurations are reset, and must be re-configured by using
+ `absolute_mode_config()` or `relative_mode_config()`.
+ """
return self._mode
@data_mode.setter
- def data_mode(self, mode):
+ def data_mode(self, mode: int):
if mode not in (ANYMEAS, RELATIVE, ABSOLUTE):
- raise ValueError("Unrecognised input value for data_mode.")
+ raise ValueError("Unrecognized input value for data_mode.")
sys_config = self._rap_read(3) & 0xE7 # clear AnyMeas mode flags
if mode in (RELATIVE, ABSOLUTE):
if self.data_mode == ANYMEAS: # if leaving AnyMeas mode
@@ -98,89 +146,251 @@ def data_mode(self, mode):
self._mode = mode
@property
- def hard_configured(self):
- """This `bool` attribute can be used to inform applications about
- factory customized hardware configuration."""
- return bool(self._rap_read(0x1f))
-
- def relative_mode_config(self, rotate90=False, taps=True,
- secondary_tap=True, glide_extend=True,
- intellimouse=False):
+ def hard_configured(self) -> bool:
+ """This read-only `bool` attribute can be used to inform applications about
+ factory customized hardware configuration. See note about product labeling in
+ `Model Labeling Scheme `_.
+
+ :Returns:
+ `True` if a 470K ohm resistor is populated at the junction labeled "R4"
+ """
+ return bool(self._rap_read(0x1F))
+
+ def relative_mode_config(
+ self,
+ rotate90: bool = False,
+ taps: bool = True,
+ secondary_tap: bool = True,
+ glide_extend: bool = True,
+ intellimouse: bool = False,
+ ):
"""Configure settings specific to Relative mode (AKA Mouse mode) data
- reporting."""
+ reporting.
+
+ This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`
+ mode, otherwise if `data_mode` is set to
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` or
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE`, then this function does nothing.
+
+ :param rotate90: Specifies if the axis data is altered for 90 degree rotation before
+ reporting it (essentially swaps the axis data). Default is `False`.
+ :param taps: Specifies if all taps should be reported (`True`) or not
+ (`False`). Default is `True`. This affects ``secondary_tap`` option as well.
+ :param secondary_tap: Specifies if tapping in the top-left corner (depending on
+ orientation) triggers the secondary button data. Defaults to `True`. This feature is
+ always disabled if `hard_configured` is `True`.
+ :param glide_extend: A patented feature that allows the user to glide their finger off
+ the edge of the sensor and continue gesture with the touch event. Default is `True`.
+ This feature is always disabled if `hard_configured` is `True`.
+ :param intellimouse: Specifies if the data reported includes a byte about scroll data.
+ Default is `False`. Because this flag is specific to scroll data, this feature is always
+ disabled if `hard_configured` is `True`.
+ """
if self.data_mode == RELATIVE:
config2 = (rotate90 << 7) | ((not glide_extend) << 4)
config2 |= ((not secondary_tap) << 2) | ((not taps) << 1)
self._rap_write(5, config2 | bool(intellimouse))
- def absolute_mode_config(self, z_idle_count=30,
- invert_x=False, invert_y=False):
+ def absolute_mode_config(
+ self, z_idle_count: int = 30, invert_x: bool = False, invert_y: bool = False
+ ):
"""Configure settings specific to Absolute mode (reports axis
- positions)."""
+ positions).
+
+ This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE`
+ mode, otherwise if `data_mode` is set to
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` or
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`, then this function does nothing.
+
+ :param z_idle_count: Specifies the number of empty packets (x-axis, y-axis, and z-axis
+ are ``0``) reported (every 10 milliseconds) when there is no touch detected. Defaults
+ to 30. This number is clamped to range [0, 255].
+ :param invert_x: Specifies if the x-axis data is to be inverted before reporting it.
+ Default is `False`.
+ :param invert_y: Specifies if the y-axis data is to be inverted before reporting it.
+ Default is `False`.
+ """
if self.data_mode == ABSOLUTE:
self._rap_write(0x0A, max(0, min(z_idle_count, 255)))
config1 = self._rap_read(4) & 0x3F | (invert_y << 7)
self._rap_write(4, config1 | (invert_x << 6))
- def report(self, only_new=True):
+ def available(self) -> bool:
+ """Determine if there is fresh data to report.
+
+ If the ``dr_pin`` parameter is specified upon instantiation, then the specified
+ input pin is used to detect if the data is new. Otherwise the SW_DR flag in the
+ STATUS register is used to determine if the data is new.
+
+ :Return: If there is fresh data to report (`True`) or not (`False`).
+
+ .. versionadded:: 0.0.5
+ """
+ if self.dr_pin is None:
+ return bool(self._rap_read(2) & 4)
+ return self.dr_pin.value
+
+ def read(self) -> Optional[Union[List[int], bytearray]]:
"""This function will return touch event data from the Pinnacle ASIC
- (including empty packets on ending of a touch event)."""
+ (including empty packets on ending of a touch event).
+
+ This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`
+ or :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` mode. Otherwise if
+ `data_mode` is set to :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`, then this
+ function returns `None` and does nothing.
+
+ :Returns: A `list` or `bytearray` of parameters that describe the (touch or
+ button) event. The structure is as follows:
+
+ .. list-table::
+ :header-rows: 1
+ :widths: 1, 5, 5
+
+ * - Index
+ - Relative (Mouse) mode
+
+ as a `bytearray`
+ - Absolute Mode
+
+ as a `list`
+ * - 0
+ - Button Data [1]_
+
+ one unsigned byte
+ - Button Data [1]_
+
+ one unsigned byte
+ * - 1
+ - change in x-axis [2]_
+
+ -128 |LessEq| X |LessEq| 127
+ - x-axis Position
+
+ 0 |LessEq| X |LessEq| 2047 [4]_
+ * - 2
+ - change in y-axis [2]_
+
+ -128 |LessEq| Y |LessEq| 127
+ - y-axis Position
+
+ 0 |LessEq| Y |LessEq| 1535 [5]_
+ * - 3
+ - change in scroll wheel [3]_
+
+ -128 |LessEq| SCROLL |LessEq| 127
+ - z-axis Magnitude
+
+ .. [1] The returned button data is a byte in which each bit represents a button.
+ The bit to button order is as follows:
+
+ 0. [LSB] Button 1 (thought of as Left button in Relative/Mouse mode). If ``taps``
+ parameter is passed as `True` when calling `relative_mode_config()`, a single
+ tap will be reflected here.
+ 1. Button 2 (thought of as Right button in Relative/Mouse mode). If ``taps`` and
+ ``secondary_tap`` parameters are passed as `True` when calling
+ `relative_mode_config()`, a single tap in the perspective top-left-most corner will
+ be reflected here (secondary taps are constantly disabled if `hard_configured`
+ returns `True`). Note that the top-left-most corner can be perspectively moved if
+ ``rotate90`` parameter is passed as `True` when calling `relative_mode_config()`.
+ 2. Button 3 (thought of as Middle or scroll wheel button in Relative/Mouse mode)
+ .. [2] The axis data reported in Relative/Mouse mode is in two's
+ compliment form. Use Python's :py:func:`struct.unpack()` to convert the
+ data into integer form (see `Simple Test example `_
+ for how to use this function).
+
+ The axis data reported in Absolute mode is always positive as the
+ xy-plane's origin is located to the top-left, unless ``invert_x`` or ``invert_y``
+ parameters to `absolute_mode_config()` are manipulated to change the perspective
+ location of the origin.
+ .. [3] In Relative/Mouse mode the scroll wheel data is only reported if the
+ ``intellimouse`` parameter is passed as `True` to `relative_mode_config()`.
+ Otherwise this is an empty byte as the
+ returned `bytearray` follows the buffer structure of a mouse HID report (see
+ `USB Mouse example `_).
+ .. [4] The datasheet recommends the x-axis value (in Absolute mode) should be
+ clamped to range 128 |LessEq| ``x`` |LessEq| 1920 for reliability.
+ .. [5] The datasheet recommends the y-axis value (in Absolute mode) should be
+ clamped to range 64 |LessEq| ``y`` |LessEq| 1472 for reliability.
+ .. |LessEq| unicode:: U+2264
+
+ .. versionchanged:: 0.0.5
+ removed ``only_new`` parameter in favor of using `available()`.
+ """
if self._mode == ANYMEAS:
return None
- return_vals = None
- data_ready = False
- if only_new:
- if self.dr_pin is None:
- data_ready = self._rap_read(2) & 4
- else:
- data_ready = self.dr_pin.value
- if (only_new and data_ready) or not only_new:
- if self.data_mode == ABSOLUTE: # if absolute mode
- return_vals = list(self._rap_read_bytes(0x12, 6))
- return_vals[0] &= 0x3F # buttons
- return_vals[2] |= (return_vals[4] & 0x0F) << 8 # x
- return_vals[3] |= (return_vals[4] & 0xF0) << 4 # y
- return_vals[5] &= 0x3F # z
- del return_vals[4], return_vals[1] # no longer need these
- elif self.data_mode == RELATIVE: # if in relative mode
- return_vals = self._rap_read_bytes(0x12, 4)
- return_vals[0] &= 7
- self.clear_flags()
+ return_vals: Optional[Union[List[int], bytearray]] = None
+ if self.data_mode == ABSOLUTE: # if absolute mode
+ return_vals = list(self._rap_read_bytes(0x12, 6))
+ return_vals[0] &= 0x3F # buttons
+ return_vals[2] |= (return_vals[4] & 0x0F) << 8 # x
+ return_vals[3] |= (return_vals[4] & 0xF0) << 4 # y
+ return_vals[5] &= 0x3F # z
+ del return_vals[4], return_vals[1] # no longer need these
+ elif self.data_mode == RELATIVE: # if in relative mode
+ return_vals = self._rap_read_bytes(0x12, 4)
+ return_vals[0] &= 7
+ self.clear_status_flags()
return return_vals
- def clear_flags(self):
+ def clear_status_flags(self):
"""This function clears the "Data Ready" flag which is reflected with
the ``dr_pin``."""
self._rap_write(2, 0)
time.sleep(0.00005) # per official example from Cirque
@property
- def allow_sleep(self):
+ def allow_sleep(self) -> bool:
"""This attribute specifies if the Pinnacle ASIC is allowed to sleep
- after about 5 seconds of idle (no input event)."""
+ after about 5 seconds of idle (no input event).
+
+ Set this attribute to `True` if you want the Pinnacle ASIC to enter sleep (low power)
+ mode after about 5 seconds of inactivity (does not apply to AnyMeas mode). While the touch
+ controller is in sleep mode, if a touch event or button press is detected, the Pinnacle
+ ASIC will take about 300 milliseconds to wake up (does not include handling the touch event
+ or button press data).
+ """
return bool(self._rap_read(3) & 4)
@allow_sleep.setter
- def allow_sleep(self, is_enabled):
+ def allow_sleep(self, is_enabled: bool):
self._rap_write(3, (self._rap_read(3) & 0xFB) | (is_enabled << 2))
@property
- def shutdown(self):
- """This attribute controls power of the Pinnacle ASIC."""
+ def shutdown(self) -> bool:
+ """This attribute controls power of the Pinnacle ASIC. `True` means powered down
+ (AKA standby mode), and `False` means not powered down (Active, Idle, or Sleep mode).
+
+ .. note::
+ The ASIC will take about 300 milliseconds to complete the transition
+ from powered down mode to active mode. No touch events or button presses will be
+ monitored while powered down.
+ """
return bool(self._rap_read(3) & 2)
@shutdown.setter
- def shutdown(self, is_off):
+ def shutdown(self, is_off: bool):
self._rap_write(3, (self._rap_read(3) & 0xFD) | (is_off << 1))
@property
- def sample_rate(self):
- """This attribute controls how many samples (of data) per second are
- reported."""
+ def sample_rate(self) -> int:
+ """This attribute controls how many samples (of data) per second are reported.
+
+ Valid values are ``100``, ``80``, ``60``, ``40``, ``20``, ``10``. Any other input values
+ automatically set the sample rate to 100 sps (samples per second). Optionally, ``200`` and
+ ``300`` sps can be specified, but using these values automatically disables palm (referred
+ to as "NERD" in the specification sheet) and noise compensations. These higher values are
+ meant for using a stylus with a 2mm diameter tip, while the values less than 200 are meant
+ for a finger or stylus with a 5.25mm diameter tip.
+
+ This attribute only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`
+ or :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` mode. Otherwise if
+ `data_mode` is set to :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`, then
+ this attribute will have no effect.
+ """
return self._rap_read(9)
@sample_rate.setter
- def sample_rate(self, val):
+ def sample_rate(self, val: int):
if self.data_mode != ANYMEAS:
if val in (200, 300):
# disable palm & noise compensations
@@ -195,19 +405,64 @@ def sample_rate(self, val):
val = val if val in (100, 80, 60, 40, 20, 10) else 100
self._rap_write(9, val)
- def detect_finger_stylus(self, enable_finger=True,
- enable_stylus=True, sample_rate=100):
+ def detect_finger_stylus(
+ self,
+ enable_finger: bool = True,
+ enable_stylus: bool = True,
+ sample_rate: int = 100,
+ ):
"""This function will configure the Pinnacle ASIC to detect either
- finger, stylus, or both."""
+ finger, stylus, or both.
+
+ :param enable_finger: `True` enables the Pinnacle ASIC's measurements to
+ detect if the touch event was caused by a finger or 5.25mm stylus. `False` disables
+ this feature. Default is `True`.
+ :param enable_stylus: `True` enables the Pinnacle ASIC's measurements to
+ detect if the touch event was caused by a 2mm stylus. `False` disables this
+ feature. Default is `True`.
+ :param sample_rate: See the `sample_rate` attribute as this parameter manipulates that
+ attribute.
+
+ .. tip::
+ Consider adjusting the ADC matrix's gain to enhance performance/results using
+ `set_adc_gain()`
+ """
finger_stylus = self._era_read(0x00EB)
finger_stylus |= (enable_stylus << 2) | enable_finger
self._era_write(0x00EB, finger_stylus)
self.sample_rate = sample_rate
- def calibrate(self, run, tap=True, track_error=True, nerd=True,
- background=True):
+ def calibrate(
+ self,
+ run: bool,
+ tap: bool = True,
+ track_error: bool = True,
+ nerd: bool = True,
+ background: bool = True,
+ ):
"""Set calibration parameters when the Pinnacle ASIC calibrates
- itself."""
+ itself.
+
+ This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`
+ or :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` mode. Otherwise if
+ `data_mode` is set to :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`, then this
+ function will have no effect.
+
+ :param run: If `True`, this function forces a calibration of the sensor. If `False`,
+ this function just writes the following parameters to the Pinnacle ASIC's "CalConfig1"
+ register. This parameter is required while the rest are optional keyword parameters.
+ :param tap: Enable dynamic tap compensation? Default is `True`.
+ :param track_error: Enable dynamic track error compensation? Default is `True`.
+ :param nerd: Enable dynamic NERD compensation? Default is `True`. This parameter has
+ something to do with palm detection/compensation.
+ :param background: Enable dynamic background compensation? Default is `True`.
+
+ .. note::
+ According to the datasheet, calibration of the sensor takes about 100
+ milliseconds. This function will block until calibration is complete (if ``run`` is
+ `True`). It is recommended for typical applications to leave all optional parameters
+ in their default states.
+ """
if self.data_mode != ANYMEAS:
cal_config = (tap << 4) | (track_error << 3) | (nerd << 2)
cal_config |= background << 1
@@ -215,70 +470,223 @@ def calibrate(self, run, tap=True, track_error=True, nerd=True,
if run:
while self._rap_read(7) & 1:
pass # calibration is running
- self.clear_flags() # now that calibration is done
+ self.clear_status_flags() # now that calibration is done
@property
- def calibration_matrix(self):
+ def calibration_matrix(self) -> List[int]:
"""This attribute returns a `list` of the 46 signed 16-bit (short)
values stored in the Pinnacle ASIC's memory that is used for taking
- measurements."""
+ measurements.
+
+ This matrix is not applicable in AnyMeas mode. Use this attribute to compare a prior
+ compensation matrix with a new matrix that was either loaded manually by setting this
+ attribute to a `list` of 46 signed 16-bit (short) integers or created internally by calling
+ `calibrate()` with the ``run`` parameter as `True`.
+
+ .. note::
+ A paraphrased note from Cirque's Application Note on Comparing compensation matrices:
+
+ If any 16-bit values are above 20K (absolute), it generally indicates a problem with
+ the sensor. If no values exceed 20K, proceed with the data comparison. Compare each
+ 16-bit value in one matrix to the corresponding 16-bit value in the other matrix. If
+ the difference between the two values is greater than 500 (absolute), it indicates a
+ change in the environment. Either an object was on the sensor during calibration, or
+ the surrounding conditions (temperature, humidity, or noise level) have changed. One
+ strategy is to force another calibration and compare again, if the values continue to
+ differ by 500, determine whether to use the new data or a previous set of stored data.
+ Another strategy is to average any two values that differ by more than 500 and write
+ this new matrix, with the average values, back into Pinnacle ASIC.
+ """
# combine every 2 bytes from resulting buffer into list of signed
# 16-bits integers
- return list(unpack('46h', self._era_read_bytes(0x01DF, 92)))
+ return list(struct.unpack("46h", self._era_read_bytes(0x01DF, 92)))
@calibration_matrix.setter
- def calibration_matrix(self, matrix):
- matrix += [0] * (46 - len(matrix)) # padd short matrices w/ 0s
+ def calibration_matrix(self, matrix: List[int]):
+ matrix += [0] * (46 - len(matrix)) # pad short matrices w/ 0s
for index in range(46):
- buf = pack('h', matrix[index])
+ buf = struct.pack("h", matrix[index])
self._era_write(0x01DF + index * 2, buf[0])
self._era_write(0x01DF + index * 2 + 1, buf[1])
- def set_adc_gain(self, sensitivity):
+ def set_adc_gain(self, sensitivity: int):
"""Sets the ADC gain in range [0,3] to enhance performance based on
- the overlay type"""
+ the overlay type (does not apply to AnyMeas mode).
+
+ :param int sensitivity: This int specifies how sensitive the ADC (Analog to Digital
+ Converter) component is. ``0`` means most sensitive, and ``3`` means least sensitive.
+ A value outside this range will raise a `ValueError` exception.
+
+ .. tip:: The official example code from Cirque for a curved overlay uses a value of ``1``.
+ """
if not 0 <= sensitivity < 4:
raise ValueError("sensitivity is out of bounds [0,3]")
val = self._era_read(0x0187) & 0x3F | (sensitivity << 6)
self._era_write(0x0187, val)
- def tune_edge_sensitivity(self, x_axis_wide_z_min=0x04,
- y_axis_wide_z_min=0x03):
- """Changes thresholds to improve detection of fingers."""
+ def tune_edge_sensitivity(
+ self, x_axis_wide_z_min: int = 0x04, y_axis_wide_z_min: int = 0x03
+ ):
+ """Changes thresholds to improve detection of fingers.
+
+ .. warning::
+ This function was ported from Cirque's example code and doesn't seem to have
+ corresponding documentation. I'm having trouble finding a memory map of the Pinnacle
+ ASIC as this function directly alters values in the Pinnacle ASIC's memory.
+ USE AT YOUR OWN RISK!
+ """
self._era_write(0x0149, x_axis_wide_z_min)
self._era_write(0x0168, y_axis_wide_z_min)
- def anymeas_mode_config(self, gain=GAIN_200, frequency=FREQ_0,
- sample_length=512, mux_ctrl=MUX_PNP,
- apperture_width=500, ctrl_pwr_cnt=1):
+ def anymeas_mode_config(
+ self,
+ gain: int = GAIN_200,
+ frequency: int = FREQ_0,
+ sample_length: int = 512,
+ mux_ctrl: int = MUX_PNP,
+ apperture_width: int = 500,
+ ctrl_pwr_cnt: int = 1,
+ ):
"""This function configures the Pinnacle ASIC to output raw ADC
- measurements."""
+ measurements.
+
+ Be sure to set the `data_mode` attribute to
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` before calling this function
+ otherwise it will do nothing.
+
+ :param gain: Sets the sensitivity of the ADC matrix. Valid values are the constants
+ defined in `AnyMeas mode Gain`_. Defaults to
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.GAIN_200`.
+ :param frequency: Sets the frequency of measurements made by the ADC matrix. Valid
+ values are the constants defined in `AnyMeas mode Frequencies`_.
+ Defaults :attr:`~circuitpython_cirque_pinnacle.glidepoint.FREQ_0`.
+ :param sample_length: Sets the maximum bit length of the measurements made by the ADC
+ matrix. Valid values are ``128``, ``256``, or ``512``. Defaults to ``512``.
+ :param mux_ctrl: The Pinnacle ASIC can employ different bipolar junctions
+ and/or reference capacitors. Valid values are the constants defined in
+ `AnyMeas mode Muxing`_. Additional combination of
+ these constants is also allowed. Defaults to
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.MUX_PNP`.
+ :param apperture_width: Sets the window of time (in nanoseconds) to allow for the ADC
+ to take a measurement. Valid values are multiples of 125 in range [``250``, ``1875``].
+ Erroneous values are clamped/truncated to this range.
+
+ .. note:: The ``apperture_width`` parameter has a inverse relationship/affect on the
+ ``frequency`` parameter. The approximated frequencies described in this
+ documentation are based on an aperture width of 500 nanoseconds, and they will
+ shrink as the apperture width grows or grow as the aperture width shrinks.
+
+ :param ctrl_pwr_cnt: Configure the Pinnacle to perform a number of measurements for
+ each call to `measure_adc()`. Defaults to 1. Constants defined in
+ `AnyMeas mode Control`_ can be used to specify if is sleep
+ is allowed (:attr:`~circuitpython_cirque_pinnacle.glidepoint.CRTL_PWR_IDLE` -- this
+ is not default) or if repetitive measurements is allowed
+ (:attr:`~circuitpython_cirque_pinnacle.glidepoint.CRTL_REPEAT`) if number of
+ measurements is more than 1.
+
+ .. warning::
+ There is no bounds checking on the number of measurements specified
+ here. Specifying more than 63 will trigger sleep mode after performing
+ measurements.
+
+ .. tip::
+ Be aware that allowing the Pinnacle to enter sleep mode after taking
+ measurements will slow consecutive calls to `measure_adc()` as the Pinnacle
+ requires about 300 milliseconds to wake up.
+ """
if self.data_mode == ANYMEAS:
anymeas_config = [2, 3, 4, 0, 4, 0, 19, 0, 0, 1]
anymeas_config[0] = gain | frequency
- anymeas_config[1] = (max(1, min(int(sample_length / 128), 3)))
+ anymeas_config[1] = max(1, min(int(sample_length / 128), 3))
anymeas_config[2] = mux_ctrl
anymeas_config[4] = max(2, min(int(apperture_width / 125), 15))
anymeas_config[9] = ctrl_pwr_cnt
self._rap_write_bytes(5, anymeas_config)
self._rap_write_bytes(0x13, [0] * 8)
- self.clear_flags()
+ self.clear_status_flags()
- def measure_adc(self, bits_to_toggle, toggle_polarity):
+ def measure_adc(self, bits_to_toggle: int, toggle_polarity: int) -> bytearray:
"""This blocking function instigates and returns the measurements (a
- signed short) from the Pinnacle ASIC's ADC (Analog to Digital
- Converter) matrix."""
+ signed short) from the Pinnacle ASIC's ADC (Analog to Digital Converter) matrix.
+
+ Internally this function calls `start_measure_adc()` and `get_measure_adc()` in sequence.
+ Be sure to set the `data_mode` attribute to
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` before calling this function
+ otherwise it will do nothing.
+
+ :Parameters' Context:
+ Each of the parameters are a 4-byte integer (see
+ :ref:`format table below `) in which each bit corresponds to a
+ capacitance sensing electrode in the sensor's matrix (12 electrodes for Y-axis, 16
+ electrodes for X-axis). They are used to compensate for varying capacitances in
+ the electrodes during measurements. **It is highly recommended that the trackpad be
+ installed in a finished/prototyped housing when determining what electrodes to
+ manipulate.** See `AnyMeas mode example `_ to
+ understand how to use these 4-byte integers.
+
+ :param bits_to_toggle: A bit of ``1`` flags that electrode's output for toggling, and a bit
+ of ``0`` signifies that the electrode's output should remain unaffected.
+ :param toggle_polarity: This specifies which polarity the output of the electrode(s)
+ (specified with corresponding bits in ``bits_to_toggle`` parameter) should be toggled
+ (forced). A bit of ``1`` toggles that bit positive, and a bit of ``0`` toggles that
+ bit negative.
+
+ :Returns:
+ A 2-byte `bytearray` that represents a signed short integer. If `data_mode` is not set
+ to :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`, then this function returns
+ `None` and does nothing.
+
+ .. _polynomial-fmt:
+
+ :4-byte Integer Format:
+ Bits 31 & 30 are not used and should remain ``0``. Bits 29 and 28 represent the optional
+ implementation of reference capacitors built into the Pinnacle ASIC. To use these
+ capacitors, the corresponding constants
+ (:attr:`~circuitpython_cirque_pinnacle.glidepoint.MUX_REF0` and/or
+ :attr:`~circuitpython_cirque_pinnacle.glidepoint.MUX_REF1`) must be passed to
+ `anymeas_mode_config()` in the ``mux_ctrl`` parameter, and their representative
+ bits must be flagged in both ``bits_to_toggle`` & ``toggle_polarity`` parameters.
+
+ .. csv-table:: byte 3 (MSByte)
+ :stub-columns: 1
+ :widths: 10, 5, 5, 5, 5, 5, 5, 5, 5
+
+ "bit position",31,30,29,28,27,26,25,24
+ "representation",N/A,N/A,Ref1,Ref0,Y11,Y10,Y9,Y8
+ .. csv-table:: byte 2
+ :stub-columns: 1
+ :widths: 10, 5, 5, 5, 5, 5, 5, 5, 5
+
+ "bit position",23,22,21,20,19,18,17,16
+ "representation",Y7,Y6,Y5,Y4,Y3,Y2,Y1,Y0
+ .. csv-table:: byte 1
+ :stub-columns: 1
+ :widths: 10, 5, 5, 5, 5, 5, 5, 5, 5
+
+ "bit position",15,14,13,12,11,10,9,8
+ "representation",X15,X14,X13,X12,X11,X10,X9,X8
+ .. csv-table:: byte 0 (LSByte)
+ :stub-columns: 1
+ :widths: 10, 5, 5, 5, 5, 5, 5, 5, 5
+
+ "bit position",7,6,5,4,3,2,1,0
+ "representation",X7,X6,X5,X4,X3,X2,X1,X0
+ """
self.start_measure_adc(bits_to_toggle, toggle_polarity)
result = self.get_measure_adc()
while result is None: # wait till measurements are complete
result = self.get_measure_adc() # Pinnacle is still computing
return result
- def start_measure_adc(self, bits_to_toggle, toggle_polarity):
+ def start_measure_adc(self, bits_to_toggle: int, toggle_polarity: int):
"""A non-blocking function that starts measuring ADC values in
- AnyMeas mode."""
+ AnyMeas mode.
+
+ See the parameters and table in `measure_adc()` as this is its helper function, and all
+ parameters there are used the same way here.
+ """
if self._mode == ANYMEAS:
- tog_pol = [] # assemble list of register buffers
+ tog_pol: List[int] = [] # assemble list of register buffers
for i in range(3, -1, -1):
tog_pol.append((bits_to_toggle >> (i * 8)) & 0xFF)
for i in range(3, -1, -1):
@@ -288,91 +696,118 @@ def start_measure_adc(self, bits_to_toggle, toggle_polarity):
# initiate measurements
self._rap_write(3, self._rap_read(3) | 0x18)
- def get_measure_adc(self):
+ def get_measure_adc(self) -> Optional[bytearray]:
"""A non-blocking function that returns ADC measurement on
- completion."""
+ completion.
+
+ This function is only meant ot be used in conjunction with `start_measure_adc()` for
+ non-blocking application.
+
+ :returns:
+ * `None` if `data_mode` is not set to `ANYMEAS` or if the "data ready" pin's signal is
+ not active (while `data_mode` is set to `ANYMEAS`) meaning the Pinnacle ASIC is still
+ computing the ADC measurements based on the 4-byte polynomials passed to
+ `start_measure_adc()`.
+ * a `bytearray` that represents a signed 16-bit integer upon completed ADC measurements
+ based on the 4-byte polynomials passed to `start_measure_adc()`.
+ """
if self._mode != ANYMEAS:
return None
- if not self.dr_pin.value:
+ if self.dr_pin is not None and not self.dr_pin.value:
return None
result = self._rap_read_bytes(0x11, 2)
- self.clear_flags()
+ self.clear_status_flags()
return result
- def _rap_read(self, reg):
+ def _rap_read(self, reg: int) -> int:
raise NotImplementedError()
- def _rap_read_bytes(self, reg, numb_bytes):
+ def _rap_read_bytes(self, reg: int, numb_bytes: int) -> bytearray:
raise NotImplementedError()
- def _rap_write(self, reg, value):
+ def _rap_write(self, reg: int, value: int):
raise NotImplementedError()
- def _rap_write_bytes(self, reg, values):
+ def _rap_write_bytes(self, reg: int, values: List[int]):
raise NotImplementedError()
- def _era_read(self, reg):
+ def _era_read(self, reg: int) -> int:
prev_feed_state = self.feed_enable
self.feed_enable = False # accessing raw memory, so do this
- self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xff])
+ self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xFF])
self._rap_write(0x1E, 1) # indicate reading only 1 byte
while self._rap_read(0x1E): # read until reg == 0
pass # also sets Command Complete flag in Status register
buf = self._rap_read(0x1B) # get value
- self.clear_flags()
+ self.clear_status_flags()
self.feed_enable = prev_feed_state # resume previous feed state
return buf
- def _era_read_bytes(self, reg, numb_bytes):
+ def _era_read_bytes(self, reg: int, numb_bytes: int) -> bytes:
buf = b""
prev_feed_state = self.feed_enable
self.feed_enable = False # accessing raw memory, so do this
- self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xff])
+ self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xFF])
for _ in range(numb_bytes):
self._rap_write(0x1E, 5) # indicate reading sequential bytes
while self._rap_read(0x1E): # read until reg == 0
pass # also sets Command Complete flag in Status register
buf += bytes([self._rap_read(0x1B)]) # get value
- self.clear_flags()
+ self.clear_status_flags()
self.feed_enable = prev_feed_state # resume previous feed state
return buf
- def _era_write(self, reg, value):
+ def _era_write(self, reg: int, value: int):
prev_feed_state = self.feed_enable
self.feed_enable = False # accessing raw memory, so do this
self._rap_write(0x1B, value) # write value
- self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xff])
+ self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xFF])
self._rap_write(0x1E, 2) # indicate writing only 1 byte
while self._rap_read(0x1E): # read until reg == 0
pass # also sets Command Complete flag in Status register
- self.clear_flags()
+ self.clear_status_flags()
self.feed_enable = prev_feed_state # resume previous feed state
- def _era_write_bytes(self, reg, value, numb_bytes):
+ def _era_write_bytes(self, reg: int, value: int, numb_bytes: int):
# rarely used as it only writes 1 value to multiple registers
prev_feed_state = self.feed_enable
self.feed_enable = False # accessing raw memory, so do this
self._rap_write(0x1B, value) # write value
- self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xff])
+ self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xFF])
self._rap_write(0x1E, 0x0A) # indicate writing sequential bytes
for _ in range(numb_bytes):
while self._rap_read(0x1E): # read until reg == 0
pass # also sets Command Complete flag in Status register
- self.clear_flags()
+ self.clear_status_flags()
self.feed_enable = prev_feed_state # resume previous feed state
+
# pylint: disable=no-member
class PinnacleTouchI2C(PinnacleTouch):
"""Parent class for interfacing with the Pinnacle ASIC via the I2C
- protocol."""
- def __init__(self, i2c, address=0x2A, dr_pin=None):
+ protocol.
+
+ :param ~busio.I2C i2c: The object of the I2C bus to use. This object must be shared among
+ other driver classes that use the same I2C bus (SDA & SCL pins).
+ :param int address: The slave I2C address of the Pinnacle ASIC. Defaults to ``0x2A``.
+ :param ~digitalio.DigitalInOut dr_pin: |dr_pin_parameter|
+
+ .. important:: |dr_pin_note|
+ """
+
+ def __init__(
+ self,
+ i2c: busio.I2C,
+ address: int = 0x2A,
+ dr_pin: Optional[digitalio.DigitalInOut] = None,
+ ):
self._i2c = I2CDevice(i2c, address)
- super(PinnacleTouchI2C, self).__init__(dr_pin=dr_pin)
+ super().__init__(dr_pin=dr_pin)
- def _rap_read(self, reg):
- return self._rap_read_bytes(reg, 1)
+ def _rap_read(self, reg: int) -> int:
+ return self._rap_read_bytes(reg, 1)[0]
- def _rap_read_bytes(self, reg, numb_bytes):
+ def _rap_read_bytes(self, reg: int, numb_bytes: int) -> bytearray:
buf = bytes([reg | 0xA0]) # per datasheet
with self._i2c as i2c:
i2c.write(buf) # includes a STOP condition
@@ -381,10 +816,10 @@ def _rap_read_bytes(self, reg, numb_bytes):
i2c.readinto(buf)
return buf
- def _rap_write(self, reg, value):
+ def _rap_write(self, reg: int, value: int):
self._rap_write_bytes(reg, [value])
- def _rap_write_bytes(self, reg, values):
+ def _rap_write_bytes(self, reg: int, values: List[int]):
buf = b""
for index, byte in enumerate(values):
# Pinnacle doesn't auto-increment register
@@ -394,22 +829,38 @@ def _rap_write_bytes(self, reg, values):
with self._i2c as i2c:
i2c.write(buf)
+
class PinnacleTouchSPI(PinnacleTouch):
"""Parent class for interfacing with the Pinnacle ASIC via the SPI
- protocol."""
- def __init__(self, spi, ss_pin, spi_frequency=12000000, dr_pin=None):
- self._spi = SPIDevice(spi, chip_select=ss_pin, phase=1,
- baudrate=spi_frequency)
- super(PinnacleTouchSPI, self).__init__(dr_pin=dr_pin)
-
- def _rap_read(self, reg):
+ protocol.
+
+ :param ~busio.SPI spi: The object of the SPI bus to use. This object must be shared among
+ other driver classes that use the same SPI bus (MOSI, MISO, & SCK pins).
+ :param ~digitalio.DigitalInOut ss_pin: The "slave select" pin output to the Pinnacle ASIC.
+ :param int spi_frequency: The SPI bus speed in Hz. Default is 12 MHz.
+ :param ~digitalio.DigitalInOut dr_pin: |dr_pin_parameter|
+
+ .. important:: |dr_pin_note|
+ """
+
+ def __init__(
+ self,
+ spi: busio.SPI,
+ ss_pin: digitalio.DigitalInOut,
+ spi_frequency: int = 12000000,
+ dr_pin: Optional[digitalio.DigitalInOut] = None,
+ ):
+ self._spi = SPIDevice(spi, chip_select=ss_pin, phase=1, baudrate=spi_frequency)
+ super().__init__(dr_pin=dr_pin)
+
+ def _rap_read(self, reg: int) -> int:
buf_out = bytes([reg | 0xA0]) + b"\xFB" * 3
buf_in = bytearray(len(buf_out))
with self._spi as spi:
spi.write_readinto(buf_out, buf_in)
return buf_in[3]
- def _rap_read_bytes(self, reg, numb_bytes):
+ def _rap_read_bytes(self, reg: int, numb_bytes: int) -> bytearray:
# using auto-increment method
buf_out = bytes([reg | 0xA0]) + b"\xFC" * (1 + numb_bytes) + b"\xFB"
buf_in = bytearray(len(buf_out))
@@ -417,11 +868,11 @@ def _rap_read_bytes(self, reg, numb_bytes):
spi.write_readinto(buf_out, buf_in)
return buf_in[3:]
- def _rap_write(self, reg, value):
+ def _rap_write(self, reg: int, value: int):
buf = bytes([(reg | 0x80), value])
with self._spi as spi:
spi.write(buf)
- def _rap_write_bytes(self, reg, values):
+ def _rap_write_bytes(self, reg: int, values: List[int]):
for i, val in enumerate(values):
self._rap_write(reg + i, val)
diff --git a/circuitpython_cirque_pinnacle/glidepoint_lite.py b/circuitpython_cirque_pinnacle/glidepoint_lite.py
index 4c04dbc..ca72243 100644
--- a/circuitpython_cirque_pinnacle/glidepoint_lite.py
+++ b/circuitpython_cirque_pinnacle/glidepoint_lite.py
@@ -3,14 +3,17 @@
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle.git"
import time
+from micropython import const
+
try:
from ubus_device import SPIDevice, I2CDevice
except ImportError:
from adafruit_bus_device.spi_device import SPIDevice
from adafruit_bus_device.i2c_device import I2CDevice
-RELATIVE = 0x00
-ABSOLUTE = 0x02
+RELATIVE = const(0x00)
+ABSOLUTE = const(0x02)
+
class PinnacleTouch:
def __init__(self, dr_pin=None):
@@ -19,12 +22,12 @@ def __init__(self, dr_pin=None):
self.dr_pin.switch_to_input()
firmware_id, firmware_ver = self._rap_read_bytes(0, 2)
if firmware_id != 7 or firmware_ver != 0x3A:
- raise OSError("Cirque Pinnacle ASIC not responding")
+ raise RuntimeError("Cirque Pinnacle ASIC not responding")
self._mode = 0
self.sample_rate = 100
self._rap_write(0x0A, 30)
self._rap_write_bytes(3, [0, 1, 2])
- self.clear_flags()
+ self.clear_status_flags()
@property
def feed_enable(self):
@@ -43,51 +46,51 @@ def data_mode(self):
@data_mode.setter
def data_mode(self, mode):
- if mode not in (RELATIVE, ABSOLUTE):
- raise ValueError("Unrecognised input value for data_mode.")
- self._rap_write(4, 1 | mode)
- self._mode = mode
+ self._mode = bool(mode) * 2
+ self._rap_write(4, 1 | self._mode)
@property
def hard_configured(self):
- return bool(self._rap_read(0x1f))
-
- def relative_mode_config(self, rotate90=False, taps=True,
- secondary_tap=True, glide_extend=True,
- intellimouse=False):
+ return bool(self._rap_read(0x1F))
+
+ def relative_mode_config(
+ self,
+ rotate90=False,
+ taps=True,
+ secondary_tap=True,
+ glide_extend=True,
+ intellimouse=False,
+ ):
config2 = (rotate90 << 7) | ((not glide_extend) << 4)
config2 |= ((not secondary_tap) << 2) | ((not taps) << 1)
self._rap_write(5, config2 | bool(intellimouse))
- def absolute_mode_config(self, z_idle_count=30,
- invert_x=False, invert_y=False):
+ def absolute_mode_config(self, z_idle_count=30, invert_x=False, invert_y=False):
self._rap_write(0x0A, max(0, min(z_idle_count, 255)))
config1 = self._rap_read(4) & 0x3F | (invert_y << 7)
self._rap_write(4, config1 | (invert_x << 6))
- def report(self, only_new=True):
+ def available(self):
+ if self.dr_pin is None:
+ return bool(self._rap_read(2) & 4)
+ return self.dr_pin.value
+
+ def read(self):
return_vals = None
- data_ready = False
- if only_new:
- if self.dr_pin is None:
- data_ready = self._rap_read(2) & 4
- else:
- data_ready = self.dr_pin.value
- if (only_new and data_ready) or not only_new:
- if self.data_mode == ABSOLUTE:
- return_vals = list(self._rap_read_bytes(0x12, 6))
- return_vals[0] &= 0x3F
- return_vals[2] |= (return_vals[4] & 0x0F) << 8
- return_vals[3] |= (return_vals[4] & 0xF0) << 4
- return_vals[5] &= 0x3F
- del return_vals[4], return_vals[1]
- elif self.data_mode == RELATIVE:
- return_vals = self._rap_read_bytes(0x12, 4)
- return_vals[0] &= 7
- self.clear_flags()
+ if self.data_mode == ABSOLUTE:
+ return_vals = list(self._rap_read_bytes(0x12, 6))
+ return_vals[0] &= 0x3F
+ return_vals[2] |= (return_vals[4] & 0x0F) << 8
+ return_vals[3] |= (return_vals[4] & 0xF0) << 4
+ return_vals[5] &= 0x3F
+ del return_vals[4], return_vals[1]
+ elif self.data_mode == RELATIVE:
+ return_vals = self._rap_read_bytes(0x12, 4)
+ return_vals[0] &= 7
+ self.clear_status_flags()
return return_vals
- def clear_flags(self):
+ def clear_status_flags(self):
self._rap_write(2, 0)
time.sleep(0.00005)
@@ -97,7 +100,7 @@ def allow_sleep(self):
@allow_sleep.setter
def allow_sleep(self, is_enabled):
- self._rap_write(3, (self._rap_read(3) & 0xFB) | (is_enabled << 2))
+ self._rap_write(3, (self._rap_read(3) & 0xFB) | (bool(is_enabled) << 2))
@property
def shutdown(self):
@@ -105,7 +108,7 @@ def shutdown(self):
@shutdown.setter
def shutdown(self, is_off):
- self._rap_write(3, (self._rap_read(3) & 0xFD) | (is_off << 1))
+ self._rap_write(3, (self._rap_read(3) & 0xFD) | (bool(is_off) << 1))
@property
def sample_rate(self):
@@ -141,26 +144,26 @@ def _rap_write_bytes(self, reg, values):
def _era_read(self, reg):
prev_feed_state = self.feed_enable
self.feed_enable = False
- self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xff])
+ self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xFF])
self._rap_write(0x1E, 1)
while self._rap_read(0x1E):
pass
buf = self._rap_read(0x1B)
- self.clear_flags()
+ self.clear_status_flags()
self.feed_enable = prev_feed_state
return buf
def _era_read_bytes(self, reg, numb_bytes):
- buf = b''
+ buf = b""
prev_feed_state = self.feed_enable
self.feed_enable = False
- self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xff])
+ self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xFF])
for _ in range(numb_bytes):
self._rap_write(0x1E, 5)
while self._rap_read(0x1E):
pass
buf += bytes([self._rap_read(0x1B)])
- self.clear_flags()
+ self.clear_status_flags()
self.feed_enable = prev_feed_state
return buf
@@ -168,18 +171,19 @@ def _era_write(self, reg, value):
prev_feed_state = self.feed_enable
self.feed_enable = False
self._rap_write(0x1B, value)
- self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xff])
+ self._rap_write_bytes(0x1C, [reg >> 8, reg & 0xFF])
self._rap_write(0x1E, 2)
while self._rap_read(0x1E):
pass
- self.clear_flags()
+ self.clear_status_flags()
self.feed_enable = prev_feed_state
+
# pylint: disable=no-member
class PinnacleTouchI2C(PinnacleTouch):
def __init__(self, i2c, address=0x2A, dr_pin=None):
self._i2c = I2CDevice(i2c, address)
- super(PinnacleTouchI2C, self).__init__(dr_pin=dr_pin)
+ super().__init__(dr_pin=dr_pin)
def _rap_read(self, reg):
return self._rap_read_bytes(reg, 1)
@@ -202,11 +206,11 @@ def _rap_write_bytes(self, reg, values):
with self._i2c as i2c:
i2c.write(buf)
+
class PinnacleTouchSPI(PinnacleTouch):
def __init__(self, spi, ss_pin, spi_frequency=12000000, dr_pin=None):
- self._spi = SPIDevice(spi, chip_select=ss_pin, phase=1,
- baudrate=spi_frequency)
- super(PinnacleTouchSPI, self).__init__(dr_pin=dr_pin)
+ self._spi = SPIDevice(spi, chip_select=ss_pin, phase=1, baudrate=spi_frequency)
+ super().__init__(dr_pin=dr_pin)
def _rap_read(self, reg):
buf_out = bytes([reg | 0xA0]) + b"\xFB" * 3
diff --git a/docs/_static/Logo.png b/docs/_static/Logo.png
new file mode 100644
index 0000000..79a714f
Binary files /dev/null and b/docs/_static/Logo.png differ
diff --git a/docs/_static/darkness.css b/docs/_static/darkness.css
deleted file mode 100644
index 5ad759e..0000000
--- a/docs/_static/darkness.css
+++ /dev/null
@@ -1,334 +0,0 @@
-/* -----------------------------code sections------------------------------ */
-.highlight {
- background: #202020;
-}
-
-.highlight .s1 {
- color: #da8c00;
-}
-
-.highlight .mi {
- color: #9ff1c6;
-}
-
-.highlight .nb {
- color: #f7ef84;
-}
-
-.highlight .ow {
- color: #1f95cb;
-}
-
-.highlight .kc {
- color: #2886e4;
-}
-
-.highlight .s2 {
- color: #da8c00;
-}
-
-.highlight .mf {
- color: #9ff1c6;
-}
-
-.highlight .se {
- color: #e2c458;
-}
-
-.highlight .si {
- color: #2886e4;
-}
-
-.highlight .sa {
- color: #2886e4;
-}
-
-.highlight .nf {
- color: #f7ef84;
-}
-
-.highlight .k {
- color: #af63ab;
-}
-
-.highlight .c1 {
- color: #4bbc3f;
-}
-
-.highlight .o {
- color: #fefefe;
-}
-
-.highlight .sd {
- color: #da8c00;
-}
-
-.highlight .nn {
- color: #fff;
-}
-
-.highlight .kn {
- color: #af63ab;
-}
-
-.highlight .bp {
- color: #1f95cb;
-}
-
-.highlight .nd {
- color: #f7ef84;
-}
-
-.highlight .ne {
- color: #13d297;
-}
-
-.highlight .mh {
- color: #9ff1c6;
-}
-
-.highlight .go {
- color: #1afd00;
- }
-
-/* ----------------------table sections---------------------------------------- */
-.wy-table thead,
-.rst-content table.docutils thead,
-.rst-content table.field-list thead {
- color:#fcfcfc;
- text-align:center;
- background-color: #1a4228;
-}
-
-.wy-table-odd td,
-.wy-table-striped tr:nth-child(2n-1) td,
-.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
- background-color:#3d3d3d;
-}
-
-.wy-table-bordered-all td,
-.rst-content table.docutils td {
- border-bottom:1px solid #e1e4e5;
- border-left:1px solid #e1e4e5;
- text-align: center;
-}
-
-/* ------------------------admonition sections------------------------------- */
-.wy-alert.wy-alert-success .wy-alert-title,
-.rst-content .wy-alert-success.note .wy-alert-title,
-.rst-content .wy-alert-success.attention .wy-alert-title,
-.rst-content .wy-alert-success.caution .wy-alert-title,
-.rst-content .wy-alert-success.danger .wy-alert-title,
-.rst-content .wy-alert-success.error .wy-alert-title,
-.rst-content .hint .wy-alert-title,
-.rst-content .important .wy-alert-title,
-.rst-content .tip .wy-alert-title,
-.rst-content .wy-alert-success.warning .wy-alert-title,
-.rst-content .wy-alert-success.seealso .wy-alert-title,
-.rst-content .wy-alert-success.admonition-todo .wy-alert-title,
-.rst-content .wy-alert-success.admonition .wy-alert-title,
-.wy-alert.wy-alert-success .rst-content .admonition-title,
-.rst-content .wy-alert.wy-alert-success .admonition-title,
-.rst-content .wy-alert-success.note .admonition-title,
-.rst-content .wy-alert-success.attention .admonition-title,
-.rst-content .wy-alert-success.caution .admonition-title,
-.rst-content .wy-alert-success.danger .admonition-title,
-.rst-content .wy-alert-success.error .admonition-title,
-.rst-content .hint .admonition-title,
-.rst-content .important .admonition-title,
-.rst-content .tip .admonition-title,
-.rst-content .wy-alert-success.warning .admonition-title,
-.rst-content .wy-alert-success.seealso .admonition-title,
-.rst-content .wy-alert-success.admonition-todo .admonition-title,
-.rst-content .wy-alert-success.admonition .admonition-title {
- background:#05886e;
-}
-
-.wy-alert.wy-alert-success,
-.rst-content .wy-alert-success.note,
-.rst-content .wy-alert-success.attention,
-.rst-content .wy-alert-success.caution,
-.rst-content .wy-alert-success.danger,
-.rst-content .wy-alert-success.error,
-.rst-content .hint,
-.rst-content .important,
-.rst-content .tip,
-.rst-content .wy-alert-success.warning,
-.rst-content .wy-alert-success.seealso,
-.rst-content .wy-alert-success.admonition-todo,
-.rst-content .wy-alert-success.admonition {
- background: #28443e;
-}
-
-.wy-alert.wy-alert-info .wy-alert-title, .rst-content .note .wy-alert-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .rst-content .note .admonition-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .seealso .admonition-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition .admonition-title {
- background: #064873;
-}
-
-.wy-alert.wy-alert-info, .rst-content .note, .rst-content .wy-alert-info.attention, .rst-content .wy-alert-info.caution, .rst-content .wy-alert-info.danger, .rst-content .wy-alert-info.error, .rst-content .wy-alert-info.hint, .rst-content .wy-alert-info.important, .rst-content .wy-alert-info.tip, .rst-content .wy-alert-info.warning, .rst-content .seealso, .rst-content .wy-alert-info.admonition-todo, .rst-content .wy-alert-info.admonition {
- background: #2d3d48;
-}
-
-.wy-alert.wy-alert-warning .wy-alert-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .attention .wy-alert-title, .rst-content .caution .wy-alert-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .attention .admonition-title, .rst-content .caution .admonition-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .warning .admonition-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .admonition-todo .admonition-title, .rst-content .wy-alert-warning.admonition .admonition-title {
- background: #ed2222;
-}
-
-.wy-alert.wy-alert-warning, .rst-content .wy-alert-warning.note, .rst-content .attention, .rst-content .caution, .rst-content .wy-alert-warning.danger, .rst-content .wy-alert-warning.error, .rst-content .wy-alert-warning.hint, .rst-content .wy-alert-warning.important, .rst-content .wy-alert-warning.tip, .rst-content .warning, .rst-content .wy-alert-warning.seealso, .rst-content .admonition-todo, .rst-content .wy-alert-warning.admonition {
- background: #490707;
-}
-
-/* -------------------------------------general page styling-------------------------------------------- */
-body {
- color:#fcfcfc;
-}
-
-.wy-nav-content-wrap, .wy-nav-content {
- background:#242424;
-}
-
-/* -------------------------------------sidebar sections------------------------------------------------ */
-.wy-side-nav-search {
- background-color:#006B09;
- color:#fcfcfc;
-}
-
-.wy-side-nav-search input[type=text] {
- background: #3e3e3e;
- color: #fcfcfc;
-}
-
-.wy-menu-vertical li.on a,
-.wy-menu-vertical li.current>a {
- color:#fcfcfc;
- background:#242424;
-}
-
-.wy-nav-side {
- background:#172353;
-}
-
-.wy-menu-vertical li.on a:hover,
-.wy-menu-vertical li.current>a:hover {
- background:#395c62;
-}
-
-.wy-menu-vertical li.on a:hover,
-.wy-menu-vertical li.current>a:hover {
- background:#395c62;
-}
-
-.wy-side-nav-search>div.version {
- color:rgba(255, 255, 255, 0.69);
-}
-
-.wy-menu-vertical header,
-.wy-menu-vertical p.caption {
- color:#43df96;
-}
-
-.wy-nav-top {
- background:#006B09;
-}
-
-.wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.current > a span.toctree-expand {
- color: #f2f2f2;
-}
-
-.wy-menu-vertical li span.toctree-expand {
- color: #f2f2f2;
-}
-
-.wy-menu-vertical li.current {
- background: #034e69;
-}
-
-.wy-menu-vertical li.toctree-l2 a,
-.wy-menu-vertical li.toctree-l3 a,
-.wy-menu-vertical li.toctree-l4 a {
- color:#f2f2f2;
-}
-
-.wy-menu-vertical li.current a:hover {
- background:#3e3e3ecf;
-}
-
-.wy-menu-vertical li.toctree-l2.current>a {
- background:#242424;
-}
-
-.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a {
- background:#033969;
-}
-
-.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a {
- background:#092d21;
-}
-
-/* -----------------------------------------API sections-------------------------------------- */
-.wy-table caption,
-.rst-content table.docutils caption,
-.rst-content table.field-list caption {
- color:#fff;
- text-align: left;
-}
-
-.rst-content table.docutils.citation tt,
-.rst-content table.docutils.citation code,
-.rst-content table.docutils.footnote tt,
-.rst-content table.docutils.footnote code {
- color:#16ff00;
-}
-
-.wy-table-bordered-all td, .rst-content table.docutils td {
- text-align: left;
-}
-
-.rst-content table.docutils.citation, .rst-content table.docutils.footnote {
- color: white;
-}
-
-.rst-content dl:not(.docutils) dl dt {
- background: #343434;
- color: #e5df8e;
-}
-
-.rst-content tt, .rst-content tt, .rst-content code {
- color: #f3f3f3;
-}
-
-.rst-content dl:not(.docutils) dt {
- background: #2e363c;
-}
-
-.rst-content tt.literal, .rst-content tt.literal, .rst-content code.literal {
- color: #16FF00;
- border-color: #303030;
-}
-
-code, .rst-content tt, .rst-content code {
- background: #000;
-}
-
-.rst-content tt.xref, a .rst-content tt, .rst-content tt.xref, .rst-content code.xref, a .rst-content tt, a .rst-content code {
- color: #fff;
-}
-
-.rst-content dl:not(.docutils) dl dt {
- background: #343434;
- color: #e5df8e;
-}
-
-.rst-content dl:not(.docutils) dl dt .headerlink {
- color: #29ae5b;
-}
-
-.rst-content dl:not(.docutils) dt .headerlink {
- color: #29ae5b4d !important;
-}
-
-.rst-content dl dt .headerlink::after {
- visibility: visible;
-}
-
-.rst-content h1:hover .headerlink::after, .rst-content h2:hover .headerlink::after, .rst-content .toctree-wrapper p.caption:hover .headerlink::after, .rst-content h3:hover .headerlink::after, .rst-content h4:hover .headerlink::after, .rst-content h5:hover .headerlink::after, .rst-content h6:hover .headerlink::after, .rst-content dl dt:hover .headerlink::after, .rst-content p.caption:hover .headerlink::after, .rst-content table > caption:hover .headerlink::after, .rst-content .code-block-caption:hover .headerlink::after {
- color: #29ae5b !important;
-}
diff --git a/docs/_static/extra_css.css b/docs/_static/extra_css.css
new file mode 100644
index 0000000..2b55bc1
--- /dev/null
+++ b/docs/_static/extra_css.css
@@ -0,0 +1,10 @@
+
+th {
+ background-color: var(--md-default-fg-color--lightest);
+}
+
+.md-nav.md-nav--primary > label {
+ white-space: normal;
+ line-height: inherit;
+ padding-top: 3.5rem;
+}
diff --git a/docs/about_lite.rst b/docs/about_lite.rst
new file mode 100644
index 0000000..b2781c1
--- /dev/null
+++ b/docs/about_lite.rst
@@ -0,0 +1,18 @@
+
+About the lite version
+======================
+
+This library includes a "lite" version of the module ``glidepoint.py`` titled ``glidepoint_lite.py``.
+The lite version is limited to only Relative and Absolute data modes. It has been developed to
+save space on microcontrollers with limited amount of RAM and/or storage (like boards using the
+ATSAMD21 M0). The following functionality has been removed from the lite version:
+
+* `anymeas_mode_config()`
+* `measure_adc()`
+* `detect_finger_stylus()`
+* `calibrate()`
+* `calibration_matrix`
+* `set_adc_gain()`
+* `tune_edge_sensitivity()`
+* ``_era_write_bytes()`` (private member for accessing the Pinnacle ASIC's memory)
+* all comments and docstrings (meaning ``help()`` will provide no specific information)
diff --git a/docs/anymeas.rst b/docs/anymeas.rst
new file mode 100644
index 0000000..796ad88
--- /dev/null
+++ b/docs/anymeas.rst
@@ -0,0 +1,95 @@
+
+AnyMeas mode API
+================
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.anymeas_mode_config
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.measure_adc
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.start_measure_adc
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.get_measure_adc
+
+AnyMeas mode Gain
+-----------------
+
+Allowed ADC gain configurations of AnyMeas mode. The percentages defined here are approximate
+values.
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.GAIN_100
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.GAIN_133
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.GAIN_166
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.GAIN_200
+ :no-value:
+
+AnyMeas mode Frequencies
+------------------------
+
+Allowed frequency configurations of AnyMeas mode. The frequencies defined here are
+approximated based on an aperture width of 500 nanoseconds. If the ``aperture_width``
+parameter to `anymeas_mode_config()` specified is less than 500 nanoseconds, then the
+frequency will be larger than what is described here (& vice versa).
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.FREQ_0
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.FREQ_1
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.FREQ_2
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.FREQ_3
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.FREQ_4
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.FREQ_5
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.FREQ_6
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.FREQ_7
+ :no-value:
+
+AnyMeas mode Muxing
+-------------------
+
+Allowed muxing gate polarity and reference capacitor configurations of AnyMeas mode.
+Combining these values (with ``+`` operator) is allowed.
+
+.. note::
+ The sign of the measurements taken in AnyMeas mode is inverted depending on which
+ muxing gate is specified (when specifying an individual gate polarity).
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.MUX_REF1
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.MUX_REF0
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.MUX_PNP
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.MUX_NPN
+ :no-value:
+
+AnyMeas mode Control
+--------------------
+
+These constants control the number of measurements performed in `measure_adc()`.
+The number of measurements can range [0, 63].
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.CRTL_REPEAT
+ :no-value:
+
+.. autodata:: circuitpython_cirque_pinnacle.glidepoint.CRTL_PWR_IDLE
+ :no-value:
diff --git a/docs/api.rst b/docs/api.rst
index 9dd6aef..8804a5b 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -1,644 +1,43 @@
-.. currentmodule:: circuitpython_cirque_pinnacle
-
-About the lite version
-======================
-
-This library includes a "lite" version of the module ``glidepoint.py`` titled ``glidepoint_lite.py``.
-The lite version is limited to only Relative and Absolute data modes. It has been developed to
-save space on microcontrollers with limited amount of RAM and/or storage (like boards using the
-ATSAMD21 M0). The following functionality has been removed from the lite version:
-
- * `anymeas_mode_config()`
- * `measure_adc()`
- * `detect_finger_stylus()`
- * `calibrate()`
- * `calibration_matrix`
- * `set_adc_gain()`
- * `tune_edge_sensitivity()`
- * ``_era_write_bytes()`` (private member for accessing the Pinnacle ASIC's memory)
- * all comments and docstrings (meaning ``help()`` will provide no specific information)
-
PinnacleTouch API
==================
-Accepted Constants
-------------------
-
Data Modes
-***********
- Allowed symbols for configuring the Pinanacle ASIC's data reporting/measurements.
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.RELATIVE
- :annotation: =0
-
- Alias symbol for specifying Relative mode (AKA Mouse mode).
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.ANYMEAS
- :annotation: =1
-
- Alias symbol for specifying "AnyMeas" mode (raw ADC measurement)
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE
- :annotation: =2
-
- Alias symbol for specifying Absolute mode (axis positions)
-
-AnyMeas mode Gain
-******************
-
- Allowed ADC gain configurations of AnyMeas mode. The percentages defined here are approximate
- values.
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.GAIN_100
-
- around 100% gain
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.GAIN_133
-
- around 133% gain
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.GAIN_166
-
- around 166% gain
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.GAIN_200
-
- around 200% gain
-
-
-AnyMeas mode Frequencies
-************************
-
- Allowed frequency configurations of AnyMeas mode. The frequencies defined here are
- approximated based on an aperture width of 500 nanoseconds. If the ``aperture_width``
- parameter to `anymeas_mode_config()` specified is less than 500 nanoseconds, then the
- frequency will be larger than what is described here (& vice versa).
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.FREQ_0
-
- frequency around 500,000Hz
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.FREQ_1
-
- frequency around 444,444Hz
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.FREQ_2
-
- frequency around 400,000Hz
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.FREQ_3
-
- frequency around 363,636Hz
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.FREQ_4
-
- frequency around 333,333Hz
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.FREQ_5
-
- frequency around 307,692Hz
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.FREQ_6
-
- frequency around 267,000Hz
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.FREQ_7
-
- frequency around 235,000Hz
-
-
-AnyMeas mode Muxing
-*******************
+----------
- Allowed muxing gate polarity and reference capacitor configurations of AnyMeas mode.
- Combining these values (with ``+`` operator) is allowed.
+Allowed symbols for configuring the Pinnacle ASIC's data reporting/measurements.
- .. note:: The sign of the measurements taken in AnyMeas mode is inverted depending on which
- muxing gate is specified (when specifying an individual gate polarity).
+.. data:: circuitpython_cirque_pinnacle.glidepoint.RELATIVE
+ :annotation: = 0
- .. data:: circuitpython_cirque_pinnacle.glidepoint.MUX_REF1
+ Alias symbol for specifying Relative mode (AKA Mouse mode).
- enables a builtin capacitor (~0.5pF). See note in `measure_adc()`
+.. data:: circuitpython_cirque_pinnacle.glidepoint.ANYMEAS
+ :annotation: = 1
- .. data:: circuitpython_cirque_pinnacle.glidepoint.MUX_REF0
+ Alias symbol for specifying "AnyMeas" mode (raw ADC measurement)
- enables a builtin capacitor (~0.25pF). See note in `measure_adc()`
+.. data:: circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE
+ :annotation: = 2
- .. data:: circuitpython_cirque_pinnacle.glidepoint.MUX_PNP
+ Alias symbol for specifying Absolute mode (axis positions)
- enable PNP sense line
- .. data:: circuitpython_cirque_pinnacle.glidepoint.MUX_NPN
+PinnacleTouch class
+-------------------
- enable NPN sense line
-
-
-AnyMeas mode Control
-********************
-
- These constants control the number of measurements performed in `measure_adc()`.
- The number of measurements can range [0, 63].
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.CRTL_REPEAT
-
- required for more than 1 measurement
-
- .. data:: circuitpython_cirque_pinnacle.glidepoint.CRTL_PWR_IDLE
-
- triggers low power mode (sleep) after completing measurements
-
-
-PinnacleTouch
--------------
-
-.. |dr_pin_parameter| replace:: The input pin connected to the Pinnacle ASIC's "Data
- Ready" pin. If this parameter is not specified, then the SW_DR (software data ready) flag
- of the STATUS register is used to detirmine if the data being reported is new.
-
-.. |dr_pin_note| replace:: This parameter must be specified if your application is going to use the
- Pinnacle ASIC's :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`
- mode (a rather experimental measuring of raw ADC values).
-
-
-Constructor
-*************************
-
- .. autoclass:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch
- :no-members:
-
- :param ~microcontroller.Pin dr_pin: |dr_pin_parameter|
-
- .. important:: |dr_pin_note|
-
-data_mode
-*************************
+.. autoclass:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch
+ :no-members:
.. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.data_mode
- Valid input values are :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE` for
- relative/mouse mode, :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` for
- absolute positioning mode, or :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`
- (referred to as "AnyMeas" in specification sheets) mode for reading ADC values.
-
- :Returns:
-
- - ``0`` for Relative mode (AKA mouse mode)
- - ``1`` for AnyMeas mode (raw ADC measurements)
- - ``2`` for Absolute mode (X & Y axis positions)
-
- .. important:: When switching from :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE` or
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` all configurations are reset, and
- must be re-configured by using `absolute_mode_config()` or `relative_mode_config()`.
-
-Relative or Absolute mode
-*************************
-
-feed_enable
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.feed_enable
-
- This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`
- or :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` mode, otherwise if `data_mode` is set to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`, then this function will do nothing.
-
-hard_configured
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.hard_configured
-
- See note about product labeling in `Model Labeling Scheme `_. (read only)
-
- :Returns:
- `True` if a 470K ohm resistor is populated at the junction labeled "R4"
-
-relative_mode_config()
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.relative_mode_config
-
- (write only)
-
- This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`
- mode, otherwise if `data_mode` is set to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` or
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE`, then this function does nothing.
-
- :param bool rotate90: Specifies if the axis data is altered for 90 degree rotation before
- reporting it (essentially swaps the axis data). Default is `False`.
- :param bool taps: Specifies if all taps should be reported (`True`) or not
- (`False`). Default is `True`. This affects ``secondary_tap`` option as well.
- :param bool secondary_tap: Specifies if tapping in the top-left corner (depending on
- orientation) triggers the secondary button data. Defaults to `True`. This feature is
- always disabled if `hard_configured` is `True`.
- :param bool glide_extend: A patended feature that allows the user to glide their finger off
- the edge of the sensor and continue gesture with the touch event. Default is `True`.
- This feature is always disabled if `hard_configured` is `True`.
- :param bool intellimouse: Specifies if the data reported includes a byte about scroll data.
- Default is `False`. Because this flag is specific to scroll data, this feature is always
- disabled if `hard_configured` is `True`.
-
-absolute_mode_config()
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.absolute_mode_config
-
- (write only)
-
- This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE`
- mode, otherwise if `data_mode` is set to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` or
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`, then this function does nothing.
-
- :param int z_idle_count: Specifies the number of empty packets (x-axis, y-axis, and z-axis
- are ``0``) reported (every 10 milliseconds) when there is no touch detected. Defaults
- to 30. This number is clamped to range [0, 255].
- :param bool invert_x: Specifies if the x-axis data is to be inverted before reporting it.
- Default is `False`.
- :param bool invert_y: Specifies if the y-axis data is to be inverted before reporting it.
- Default is `False`.
-
-report()
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.report
-
- This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`
- or :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` mode, otherwise if `data_mode` is set to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`, then this function returns `None` and does nothing.
-
- :param bool only_new: This parameter can be used to ensure the data reported is only new
- data. Otherwise the data returned can be either old data or new data. If the ``dr_pin``
- parameter is specified upon instantiation, then the specified input pin is used to
- detect if the data is new. Otherwise the SW_DR flag in the STATUS register is used to
- detirmine if the data is new.
-
- :Returns: `None` if the ``only_new`` parameter is set `True` and there is no new data to
- report. Otherwise, a `list` or `bytearray` of parameters that describe the (touch or
- button) event. The structure is as follows:
-
- .. list-table::
- :header-rows: 1
- :widths: 1, 5, 5
-
- * - Index
- - Relative (Mouse) mode
-
- as a `bytearray`
- - Absolute Mode
-
- as a `list`
- * - 0
- - Button Data [1]_
-
- one unsigned byte
- - Button Data [1]_
-
- one unsigned byte
- * - 1
- - change in x-axis [2]_
-
- -128 |LessEq| X |LessEq| 127
- - x-axis Position
-
- 0 |LessEq| X |LessEq| 2047
- * - 2
- - change in y-axis [2]_
-
- -128 |LessEq| Y |LessEq| 127
- - y-axis Position
-
- 0 |LessEq| Y |LessEq| 1535
- * - 3
- - change in scroll wheel
-
- -128 |LessEq| SCROLL |LessEq| 127 [3]_
- - z-axis Magnitude
-
- .. [1] The returned button data is a byte in which each bit represents a button.
- The bit to button order is as follows:
-
- 0. [LSB] Button 1 (thought of as Left button in Relative/Mouse mode). If ``taps``
- parameter is passed as `True` when calling `relative_mode_config()`, a single
- tap will be reflected here.
- 1. Button 2 (thought of as Right button in Relative/Mouse mode). If ``taps`` and
- ``secondary_tap`` parameters are passed as `True` when calling `relative_mode_config()`,
- a single tap in the perspective top-left-most corner will be reflected here (secondary
- taps are constantly disabled if `hard_configured` returns `True`). Note that the
- top-left-most corner can be perspectively moved if ``rotate90`` parameter is passed as
- `True` when calling `relative_mode_config()`.
- 2. Button 3 (thought of as Middle or scroll wheel button in Relative/Mouse mode)
- .. [2] The axis data reported in Relative/Mouse mode is in two's
- comliment form. Use Python's :py:func:`struct.unpack()` to convert the
- data into integer form (see `Simple Test example `_
- for how to use this function).
-
- The axis data reported in Absolute mode is always positive as the
- xy-plane's origin is located to the top-left, unless ``invert_x`` or ``invert_y``
- parameters to `absolute_mode_config()` are manipulated to change the perspective
- location of the origin.
- .. [3] In Relative/Mouse mode the scroll wheel data is only reported if the
- ``intellimouse`` parameter is passed as `True` to `relative_mode_config()`.
- Otherwise this is an empty byte as the
- returned `bytearray` follows the buffer structure of a mouse HID report (see
- `USB Mouse example `_).
- .. |LessEq| unicode:: U+2264
-
-clear_flags()
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.clear_flags
-
-allow_sleep
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.allow_sleep
-
- Set this attribute to `True` if you want the Pinnacle ASIC to enter sleep (low power)
- mode after about 5 seconds of inactivity (does not apply to AnyMeas mode). While the touch
- controller is in sleep mode, if a touch event or button press is detected, the Pinnacle
- ASIC will take about 300 milliseconds to wake up (does not include handling the touch event
- or button press data).
-
-shutdown
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.shutdown
-
- `True` means powered down (AKA standby mode), and `False` means not powered down
- (Active, Idle, or Sleep mode).
-
- .. note:: The ASIC will take about 300 milliseconds to complete the transition
- from powered down mode to active mode. No touch events or button presses will be
- monitored while powered down.
-
-sample_rate
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.sample_rate
-
- Valid values are ``100``, ``80``, ``60``, ``40``, ``20``, ``10``. Any other input values
- automatically set the sample rate to 100 sps (samples per second). Optionally, ``200`` and
- ``300`` sps can be specified, but using these values automatically disables palm (referred
- to as "NERD" in the specification sheet) and noise compensations. These higher values are
- meant for using a stylus with a 2mm diameter tip, while the values less than 200 are meant
- for a finger or stylus with a 5.25mm diameter tip.
-
- This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`
- or :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` mode, otherwise if `data_mode` is set to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`, then this function will do nothing.
-
-detect_finger_stylus()
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.detect_finger_stylus
-
- :param bool enable_finger: `True` enables the Pinnacle ASIC's measurements to
- detect if the touch event was caused by a finger or 5.25mm stylus. `False` disables
- this feature. Default is `True`.
- :param bool enable_stylus: `True` enables the Pinnacle ASIC's measurements to
- detect if the touch event was caused by a 2mm stylus. `False` disables this
- feature. Default is `True`.
- :param int sample_rate: See the `sample_rate` attribute as this parameter manipulates that
- attribute.
-
- .. tip:: Consider adjusting the ADC matrix's gain to enhance performance/results using
- `set_adc_gain()`
-
-calibrate()
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.calibrate
-
- This function only applies to :attr:`~circuitpython_cirque_pinnacle.glidepoint.RELATIVE`
- or :attr:`~circuitpython_cirque_pinnacle.glidepoint.ABSOLUTE` mode, otherwise if `data_mode` is set to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`, then this function will do nothing.
-
- :param bool run: If `True`, this function forces a calibration of the sensor. If `False`,
- this function just writes the following parameters to the Pinnacle ASIC's "CalConfig1"
- register. This parameter is required while the rest are optional keyword parameters.
- :param bool tap: Enable dynamic tap compensation? Default is `True`.
- :param bool track_error: Enable dynamic track error compensation? Default is `True`.
- :param bool nerd: Enable dynamic NERD compensation? Default is `True`. This parameter has
- something to do with palm detection/compensation.
- :param bool background: Enable dynamic background compensation? Default is `True`.
-
- .. note:: According to the datasheet, calibration of the sensor takes about 100
- milliseconds. This function will block until calibration is complete (if ``run`` is
- `True`). It is recommended for typical applications to leave all optional parameters
- in their default states.
-
-calibration_matrix
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.calibration_matrix
-
- This matrix is not applicable in AnyMeas mode. Use this attribute to compare a prior
- compensation matrix with a new matrix that was either loaded manually by setting this
- attribute to a `list` of 46 signed 16-bit (short) integers or created internally by calling
- `calibrate()` with the ``run`` parameter as `True`.
-
- .. note:: A paraphrased note from Cirque's Application Note on Comparing compensation
- matrices:
-
- If any 16-bit values are above 20K (absolute), it generally indicates a problem with
- the sensor. If no values exceed 20K, proceed with the data comparison. Compare each
- 16-bit value in one matrix to the corresponding 16-bit value in the other matrix. If
- the difference between the two values is greater than 500 (absolute), it indicates a
- change in the environment. Either an object was on the sensor during calibration, or
- the surrounding conditions (temperature, humidity, or noise level) have changed. One
- strategy is to force another calibration and compare again, if the values continue to
- differ by 500, determine whether to use the new data or a previous set of stored data.
- Another strategy is to average any two values that differ by more than 500 and write
- this new matrix, with the average values, back into Pinnacle ASIC.
-
-set_adc_gain()
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.set_adc_gain
-
- (does not apply to AnyMeas mode). (write-only)
-
- :param int sensitivity: This int specifies how sensitive the ADC (Analog to Digital
- Converter) component is. ``0`` means most sensitive, and ``3`` means least sensitive.
- A value outside this range will raise a `ValueError` exception.
-
- .. tip:: The official example code from Cirque for a curved overlay uses a value of ``1``.
-
-tune_edge_sensitivity()
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.tune_edge_sensitivity
-
- This function was ported from Cirque's example code and doesn't seem to have corresponding
- documentation. I'm having trouble finding a memory map of the Pinnacle ASIC as this
- function directly alters values in the Pinnacle ASIC's memory. USE AT YOUR OWN RISK!
-
-AnyMeas mode
-*************
-
-anymeas_mode_config()
-^^^^^^^^^^^^^^^^^^^^^^^
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.anymeas_mode_config
-
- Be sure to set the `data_mode` attribute to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` before calling this function
- otherwise it will do nothing.
-
- :param int gain: Sets the sensitivity of the ADC matrix. Valid values are the constants
- defined in `AnyMeas mode Gain`_. Defaults to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.GAIN_200`.
- :param int frequency: Sets the frequency of measurements made by the ADC matrix. Valid
- values are the constants defined in
- `AnyMeas mode Frequencies`_.
- Defaults :attr:`~circuitpython_cirque_pinnacle.glidepoint.FREQ_0`.
- :param int sample_length: Sets the maximum bit length of the measurements made by the ADC
- matrix. Valid values are ``128``, ``256``, or ``512``. Defaults to ``512``.
- :param int mux_ctrl: The Pinnacle ASIC can employ different bipolar junctions
- and/or reference capacitors. Valid values are the constants defined in
- `AnyMeas mode Muxing`_. Additional combination of
- these constants is also allowed. Defaults to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.MUX_PNP`.
- :param int apperture_width: Sets the window of time (in nanoseconds) to allow for the ADC
- to take a measurement. Valid values are multiples of 125 in range [``250``, ``1875``].
- Erroneous values are clamped/truncated to this range.
-
- .. note:: The ``apperture_width`` parameter has a inverse relationship/affect on the
- ``frequency`` parameter. The approximated frequencies described in this
- documentation are based on an aperture width of 500 nanoseconds, and they will
- shrink as the apperture width grows or grow as the aperture width shrinks.
-
- :param int ctrl_pwr_cnt: Configure the Pinnacle to perform a number of measurements for
- each call to `measure_adc()`. Defaults to 1. Constants defined in
- `AnyMeas mode Control`_ can be used to specify if is sleep
- is allowed (:attr:`~circuitpython_cirque_pinnacle.glidepoint.CRTL_PWR_IDLE` -- this
- is not default) or if repetive measurements is allowed (
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.CRTL_REPEAT`) if number of
- measurements is more than 1.
-
- .. warning:: There is no bounds checking on the number of measurements specified
- here. Specifying more than 63 will trigger sleep mode after performing
- measuements.
-
- .. tip:: Be aware that allowing the Pinnacle to enter sleep mode after taking
- measurements will slow consecutive calls to `measure_adc()` as the Pinnacle
- requires about 300 milliseconds to wake up.
-
-measure_adc()
-^^^^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.measure_adc
-
- Internally this function calls `start_measure_adc()` and `get_measure_adc()` in sequence.
- Be sure to set the `data_mode` attribute to
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS` before calling this function
- otherwise it will do nothing.
-
- :parameters:
- Each of the parameters are a 4-byte integer (see format table below) in which each bit
- corresponds to a capacitance sensing eletrode in the sensor's matrix (12 electrodes for
- Y-axis, 16 electrodes for X-axis). They are used to compensate for varying capacitances in
- the electrodes during measurements. **It is highly recommended that the trackpad be
- installed in a finished/prototyped housing when determining what electrodes to
- manipulate.** See `AnyMeas mode example `_ to
- understand how to use these 4-byte integers.
-
- * bits_to_toggle (`int `_) - A bit
- of ``1`` flags that electrode's ouput for toggling, and a bit of ``0`` signifies that
- the electrode's output should remain unaffected.
- * toggle_polarity (`int `_) - This
- specifies which polarity the output of the electrode(s) (specified with corresponding
- bits in ``bits_to_toggle`` parameter) should be toggled (forced). A bit of ``1`` toggles
- that bit positve, and a bit of ``0`` toggles that bit negative.
-
- :Returns:
- A 2-byte `bytearray` that represents a signed short integer. If `data_mode` is not set
- to :attr:`~circuitpython_cirque_pinnacle.glidepoint.ANYMEAS`, then this function returns
- `None` and does nothing.
-
- :4-byte Integer Format:
- Bits 31 & 30 are not used and should remain ``0``. Bits 29 and 28 represent the optional
- implementation of reference capacitors built into the Pinnacle ASIC. To use these
- capacitors, the corresponding constants
- (:attr:`~circuitpython_cirque_pinnacle.glidepoint.AnyMeasMux.MUX_REF0` and/or
- :attr:`~circuitpython_cirque_pinnacle.glidepoint.AnyMeasMux.MUX_REF1`) must be passed to
- `anymeas_mode_config()` in the ``mux_ctrl`` parameter, and their representative
- bits must be flagged in both ``bits_to_toggle`` & ``toggle_polarity`` parameters.
-
- .. csv-table:: byte 3 (MSByte)
- :stub-columns: 1
- :widths: 10, 5, 5, 5, 5, 5, 5, 5, 5
-
- "bit position",31,30,29,28,27,26,25,24
- "representation",N/A,N/A,Ref1,Ref0,Y11,Y10,Y9,Y8
- .. csv-table:: byte 2
- :stub-columns: 1
- :widths: 10, 5, 5, 5, 5, 5, 5, 5, 5
-
- "bit position",23,22,21,20,19,18,17,16
- "representation",Y7,Y6,Y5,Y4,Y3,Y2,Y1,Y0
- .. csv-table:: byte 1
- :stub-columns: 1
- :widths: 10, 5, 5, 5, 5, 5, 5, 5, 5
-
- "bit position",15,14,13,12,11,10,9,8
- "representation",X15,X14,X13,X12,X11,X10,X9,X8
- .. csv-table:: byte 0 (LSByte)
- :stub-columns: 1
- :widths: 10, 5, 5, 5, 5, 5, 5, 5, 5
-
- "bit position",7,6,5,4,3,2,1,0
- "representation",X7,X6,X5,X4,X3,X2,X1,X0
-
-start_measure_adc()
-^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.start_measure_adc
-
- See the parameters and table in `measure_adc()` as this is its helper function, and all
- parameters there are used the same way here.
-
-get_measure_adc()
-^^^^^^^^^^^^^^^^^^^^
-
- .. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.get_measure_adc
-
- This function is only meant ot be used in conjunction with `start_measure_adc()` for
- non-blocking application.
-
- :returns:
- * `None` if `data_mode` is not set to `ANYMEAS` or if the "data ready" pin's signal is not
- active (while `data_mode` is set to `ANYMEAS`) meaing the Pinnacle ASIC is still computing
- the ADC measurements based on the 4-byte polynomials passed to `start_measure_adc()`.
- * a `bytearray` that represents a signed 16-bit integer upon completed ADC measurements based
- on the 4-byte polynomials passed to `start_measure_adc()`.
-
-
SPI & I2C Interfaces
-********************
-
- .. autoclass:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouchSPI
- :members:
- :show-inheritance:
-
- :param ~busio.SPI spi: The object of the SPI bus to use. This object must be shared among
- other driver classes that use the same SPI bus (MOSI, MISO, & SCK pins).
- :param ~microcontroller.Pin ss_pin: The "slave select" pin output to the Pinnacle ASIC.
- :param int spi_frequency: The SPI bus speed in Hz. Default is 12 MHz.
- :param ~microcontroller.Pin dr_pin: |dr_pin_parameter|
-
- .. important:: |dr_pin_note|
-
- .. autoclass:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouchI2C
- :members:
- :show-inheritance:
-
+--------------------
- :param ~busio.I2C i2c: The object of the I2C bus to use. This object must be shared among
- other driver classes that use the same I2C bus (SDA & SCL pins).
- :param int address: The slave I2C address of the Pinnacle ASIC. Defaults to ``0x2A``.
- :param ~microcontroller.Pin dr_pin: |dr_pin_parameter|
+.. autoclass:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouchSPI
+ :members:
+ :show-inheritance:
- .. important:: |dr_pin_note|
+.. autoclass:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouchI2C
+ :members:
+ :show-inheritance:
diff --git a/docs/conf.py b/docs/conf.py
index db5d9d6..82f4daa 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,171 +1,298 @@
-# -*- coding: utf-8 -*-
-
-import os
-import sys
-sys.path.insert(0, os.path.abspath('..'))
-
-# -- General configuration ------------------------------------------------
-
-# 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.intersphinx',
- 'sphinx.ext.napoleon',
- 'sphinx.ext.todo',
- 'sphinx.ext.viewcode',
-]
-
-# TODO: Please Read!
-# Uncomment the below if you use native CircuitPython modules such as
-# digitalio, micropython and busio. List the modules you use. Without it, the
-# autodoc module docs will fail to generate with a warning.
-autodoc_mock_imports = ["digitalio", "busio"]
-autodoc_member_order = 'bysource'
-
-intersphinx_mapping = {
- 'python': ('https://docs.python.org/3.7', 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']
-
-source_suffix = '.rst'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'Circuitpython Cirque Pinnacle Library'
-copyright = u'2020 Brendan Doherty'
-author = u'Brendan Doherty'
-
-# 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 = u'1.0'
-# The full version, including alpha/beta/rc tags.
-release = u'1.0'
-
-# 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 patterns also effect to html_static_path and html_extra_path
-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.
-#
-default_role = "any"
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#
-add_function_parentheses = True
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# If true, `todo` and `todoList` produce output, else they produce nothing.
-todo_include_todos = False
-
-# If this is True, todo emits a warning for each TODO entries. The default is False.
-todo_emit_warnings = False
-
-napoleon_numpy_docstring = False
-
-# -- Options for HTML output ----------------------------------------------
-
-# 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'
-
-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(), '.']
- except:
- html_theme = 'default'
- html_theme_path = ['.']
-else:
- 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']
-
-
-# These paths are either relative to html_static_path
-# or fully qualified paths (eg. https://...)
-html_css_files = [
- 'darkness.css',
-]
-
-# 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'
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'CircuitpythonCirquePinnacleLibrarydoc'
-
-# -- 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, 'CircuitPythonCirquePinnacleLibrary.tex', u'CircuitPython Cirque Pinnacle Library Documentation',
- author, '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, 'CircuitPythonCirquePinnacleLibrary', u'CircuitPython Cirque Pinnacle Library 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, 'CircuitpythonCirquePinnacleLibrary', u'Circuitpython Cirque Pinnacle Library Documentation',
- author, 'CircuitpythonCirquePinnacleLibrary', 'CircuitPython Library for Cirque Pinnacle touch Controller.',
- 'Miscellaneous'),
-]
+# pylint: disable=invalid-name,too-few-public-methods
+"""This file is for `sphinx-build` configuration"""
+import os
+import sys
+
+
+sys.path.insert(0, os.path.abspath(".."))
+
+# -- General configuration
+# ------------------------------------------------
+
+# 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.intersphinx",
+ "sphinx.ext.napoleon",
+ "sphinx.ext.todo",
+ "sphinx.ext.viewcode",
+ "sphinx_immaterial",
+ # "rst2pdf.pdfbuilder", # for local pdf builder support
+]
+
+# Uncomment the below if you use native CircuitPython modules such as
+# digitalio, micropython and busio. List the modules you use. Without it, the
+# autodoc module docs will fail to generate with a warning.
+# autodoc_mock_imports = ["digitalio", "busio", "usb_hid", "microcontroller"]
+autodoc_member_order = "bysource"
+
+intersphinx_mapping = {
+ "python": ("https://docs.python.org/3.7", None),
+ "CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None),
+}
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ["_templates"]
+
+source_suffix = ".rst"
+
+# The master toctree document.
+master_doc = "index"
+
+# General information about the project.
+project = "Circuitpython Cirque Pinnacle Library"
+copyright = "2020 Brendan Doherty" # pylint: disable=redefined-builtin
+author = "Brendan Doherty"
+
+# 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 = "dev"
+# The full version, including alpha/beta/rc tags.
+release = "1.0"
+
+html_baseurl = "https://circuitpython-cirque-pinnacle.readthedocs.io/"
+
+# 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 = "en"
+
+# 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",
+ "requirements.txt",
+]
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#
+default_role = "any"
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#
+add_function_parentheses = True
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+# If this is True, todo emits a warning for each TODO entries. The default is False.
+todo_emit_warnings = False
+
+napoleon_numpy_docstring = False
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = "sphinx_immaterial"
+
+html_theme_options = {
+ "features": [
+ "search.share",
+ ],
+ # Set the color and the accent color
+ "palette": [
+ {
+ "media": "(prefers-color-scheme: light)",
+ "scheme": "default",
+ "primary": "green",
+ "accent": "light-blue",
+ "toggle": {
+ "icon": "material/lightbulb-outline",
+ "name": "Switch to dark mode",
+ },
+ },
+ {
+ "media": "(prefers-color-scheme: dark)",
+ "scheme": "slate",
+ "primary": "green",
+ "accent": "light-blue",
+ "toggle": {
+ "icon": "material/lightbulb",
+ "name": "Switch to light mode",
+ },
+ },
+ ],
+ # Set the repo location to get a badge with stats
+ "repo_url": "https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle/",
+ "repo_name": "CircuitPython_Cirque_Pinnacle",
+ "social": [
+ {
+ "icon": "fontawesome/brands/github",
+ "link": "https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle",
+ },
+ {
+ "icon": "fontawesome/brands/python",
+ "link": "https://pypi.org/project/circuitpython-cirque-pinnacle/",
+ },
+ {
+ "icon": "fontawesome/brands/discord",
+ "link": "https://adafru.it/discord",
+ },
+ {
+ "icon": "simple/adafruit",
+ "link": "https://www.adafruit.com/",
+ },
+ {
+ "icon": "simple/sparkfun",
+ "link": "https://www.sparkfun.com/",
+ },
+ {
+ "name": "CircuitPython Downloads",
+ "icon": "octicons/download-24",
+ "link": "https://circuitpython.org",
+ },
+ ],
+}
+
+sphinx_immaterial_custom_admonitions = [
+ {
+ "name": "warning",
+ "color": (255, 66, 66),
+ "icon": "octicons/alert-24",
+ "override": True,
+ },
+ {
+ "name": "note",
+ "icon": "octicons/pencil-24",
+ "override": True,
+ },
+ {
+ "name": "seealso",
+ "color": (255, 66, 252),
+ "icon": "octicons/eye-24",
+ "title": "See Also",
+ "override": True,
+ },
+ {
+ "name": "hint",
+ "icon": "material/school",
+ "override": True,
+ },
+ {
+ "name": "tip",
+ "icon": "material/school",
+ "override": True,
+ },
+ {
+ "name": "important",
+ "icon": "material/school",
+ "override": True,
+ },
+]
+
+python_type_aliases = {
+ "DigitalInOut": "digitalio.DigitalInOut",
+}
+
+object_description_options = [
+ ("py:.*", dict(generate_synopses="first_sentence")),
+]
+
+# Set link name generated in the top bar.
+html_title = "CircuitPython Cirque Pinnacle"
+
+# 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"]
+
+# These paths are either relative to html_static_path
+# or fully qualified paths (eg. https://...)
+html_css_files = ["extra_css.css"]
+
+# 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_logo = "_static/Logo.png"
+# Output file base name for HTML help builder.
+htmlhelp_basename = "CircuitpythonCirquePinnacleLibrarydoc"
+
+# -- 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,
+ "CircuitPythonCirquePinnacleLibrary.tex",
+ "CircuitPython Cirque Pinnacle Library Documentation",
+ author,
+ "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,
+ "CircuitPythonCirquePinnacleLibrary",
+ "CircuitPython Cirque Pinnacle Library 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,
+ "CircuitpythonCirquePinnacleLibrary",
+ "Circuitpython Cirque Pinnacle Library Documentation",
+ author,
+ "CircuitpythonCirquePinnacleLibrary",
+ "CircuitPython Library for Cirque Pinnacle touch Controller.",
+ "Miscellaneous",
+ ),
+]
+
+# ---Options for PDF output
+# -----------------------------------------
+# requires `rst2pdf` module which is not builtin to Python 3.4 nor
+# readthedocs.org's docker)
+
+pdf_documents = [
+ (
+ "index",
+ "CircuitPython-Cirque-Pinnacle",
+ "CircuitPython-Cirque-Pinnacle library documentation",
+ "Brendan Doherty",
+ ),
+]
diff --git a/docs/contributing.rst b/docs/contributing.rst
new file mode 100644
index 0000000..e582053
--- /dev/null
+++ b/docs/contributing.rst
@@ -0,0 +1 @@
+.. include:: ../CONTRIBUTING.rst
diff --git a/docs/examples.rst b/docs/examples.rst
index e19a118..12c48a2 100644
--- a/docs/examples.rst
+++ b/docs/examples.rst
@@ -1,26 +1,30 @@
-Simple Test
------------
-
-Ensure your device works with this simple test.
-
-.. literalinclude:: ../examples/cirque_pinnacle_simpletest.py
- :caption: examples/cirque_pinnacle_simpletest.py
- :linenos:
-
-USB Mouse example
------------------
-
-This example uses CircuitPython's built-in `usb_hid` API to emulate a mouse with the Cirque circle trackpad.
-
-.. literalinclude:: ../examples/cirque_pinnacle_usb_mouse.py
- :caption: examples/cirque_pinnacle_usb_mouse.py
- :linenos:
-
-AnyMeas mode example
---------------------
-
-This example uses the Pinnacle touch controller's AnyMeas mode to fetch raw ADC values.
-
-.. literalinclude:: ../examples/cirque_pinnacle_anymeas_test.py
- :caption: examples/cirque_pinnacle_anymeas_test.py
- :linenos:
+
+Examples
+========
+
+Simple Test
+-----------
+
+Ensure your device works with this simple test.
+
+.. literalinclude:: ../examples/cirque_pinnacle_simpletest.py
+ :caption: examples/cirque_pinnacle_simpletest.py
+ :linenos:
+
+USB Mouse example
+-----------------
+
+This example uses CircuitPython's built-in `usb_hid` API to emulate a mouse with the Cirque circle trackpad.
+
+.. literalinclude:: ../examples/cirque_pinnacle_usb_mouse.py
+ :caption: examples/cirque_pinnacle_usb_mouse.py
+ :linenos:
+
+AnyMeas mode example
+--------------------
+
+This example uses the Pinnacle touch controller's AnyMeas mode to fetch raw ADC values.
+
+.. literalinclude:: ../examples/cirque_pinnacle_anymeas_test.py
+ :caption: examples/cirque_pinnacle_anymeas_test.py
+ :linenos:
diff --git a/docs/index.rst b/docs/index.rst
index 0a01633..8137dbc 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,25 +1,27 @@
-.. include:: ../README.rst
-
-Table of Contents
-=================
.. toctree::
- :maxdepth: 4
:hidden:
self
.. toctree::
- :caption: Examples
- :maxdepth: 3
+ :hidden:
examples
.. toctree::
:caption: API Reference
- :maxdepth: 4
+ :hidden:
+ about_lite
api
+ rel_abs
+ anymeas
+
+.. toctree::
+ :hidden:
+
+ contributing
.. toctree::
:caption: Related Products
@@ -27,19 +29,160 @@ Table of Contents
Cirque Glidepoint circle trackpads
12-pin FPC cable (0.5mm pitch)
-.. toctree::
- :caption: Other Links
+Introduction
+============
+
+A CircuitPython driver library that implements the Adafruit_BusDevice library
+for interfacing with the Cirque Pinnacle (1CA027) touch controller used in Cirque Circle Trackpads.
+
+Supported Features
+------------------
+
+* Use SPI or I2C bus protocols to interface with the Pinnacle touch controller ASIC (Application
+ Specific Integrated Circuit).
+* Relative mode data reporting (AKA Mouse mode) with optional tap detection.
+* Absolute mode data reporting (x, y, & z axis positions).
+* AnyMeas mode data reporting. This mode exposes the ADC (Analog to Digital Converter) values and is
+ not well documented in the numerous datasheets provided by the Cirque corporation about the
+ Pinnacle (1CA027), thus this is a rather experimental mode.
+* Hardware input buttons' states included in data reports. There are 3 button input lines on
+ the Cirque circle trackpads -- see `Pinout`_ section.
+* Configure measurements for finger or stylus (or automatically detirmine either) touch
+ events. The Cirque circle trackpads are natively capable of measuring only 1 touch
+ point per event.
+* Download/upload the underlying compensation matrix for ADC measurements.
+* Adjust the ADC matrix gain (sensitivity).
+
+.. tip::
+ The SPI protocol is the preferred method for interfacing with more than 1 Cirque circle
+ trackpad from the same MCU (microcontroller). The Cirque Pinnacle does not allow
+ changing the I2C slave device address (via software); this means only 1 Cirque circle trackpad
+ can be accessed over the I2C bus in the lifecycle of an application. That said, you could change
+ the I2C address from ``0x2A`` to ``0x2C`` by soldering a 470K ohm resistor at the junction
+ labeled "ADR" (see picture in `Pinout`_ section), although this is untested.
+
+Unsupported Features
+--------------------
+
+* The legacy PS\\2 interface is pretty limited and not accessible by some CircuitPython MCUs.
+ Therefore, it has been neglected in this library.
+* Cirque's circle trackpads ship with the newer non-AG (Advanced Gestures) variant of the
+ Pinnacle touch controller ASIC. Thus, this library focuses on the the non-AG variant's
+ functionality via testing, and it does not provide access to the older AG variant's features
+ (register addresses slightly differ which breaks compatibility).
+
+Pinout
+------
+
+.. image:: https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle/raw/master/docs/_static/Cirque_GlidePoint-Circle-Trackpad.png
+ :target: https://www.mouser.com/new/cirque/glidepoint-circle-trackpads/
+
+The above picture is an example of the Cirque GlidePoint circle trackpad. This picture
+is chosen as the test pads (larger copper circular pads) are clearly labeled. The test pads
+are extended to the `12-pin FFC/FPC cable `_ connector (the white block near the
+bottom). The following table shows how the pins are connected in the `examples `_ (tested on an `ItsyBitys M4 `_)
+
+.. csv-table:: pinout (ordered the same as the FFC/FPC cable connector)
+ :header: "cable pin number", Label, "MCU pin", Description
+ :widths: 4, 5, 5, 13
+
+ 1, SCK, SCK, "SPI clock line"
+ 2, SO, MISO, "Master Input Slave Output"
+ 3, SS, D7, "Slave Select (AKA Chip Select)"
+ 4, DR, D2, "Data Ready interrupt"
+ 5, SI, MOSI, "SPI Master Output Slave Input"
+ 6, B2, N/A, "Hardware input button #2"
+ 7, B3, N/A, "Hardware input button #3"
+ 8, B1, N/A, "Hardware input button #1"
+ 9, SCL, SCL, "I2C clock line"
+ 10, SDA, SDA, "I2C data line"
+ 11, GND, GND, Ground
+ 12, VDD, 3V, "3V power supply"
+
+.. tip:: Of course, you can capture button data manually (if your application utilizes more
+ than 3 buttons), but if you connect the pins B1, B2, B3 to momentary push buttons that
+ (when pressed) provide a path to ground, the Pinnacle touch controller will report all 3
+ buttons' states for each touch (or even button only) events.
+
+Model Labeling Scheme
+*********************
+
+TM\ ``yyyxxx``\ -202\ ``i``\ -\ ``cc``\ ``o``
+
+- ``yyyxxx`` stands for the respective vertical & horizontal width of the trackpad in millimeters.
+- ``i`` stands for the hardwired interface protocol (3 = I2C, 4 = SPI). Notice, if there is a
+ resistor populated at the R1 (470K ohm) junction (located just above the Pinnacle ASIC), it
+ is configured for SPI, otherwise it is configured for I2C.
+- ``cc`` stands for Custom Configuration which describes if a 470K ohm resistor is populated at
+ junction R4. "30" (resistor at R4 exists) means that the hardware is configured to disable
+ certain features despite what this library does. "00" (no resistor at R4) means that the
+ hardware is configured to allow certain features to be manipulated by this library. These
+ features include "secondary tap" (thought of as "right mouse button" in relative data mode),
+ Intellimouse scrolling (Microsoft patented scroll wheel behavior -- a throw back to when
+ scroll wheels were first introduced), and 180 degree orientation (your application can invert
+ the axis data anyway).
+- ``o`` stands for the overlay type (0 = none, 1 = adhesive, 2 = flat, 3 = curved)
+
+Getting Started
+---------------
+
+Dependencies
+************
+
+This driver depends on:
+
+* `Adafruit CircuitPython `_
+* `Bus Device `_
+
+Please ensure all dependencies are available on the CircuitPython filesystem.
+This is easily achieved by downloading `the Adafruit library and driver bundle
+`_.
+
+How to Install
+**************
+
+Using ``pip``
+~~~~~~~~~~~~~
+
+This library is deployed to pypi.org, so you can easily install this library
+using
+
+.. code-block:: shell
+
+ pip3 install circuitpython-cirque-pinnacle
+
+Using git source
+~~~~~~~~~~~~~~~~
+
+This library can also be installed from the git source repository.
+
+.. code-block:: shell
+
+ git clone https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle.git
+ cd CircuitPython_Cirque_Pinnacle
+ python3 -m pip install .
+
+Usage Example
+*************
+
+Ensure you've connected the TMyyyxxx correctly by running the `examples/` located in the `examples
+folder of this library `_.
+
+Contributing
+------------
+
+Contributions are welcome! Please read our `Code of Conduct
+`_
+before contributing to help this project stay welcoming.
+
+Please review our :doc:`contributing` for details on the development workflow and linting tools.
- Download
- CircuitPython Reference Documentation
- CircuitPython Support Forum
- Adafruit Learning System
- Adafruit Blog
- Adafruit Store
+To initiate a discussion of idea(s), you need only open an issue on the
+`source's git repository `_
+(it doesn't have to be a bug report).
-Indices and tables
-==================
+Sphinx documentation
+********************
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
+Please read our :doc:`contributing` for instructions on how to build the documentation.
diff --git a/docs/rel_abs.rst b/docs/rel_abs.rst
new file mode 100644
index 0000000..fc56eda
--- /dev/null
+++ b/docs/rel_abs.rst
@@ -0,0 +1,32 @@
+Relative or Absolute mode API
+=============================
+
+.. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.feed_enable
+
+.. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.hard_configured
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.relative_mode_config
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.absolute_mode_config
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.available
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.read
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.clear_status_flags
+
+.. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.allow_sleep
+
+.. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.shutdown
+
+.. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.sample_rate
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.detect_finger_stylus
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.calibrate
+
+.. autoattribute:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.calibration_matrix
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.set_adc_gain
+
+.. automethod:: circuitpython_cirque_pinnacle.glidepoint.PinnacleTouch.tune_edge_sensitivity
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..434057c
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1 @@
+sphinx-immaterial
diff --git a/examples/cirque_pinnacle_anymeas_test.py b/examples/cirque_pinnacle_anymeas_test.py
index 6508977..26d70e1 100644
--- a/examples/cirque_pinnacle_anymeas_test.py
+++ b/examples/cirque_pinnacle_anymeas_test.py
@@ -1,11 +1,19 @@
-""" a test example using SPI to read ADC measurements from the Pinnacle touch
-controller in "AnyMeas" mode. This example does NOT work with
-glidepoint_lite.py"""
+"""
+A test example using SPI to read ADC measurements from the Pinnacle touch
+controller in "AnyMeas" mode
+"""
import time
import struct
import board
from digitalio import DigitalInOut
-import circuitpython_cirque_pinnacle.glidepoint as Pinnacle
+
+# This example does NOT work with glidepoint_lite.py
+from circuitpython_cirque_pinnacle import glidepoint
+
+try:
+ from typing import List
+except ImportError:
+ pass
dr_pin = DigitalInOut(board.D2)
# NOTE The dr_pin is a required keyword argument to the
@@ -14,25 +22,25 @@
# if using a trackpad configured for SPI
spi = board.SPI()
ss_pin = DigitalInOut(board.D7)
-tpad = Pinnacle.PinnacleTouchSPI(spi, ss_pin, dr_pin=dr_pin)
+t_pad = glidepoint.PinnacleTouchSPI(spi, ss_pin, dr_pin=dr_pin)
# if using a trackpad configured for I2C
# i2c = board.I2C()
-# tpad = Pinnacle.PinnacleTouchI2C(i2c, dr_pin=dr_pin)
+# t_pad = glidepoint.PinnacleTouchI2C(i2c, dr_pin=dr_pin)
# if dr_pin was not specified upon instantiation.
# this command will raise an AttributeError exception
-tpad.data_mode = Pinnacle.ANYMEAS
+t_pad.data_mode = glidepoint.ANYMEAS
# setup toggle and polarity bits for measuring with PNP gate muxing
-class MeasVector:
+class MeasVector: # pylint: disable=too-few-public-methods
"""A blueprint matrix used to manipulate the measurements' vector"""
- def __init__(self, toggle, polarity):
+ def __init__(self, toggle: int, polarity: int):
self.toggle = toggle
self.polarity = polarity
-vectors = []
+vectors: List[MeasVector] = []
# This toggles Y0 only and toggles it positively
vectors.append(MeasVector(0x00010000, 0x00010000))
# This toggles Y0 only and toggles it negatively
@@ -48,13 +56,12 @@ def __init__(self, toggle, polarity):
def compensate(count=5):
- """take ``count`` measurements, then average them together """
+ """take ``count`` measurements, then average them together"""
for i, vector in enumerate(vectors):
idle_vectors[i] = 0
for _ in range(count):
result = struct.unpack(
- "h",
- tpad.measure_adc(vector.toggle, vector.polarity)
+ "h", t_pad.measure_adc(vector.toggle, vector.polarity)
)[0]
idle_vectors[i] += result
idle_vectors[i] /= count
@@ -68,8 +75,7 @@ def take_measurements(timeout=10):
while time.monotonic() - start < timeout:
for i, vector in enumerate(vectors):
result = struct.unpack(
- "h",
- tpad.measure_adc(vector.toggle, vector.polarity)
+ "h", t_pad.measure_adc(vector.toggle, vector.polarity)
)[0]
print("vector{}: {}".format(i, result - idle_vectors[i]), end="\t")
print()
diff --git a/examples/cirque_pinnacle_simpletest.py b/examples/cirque_pinnacle_simpletest.py
index 1acfe41..55de49c 100644
--- a/examples/cirque_pinnacle_simpletest.py
+++ b/examples/cirque_pinnacle_simpletest.py
@@ -1,9 +1,14 @@
-"""A simple test example. This example also works with glidepoint_lite.py"""
+"""
+A simple test example. This example also works with glidepoint_lite.py
+"""
import time
import struct
import board
from digitalio import DigitalInOut
-import circuitpython_cirque_pinnacle.glidepoint as Pinnacle
+
+# if running this on a ATSAMD21 M0 based board
+# from circuitpython_cirque_pinnacle import glidepoint_lite as glidepoint
+from circuitpython_cirque_pinnacle import glidepoint
dr_pin = DigitalInOut(board.D2)
# NOTE The dr_pin is an optional keyword argument to the
@@ -12,37 +17,35 @@
# if using a trackpad configured for SPI
spi = board.SPI()
ss_pin = DigitalInOut(board.D7)
-tpad = Pinnacle.PinnacleTouchSPI(spi, ss_pin)
+t_pad = glidepoint.PinnacleTouchSPI(spi, ss_pin)
# if using a trackpad configured for I2C
# i2c = board.I2C()
-# tpad = Pinnacle.PinnacleTouchI2C(i2c)
+# t_pad = glidepoint.PinnacleTouchI2C(i2c)
+
+t_pad.data_mode = glidepoint.ABSOLUTE # ensure Absolute mode is enabled
+t_pad.absolute_mode_config(z_idle_count=1) # limit idle packet count to 1
-tpad.data_mode = Pinnacle.ABSOLUTE # ensure Absolute mode is enabled
-tpad.absolute_mode_config(z_idle_count=1) # limit idle packet count to 1
def print_data(timeout=6):
"""Print available data reports from the Pinnacle touch controller
until there's no input for a period of ``timeout`` seconds."""
- if tpad.data_mode == Pinnacle.RELATIVE:
+ if t_pad.data_mode == glidepoint.RELATIVE:
print("using Relative mode")
- elif tpad.data_mode == Pinnacle.ABSOLUTE:
+ elif t_pad.data_mode == glidepoint.ABSOLUTE:
print("using Absolute mode")
start = time.monotonic()
while time.monotonic() - start < timeout:
- if dr_pin.value: # is there new data?
- data = tpad.report(only_new=False)
- # Because we did not specify the dr_pin when instantiating the tpad variable,
- # only_new=False skips the extra SPI or I2C transaction to check the
- # SW_DR flag in the STATUS register which is reflected on the dr_pin
+ if dr_pin.value: # is there new data?
+ data = t_pad.read()
- if tpad.data_mode == Pinnacle.ABSOLUTE and data[3]:
+ if t_pad.data_mode == glidepoint.ABSOLUTE and data[3]:
# NOTE ``and data[3]`` means only when Z-axis is > 0
# specification sheet recommends clamping absolute position data of
# X & Y axis for reliability
data[1] = max(128, min(1920, data[1])) # X-axis
data[2] = max(64, min(1472, data[2])) # Y-axis
- elif tpad.data_mode == Pinnacle.RELATIVE:
+ elif t_pad.data_mode == glidepoint.RELATIVE:
# convert 2's compliment form into natural numbers
- data = struct.unpack('Bbbb', data)
+ data = struct.unpack("Bbbb", data)
print(data)
start = time.monotonic()
diff --git a/examples/cirque_pinnacle_usb_mouse.py b/examples/cirque_pinnacle_usb_mouse.py
index a5137da..3366639 100644
--- a/examples/cirque_pinnacle_usb_mouse.py
+++ b/examples/cirque_pinnacle_usb_mouse.py
@@ -1,25 +1,29 @@
-""" This example uses CircuitPython's built-in `usb_hid` API
-to emulate a mouse with the Cirque circle trackpad. This example
-also works with glidepoint_lite.py"""
+"""
+This example uses CircuitPython's built-in `usb_hid` API
+to emulate a mouse with the Cirque circle trackpad
+"""
import time
import board
from digitalio import DigitalInOut
import usb_hid
-import circuitpython_cirque_pinnacle.glidepoint as Pinnacle
+
+# if running this on a ATSAMD21 M0 based board
+# from circuitpython_cirque_pinnacle import glidepoint_lite as glidepoint
+from circuitpython_cirque_pinnacle import glidepoint
dr_pin = DigitalInOut(board.D2)
# NOTE Specifying the optional keyword argument ``dr_pin`` to the
-# constructor expedites ``report()`` when using Absolute or Relative modes
+# constructor expedites ``read()`` when using Absolute or Relative modes
# if using a trackpad configured for SPI
spi = board.SPI()
ss_pin = DigitalInOut(board.D7)
-tpad = Pinnacle.PinnacleTouchSPI(spi, ss_pin, dr_pin=dr_pin)
+t_pad = glidepoint.PinnacleTouchSPI(spi, ss_pin, dr_pin=dr_pin)
# if using a trackpad configured for I2C
# i2c = board.I2C()
-# tpad = Pinnacle.PinnacleTouchI2C(i2c, dr_pin=dr_pin)
+# t_pad = glidepoint.PinnacleTouchI2C(i2c, dr_pin=dr_pin)
-tpad.data_mode = Pinnacle.RELATIVE # ensure mouse mode is enabled
+t_pad.data_mode = glidepoint.RELATIVE # ensure mouse mode is enabled
mouse = None
for dev in usb_hid.devices:
@@ -32,16 +36,17 @@
# byte1 = delta x-axis
# byte2 = delta y-axis
# byte3 = delta scroll wheel
+if mouse is None:
+ raise OSError("mouse HID device not available.")
+
def move(timeout=10):
"""Send mouse X & Y reported data from the Pinnacle touch controller
until there's no input for a period of ``timeout`` seconds."""
- if mouse is None:
- raise OSError("mouse HID device not available.")
start = time.monotonic()
while time.monotonic() - start < timeout:
- data = tpad.report() # only returns fresh data (if any)
+ data = t_pad.read() # only returns fresh data (if any)
if data: # is there fresh data?
mouse.send_report(data) # no scrolling or backward/forward
start = time.monotonic()
- mouse.send_report(b'\x00' * 4) # release buttons (just in case)
+ mouse.send_report(b"\x00" * 4) # release buttons (just in case)
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..3a05b4a
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,616 @@
+
+[build-system]
+requires = [
+ "setuptools>=61",
+ "wheel",
+ "setuptools-scm",
+]
+
+[project]
+name = "circuitpython-cirque-pinnacle"
+requires-python = ">=3.7"
+description = "A CircuitPython driver for Cirque Pinnacle (1CA027) touch controller used in Cirque Trackpads"
+readme = "README.rst"
+authors = [
+ {name = "Brendan Doherty", email = "2bndy5@gmail.com"}
+]
+keywords = [
+ "blinka",
+ "circuitpython",
+ "raspberrypi",
+ "driver",
+ "Cirque",
+ "Pinnacle",
+ "touch",
+ "sensor",
+ "trackpad",
+]
+license = {text = "MIT"}
+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.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+]
+dynamic = ["version", "dependencies"]
+
+[project.urls]
+Documentation = "https://circuitpython-cirque-pinnacle.readthedocs.io"
+Source = "https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle"
+Tracker = "https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle/issues"
+
+[tool.setuptools]
+packages = ["circuitpython_cirque_pinnacle"]
+
+[tool.setuptools.dynamic]
+dependencies = {file = ["requirements.txt"]}
+
+[tool.setuptools_scm]
+# It would be nice to include the commit hash in the version, but that
+# can't be done in a PEP 440-compatible way.
+version_scheme= "no-guess-dev"
+# Test PyPI does not support local versions.
+local_scheme = "no-local-version"
+fallback_version = "0.0.0"
+
+[tool.pytest.ini_options]
+minversion = "6.0"
+addopts = "-vv"
+testpaths = ["tests"]
+log_level = "DEBUG"
+log_format = "%(levelname)s\t%(name)s: %(message)s"
+
+[tool.mypy]
+show_error_codes = true
+show_column_numbers = true
+
+[tool.coverage]
+[tool.coverage.run]
+dynamic_context = "test_function"
+
+[tool.coverage.json]
+pretty_print = true
+
+[tool.coverage.html]
+show_contexts = true
+
+[tool.coverage.report]
+# Regexes for lines to exclude from consideration
+exclude_lines = [
+ # Have to re-enable the standard pragma
+ "pragma: no cover",
+ "except ImportError",
+]
+
+[tool.pylint.main]
+# Analyse import fallback blocks. This can be used to support both Python 2 and 3
+# compatible code, which means that the block might have code that exists only in
+# one or another interpreter, leading to false positives when analysed.
+# analyse-fallback-blocks =
+
+# Clear in-memory caches upon conclusion of linting. Useful if running pylint in
+# a server-like mode.
+# clear-cache-post-run =
+
+# Always return a 0 (non-error) status code, even if lint errors are found. This
+# is primarily useful in continuous integration scripts.
+# exit-zero =
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code.
+# extension-pkg-allow-list =
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
+# for backward compatibility.)
+# extension-pkg-whitelist =
+
+# Return non-zero exit code if any of these messages/categories are detected,
+# even if score is above --fail-under value. Syntax same as enable. Messages
+# specified are enabled, while categories only check already-enabled messages.
+# fail-on =
+
+# Specify a score threshold under which the program will exit with error.
+fail-under = 10
+
+# Interpret the stdin as a python script, whose filename needs to be passed as
+# the module_or_package argument.
+# from-stdin =
+
+# Files or directories to be skipped. They should be base names, not paths.
+ignore = ["CVS"]
+
+# Add files or directories matching the regular expressions patterns to the
+# ignore-list. The regex matches against paths and can be in Posix or Windows
+# format. Because '\\' represents the directory delimiter on Windows systems, it
+# can't be used as an escape character.
+# ignore-paths =
+
+# Files or directories matching the regular expression patterns are skipped. The
+# regex matches against base names, not paths. The default value ignores Emacs
+# file locks
+# ignore-patterns =
+
+# List of module names for which member attributes should not be checked (useful
+# for modules/projects where namespaces are manipulated during runtime and thus
+# existing member attributes cannot be deduced by static analysis). It supports
+# qualified module names, as well as Unix pattern matching.
+ignored-modules = ["board"]
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+# init-hook =
+
+# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
+# number of processors available to use, and will cap the count on Windows to
+# avoid hangs.
+jobs = 2
+
+# Control the amount of potential inferred values when inferring a single object.
+# This can help the performance when dealing with large functions or complex,
+# nested conditions.
+limit-inference-results = 100
+
+# List of plugins (as comma separated values of python module names) to load,
+# usually to register additional checkers.
+# load-plugins =
+
+# Pickle collected data for later comparisons.
+persistent = true
+
+# Minimum Python version to use for version dependent checks. Will default to the
+# version used to run pylint.
+py-version = "3.11"
+
+# Discover python modules and packages in the file system subtree.
+# recursive =
+
+# When enabled, pylint would attempt to guess common misconfiguration and emit
+# user-friendly hints instead of false-positive error messages.
+suggestion-mode = true
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+# unsafe-load-any-extension =
+
+[tool.pylint.basic]
+# Naming style matching correct argument names.
+argument-naming-style = "snake_case"
+
+# Regular expression matching correct argument names. Overrides argument-naming-
+# style. If left empty, argument names will be checked with the set naming style.
+argument-rgx = "(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$"
+
+# Naming style matching correct attribute names.
+attr-naming-style = "snake_case"
+
+# Regular expression matching correct attribute names. Overrides attr-naming-
+# style. If left empty, attribute names will be checked with the set naming
+# style.
+attr-rgx = "(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$"
+
+# Bad variable names which should always be refused, separated by a comma.
+bad-names = ["foo", "bar", "baz", "toto", "tutu", "tata"]
+
+# Bad variable names regexes, separated by a comma. If names match any regex,
+# they will always be refused
+# bad-names-rgxs =
+
+# Naming style matching correct class attribute names.
+class-attribute-naming-style = "any"
+
+# Regular expression matching correct class attribute names. Overrides class-
+# attribute-naming-style. If left empty, class attribute names will be checked
+# with the set naming style.
+class-attribute-rgx = "([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$"
+
+# Naming style matching correct class constant names.
+class-const-naming-style = "UPPER_CASE"
+
+# Regular expression matching correct class constant names. Overrides class-
+# const-naming-style. If left empty, class constant names will be checked with
+# the set naming style.
+# class-const-rgx =
+
+# Naming style matching correct class names.
+class-naming-style = "PascalCase"
+
+# Regular expression matching correct class names. Overrides class-naming-style.
+# If left empty, class names will be checked with the set naming style.
+class-rgx = "[A-Z_][a-zA-Z0-9_]+$"
+
+# Naming style matching correct constant names.
+const-naming-style = "UPPER_CASE"
+
+# Regular expression matching correct constant names. Overrides const-naming-
+# style. If left empty, constant names will be checked with the set naming style.
+const-rgx = "(([A-Z_][A-Z0-9_]*)|(__.*__))$"
+
+# Minimum line length for functions/classes that require docstrings, shorter ones
+# are exempt.
+docstring-min-length = -1
+
+# Naming style matching correct function names.
+function-naming-style = "snake_case"
+
+# Regular expression matching correct function names. Overrides function-naming-
+# style. If left empty, function names will be checked with the set naming style.
+function-rgx = "(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$"
+
+# Good variable names which should always be accepted, separated by a comma.
+good-names = ["r", "g", "b", "w", "i", "j", "k", "n", "x", "y", "z", "ex", "ok", "Run", "_"]
+
+# Good variable names regexes, separated by a comma. If names match any regex,
+# they will always be accepted
+# good-names-rgxs =
+
+# Include a hint for the correct naming format with invalid-name.
+# include-naming-hint =
+
+# Naming style matching correct inline iteration names.
+inlinevar-naming-style = "any"
+
+# Regular expression matching correct inline iteration names. Overrides
+# inlinevar-naming-style. If left empty, inline iteration names will be checked
+# with the set naming style.
+inlinevar-rgx = "[A-Za-z_][A-Za-z0-9_]*$"
+
+# Naming style matching correct method names.
+method-naming-style = "snake_case"
+
+# Regular expression matching correct method names. Overrides method-naming-
+# style. If left empty, method names will be checked with the set naming style.
+method-rgx = "(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$"
+
+# Naming style matching correct module names.
+module-naming-style = "snake_case"
+
+# Regular expression matching correct module names. Overrides module-naming-
+# style. If left empty, module names will be checked with the set naming style.
+module-rgx = "(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$"
+
+# Colon-delimited sets of names that determine each other's naming style when the
+# name regexes allow several styles.
+# name-group =
+
+# Regular expression which should only match function or class names that do not
+# require a docstring.
+no-docstring-rgx = "^_"
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties. These
+# decorators are taken in consideration only for invalid-name.
+property-classes = ["abc.abstractproperty"]
+
+# Regular expression matching correct type variable names. If left empty, type
+# variable names will be checked with the set naming style.
+# typevar-rgx =
+
+# Naming style matching correct variable names.
+variable-naming-style = "snake_case"
+
+# Regular expression matching correct variable names. Overrides variable-naming-
+# style. If left empty, variable names will be checked with the set naming style.
+variable-rgx = "(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$"
+
+[tool.pylint.classes]
+# Warn about protected attribute access inside special methods
+# check-protected-access-in-special-methods =
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods = ["__init__", "__new__", "setUp"]
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected = ["_asdict", "_fields", "_replace", "_source", "_make"]
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg = ["cls"]
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg = ["mcs"]
+
+[tool.pylint.design]
+# List of regular expressions of class ancestor names to ignore when counting
+# public methods (see R0903)
+# exclude-too-few-public-methods =
+
+# List of qualified class names to ignore when counting class parents (see R0901)
+# ignored-parents =
+
+# Maximum number of arguments for function / method.
+max-args = 5
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes = 11
+
+# Maximum number of boolean expressions in an if statement (see R0916).
+max-bool-expr = 5
+
+# Maximum number of branch for function / method body.
+max-branches = 12
+
+# Maximum number of locals for function / method body.
+max-locals = 15
+
+# Maximum number of parents for a class (see R0901).
+max-parents = 7
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods = 20
+
+# Maximum number of return / yield for function / method body.
+max-returns = 6
+
+# Maximum number of statements in function / method body.
+max-statements = 50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods = 1
+
+[tool.pylint.exceptions]
+# Exceptions that will emit a warning when caught.
+overgeneral-exceptions = ["Exception"]
+
+[tool.pylint.format]
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format = "LF"
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines = "^\\s*(# )??$"
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren = 4
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string = " "
+
+# Maximum number of characters on a single line.
+max-line-length = 100
+
+# Maximum number of lines in a module.
+max-module-lines = 1000
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+# single-line-class-stmt =
+
+# Allow the body of an if to be on the same line as the test if there is no else.
+# single-line-if-stmt =
+
+[tool.pylint.imports]
+# List of modules that can be imported at any level, not just the top level one.
+# allow-any-import-level =
+
+# Allow explicit reexports by alias from a package __init__.
+# allow-reexport-from-package =
+
+# Allow wildcard imports from modules that define __all__.
+# allow-wildcard-with-all =
+
+# Deprecated modules which should not be used, separated by a comma.
+deprecated-modules = ["optparse", "tkinter.tix"]
+
+# Output a graph (.gv or any supported image format) of external dependencies to
+# the given file (report RP0402 must not be disabled).
+# ext-import-graph =
+
+# Output a graph (.gv or any supported image format) of all (i.e. internal and
+# external) dependencies to the given file (report RP0402 must not be disabled).
+# import-graph =
+
+# Output a graph (.gv or any supported image format) of internal dependencies to
+# the given file (report RP0402 must not be disabled).
+# int-import-graph =
+
+# Force import order to recognize a module as part of the standard compatibility
+# libraries.
+# known-standard-library =
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party = ["enchant"]
+
+# Couples of modules and preferred modules, separated by a comma.
+# preferred-modules =
+
+[tool.pylint.logging]
+# The type of string formatting that logging methods do. `old` means using %
+# formatting, `new` is for `{}` formatting.
+logging-format-style = "old"
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format.
+logging-modules = ["logging"]
+
+[tool.pylint."messages control"]
+# Only show warnings with the listed confidence levels. Leave empty to show all.
+# Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
+confidence = ["HIGH", "CONTROL_FLOW", "INFERENCE", "INFERENCE_FAILURE", "UNDEFINED"]
+
+# Disable the message, report, category or checker with the given id(s). You can
+# either give multiple identifiers separated by comma (,) or put this option
+# multiple times (only on the command line, not in the configuration file where
+# it should appear only once). You can also use "--disable=all" to disable
+# everything first and then re-enable specific checks. For example, if you want
+# to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use "--disable=all --enable=classes
+# --disable=W".
+disable = ["raw-checker-failed", "bad-inline-option", "locally-disabled", "file-ignored", "suppressed-message", "useless-suppression", "deprecated-pragma", "use-symbolic-message-instead", "import-error", "duplicate-code", "consider-using-f-string", "too-many-arguments"]
+
+# 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
+# multiple time (only on the command line, not in the configuration file where it
+# should appear only once). See also the "--disable" option for examples.
+enable = ["c-extension-no-member"]
+
+[tool.pylint.method_args]
+# List of qualified names (i.e., library.method) which require a timeout
+# parameter e.g. 'requests.api.get,requests.api.post'
+timeout-methods = ["requests.api.delete", "requests.api.get", "requests.api.head", "requests.api.options", "requests.api.patch", "requests.api.post", "requests.api.put", "requests.api.request"]
+
+[tool.pylint.miscellaneous]
+# List of note tags to take in consideration, separated by a comma.
+notes = ["FIXME", "XXX"]
+
+# Regular expression of note tags to take in consideration.
+# notes-rgx =
+
+[tool.pylint.refactoring]
+# Maximum number of nested blocks for function / method body
+max-nested-blocks = 5
+
+# Complete name of functions that never returns. When checking for inconsistent-
+# return-statements if a never returning function is called then it will be
+# considered as an explicit return statement and no message will be printed.
+never-returning-functions = ["sys.exit", "argparse.parse_error"]
+
+[tool.pylint.reports]
+# Python expression which should return a score less than or equal to 10. You
+# have access to the variables 'fatal', 'error', 'warning', 'refactor',
+# 'convention', and 'info' which contain the number of messages in each category,
+# as well as 'statement' which is the total number of statements analyzed. This
+# score is used by the global evaluation report (RP0004).
+evaluation = "10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)"
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details.
+# msg-template =
+
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio). You can also give a reporter class, e.g.
+# mypackage.mymodule.MyReporterClass.
+# output-format =
+
+# Tells whether to display a full report or only the messages.
+# reports =
+
+# Activate the evaluation score.
+score = true
+
+[tool.pylint.similarities]
+# Comments are removed from the similarity computation
+ignore-comments = true
+
+# Docstrings are removed from the similarity computation
+ignore-docstrings = true
+
+# Imports are removed from the similarity computation
+# ignore-imports =
+
+# Signatures are removed from the similarity computation
+ignore-signatures = true
+
+# Minimum lines number of a similarity.
+min-similarity-lines = 4
+
+[tool.pylint.spelling]
+# Limits count of emitted suggestions for spelling mistakes.
+max-spelling-suggestions = 4
+
+# Spelling dictionary name. Available dictionaries: none. To make it work,
+# install the 'python-enchant' package.
+# spelling-dict =
+
+# List of comma separated words that should be considered directives if they
+# appear at the beginning of a comment and should not be checked.
+spelling-ignore-comment-directives = "fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:"
+
+# List of comma separated words that should not be checked.
+# spelling-ignore-words =
+
+# A path to a file that contains the private dictionary; one word per line.
+# spelling-private-dict-file =
+
+# Tells whether to store unknown words to the private dictionary (see the
+# --spelling-private-dict-file option) instead of raising a message.
+# spelling-store-unknown-words =
+
+[tool.pylint.typecheck]
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators = ["contextlib.contextmanager"]
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+# generated-members =
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# class is considered mixin if its name matches the mixin-class-rgx option.
+# Tells whether to warn about missing members when the owner of the attribute is
+# inferred to be None.
+ignore-none = true
+
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference can
+# return multiple potential results while evaluating a Python object, but some
+# branches might not be evaluated, which results in partial inference. In that
+# case, it might be useful to still emit no-member and other checks for the rest
+# of the inferred objects.
+ignore-on-opaque-inference = true
+
+# List of symbolic message names to ignore for Mixin members.
+ignored-checks-for-mixins = ["no-member", "not-async-context-manager", "not-context-manager", "attribute-defined-outside-init"]
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes = ["optparse.Values", "thread._local", "_thread._local"]
+
+# Show a hint with possible names when a member name was not found. The aspect of
+# finding the hint is based on edit distance.
+missing-member-hint = true
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance = 1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices = 1
+
+# Regex pattern to define which classes are considered mixins.
+mixin-class-rgx = ".*[Mm]ixin"
+
+# List of decorators that change the signature of a decorated function.
+# signature-mutators =
+
+[tool.pylint.variables]
+# List of additional names supposed to be defined in builtins. Remember that you
+# should avoid defining new builtins when possible.
+# additional-builtins =
+
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables = true
+
+# List of names allowed to shadow builtins
+# allowed-redefined-builtins =
+
+# List of strings which can identify a callback function by name. A callback name
+# must start or end with one of those strings.
+callbacks = ["cb_", "_cb"]
+
+# A regular expression matching the name of dummy variables (i.e. expected to not
+# be used).
+dummy-variables-rgx = "_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_"
+
+# Argument names that match this expression will be ignored.
+ignored-argument-names = "_.*|^ignored_|^unused_"
+
+# Tells whether we should check for unused import in __init__ files.
+# init-import =
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules = ["six.moves", "future.builtins"]
diff --git a/setup.py b/setup.py
index 676f9d3..87b326e 100644
--- a/setup.py
+++ b/setup.py
@@ -1,60 +1,4 @@
-"""A setuptools based setup module.
-
-See:
-https://packaging.python.org/en/latest/distributing.html
-https://github.com/pypa/sampleproject
-"""
-
-from os import path
+"""All setup/install info is now in pyproject.toml"""
from setuptools import setup
-# To use a consistent encoding
-from codecs import open
-
-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="circuitpython-cirque-pinnacle",
- use_scm_version=True,
- setup_requires=["setuptools_scm"],
- description="A CircuitPython driver for Cirque Pinnacle (1CA027) touch "
- "controller used in Cirque Trackpads implementing the Adafruit_BusDevice library.",
- long_description=long_description,
- long_description_content_type="text/x-rst",
- # The project's main homepage.
- url="https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle",
- # Author details
- author="Brendan Doherty",
- author_email="2bndy5@gmail.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 blinka circuitpython Pinnacle "
- "touch sensor driver Cirque trackpad",
- # You can just specify the packages manually here if your project is
- # simple. Or you can use find_packages().
- # TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER,
- # CHANGE `py_modules=['...']` TO `packages=['...']`
- packages=["circuitpython_cirque_pinnacle"],
- # Extra links for the sidebar on pypi
- project_urls={
- "Documentation": "https://circuitpython-cirque-pinnacle.readthedocs.io",
- },
- download_url="https://github.com/2bndy5/CircuitPython_Cirque_Pinnacle/releases",
-)
+setup()