aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/frozen
diff options
context:
space:
mode:
Diffstat (limited to 'circuitpython/frozen')
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.pre-commit-config.yaml42
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.pylintrc436
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.readthedocs.yaml19
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/CODE_OF_CONDUCT.md135
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSE21
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/CC-BY-4.0.txt324
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/MIT.txt19
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/Unlicense.txt20
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/README.rst73
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/README.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/__init__.py0
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/i2c_device.py186
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/spi_device.py117
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/_static/favicon.icobin0 -> 4414 bytes
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/_static/favicon.ico.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/api.rst8
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/api.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/conf.py182
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/examples.rst12
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/examples.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/index.rst45
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/index.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/requirements.txt5
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/examples/busdevice_read_register_i2c_simpletest.py20
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/examples/busdevice_read_register_spi_simpletest.py22
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_BusDevice/requirements.txt6
-rwxr-xr-xcircuitpython/frozen/Adafruit_CircuitPython_BusDevice/setup.py55
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/.pre-commit-config.yaml42
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/.pylintrc436
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/.readthedocs.yaml15
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/CODE_OF_CONDUCT.md135
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSE21
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/CC-BY-4.0.txt324
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/MIT.txt19
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/Unlicense.txt20
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/README.rst160
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/README.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/__init__.py45
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control.py106
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control_code.py47
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard.py189
-rwxr-xr-xcircuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_base.py186
-rwxr-xr-xcircuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_us.py166
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keycode.py312
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/mouse.py152
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/docs/_static/favicon.icobin0 -> 4414 bytes
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/docs/_static/favicon.ico.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/docs/api.rst23
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/docs/api.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/docs/conf.py176
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/docs/examples.rst44
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/docs/examples.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/docs/index.rst45
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/docs/index.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/docs/requirements.txt5
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_consumer_control_brightness.py32
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py157
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_joywing_gamepad.py76
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_keyboard_shortcuts.py32
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_simple_gamepad.py57
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_simpletest.py31
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/requirements.txt5
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/setup.py55
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.pre-commit-config.yaml42
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.pylintrc436
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.readthedocs.yaml15
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/CODE_OF_CONDUCT.md135
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSE21
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/CC-BY-4.0.txt324
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/MIT.txt19
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/Unlicense.txt20
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/README.rst76
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/README.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/_static/favicon.icobin0 -> 4414 bytes
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/_static/favicon.ico.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/api.rst5
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/api.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/conf.py175
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/examples.rst16
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/examples.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/index.rst45
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/index.rst.license3
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/requirements.txt5
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_map_range_simpletest.py25
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_shift_in_out_demo.py38
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_tone_demo.py18
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/requirements.txt5
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/setup.py54
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/simpleio.py252
-rw-r--r--circuitpython/frozen/circuitpython-stage/LICENSE21
-rw-r--r--circuitpython/frozen/circuitpython-stage/README.rst44
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/.buildinfo4
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/.doctrees/README.doctreebin0 -> 8048 bytes
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/.doctrees/environment.picklebin0 -> 1971693 bytes
l---------circuitpython/frozen/circuitpython-stage/docs/README.rst1
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/_stage.py0
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/audioio.py3
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/board.py10
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/busio.py12
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/conf.py145
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/digitalio.py6
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/gamepad.py3
-rw-r--r--circuitpython/frozen/circuitpython-stage/docs/ustruct.py0
-rw-r--r--circuitpython/frozen/circuitpython-stage/examples/ball/ball.bmpbin0 -> 2234 bytes
-rw-r--r--circuitpython/frozen/circuitpython-stage/examples/ball/ball.py38
-rw-r--r--circuitpython/frozen/circuitpython-stage/examples/ball/main.py38
-rw-r--r--circuitpython/frozen/circuitpython-stage/examples/rpg/ground.bmpbin0 -> 2234 bytes
-rw-r--r--circuitpython/frozen/circuitpython-stage/examples/rpg/main.py68
-rw-r--r--circuitpython/frozen/circuitpython-stage/examples/rpg/tiles.bmpbin0 -> 2218 bytes
l---------circuitpython/frozen/circuitpython-stage/feather_m4_minitft_featherwing/stage.py1
-rw-r--r--circuitpython/frozen/circuitpython-stage/feather_m4_minitft_featherwing/ugame.py82
-rw-r--r--circuitpython/frozen/circuitpython-stage/font/font.bmpbin0 -> 4250 bytes
-rw-r--r--circuitpython/frozen/circuitpython-stage/font/font2.bmpbin0 -> 4250 bytes
-rw-r--r--circuitpython/frozen/circuitpython-stage/font/genfont.py89
-rw-r--r--circuitpython/frozen/circuitpython-stage/font/genfont2.py89
l---------circuitpython/frozen/circuitpython-stage/itsybitsy_m4_express/stage.py1
-rw-r--r--circuitpython/frozen/circuitpython-stage/itsybitsy_m4_express/ugame.py79
l---------circuitpython/frozen/circuitpython-stage/meowbit/stage.py1
-rw-r--r--circuitpython/frozen/circuitpython-stage/meowbit/ugame.py78
-rw-r--r--circuitpython/frozen/circuitpython-stage/pewpew_m4/pew.py203
l---------circuitpython/frozen/circuitpython-stage/pewpew_m4/stage.py1
-rw-r--r--circuitpython/frozen/circuitpython-stage/pewpew_m4/ugame.py79
l---------circuitpython/frozen/circuitpython-stage/picosystem/stage.py1
-rw-r--r--circuitpython/frozen/circuitpython-stage/picosystem/ugame.py86
l---------circuitpython/frozen/circuitpython-stage/pybadge/stage.py1
-rw-r--r--circuitpython/frozen/circuitpython-stage/pybadge/ugame.py122
l---------circuitpython/frozen/circuitpython-stage/pygamer/stage.py1
-rw-r--r--circuitpython/frozen/circuitpython-stage/pygamer/ugame.py136
-rw-r--r--circuitpython/frozen/circuitpython-stage/stage.py630
l---------circuitpython/frozen/circuitpython-stage/ugame10/stage.py1
-rw-r--r--circuitpython/frozen/circuitpython-stage/ugame10/ugame.py33
-rw-r--r--circuitpython/frozen/compromyse/compromyse.py0
132 files changed, 8738 insertions, 0 deletions
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.pre-commit-config.yaml b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.pre-commit-config.yaml
new file mode 100644
index 0000000..1b9fadc
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.pre-commit-config.yaml
@@ -0,0 +1,42 @@
+# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
+#
+# SPDX-License-Identifier: Unlicense
+
+repos:
+- repo: https://github.com/python/black
+ rev: 20.8b1
+ hooks:
+ - id: black
+- repo: https://github.com/fsfe/reuse-tool
+ rev: v0.12.1
+ hooks:
+ - id: reuse
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v2.3.0
+ hooks:
+ - id: check-yaml
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
+- repo: https://github.com/pycqa/pylint
+ rev: v2.11.1
+ hooks:
+ - id: pylint
+ name: pylint (library code)
+ types: [python]
+ args:
+ - --disable=consider-using-f-string
+ exclude: "^(docs/|examples/|tests/|setup.py$)"
+ - 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
+ - id: pylint
+ name: pylint (test code)
+ description: Run pylint rules on "tests/*.py" files
+ types: [python]
+ files: "^tests/"
+ args:
+ - --disable=missing-docstring,consider-using-f-string,duplicate-code
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.pylintrc b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.pylintrc
new file mode 100644
index 0000000..3908316
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.pylintrc
@@ -0,0 +1,436 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+[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
+
+# 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,bad-continuation,unspecified-encoding,duplicate-code
+
+# 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*(# )?<?https?://\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=yes
+
+# 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/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.readthedocs.yaml b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.readthedocs.yaml
new file mode 100644
index 0000000..33c2a61
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/.readthedocs.yaml
@@ -0,0 +1,19 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+build:
+ os: ubuntu-20.04
+ tools:
+ python: "3"
+
+python:
+ install:
+ - requirements: docs/requirements.txt
+ - requirements: requirements.txt
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/CODE_OF_CONDUCT.md b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..8a55c07
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/CODE_OF_CONDUCT.md
@@ -0,0 +1,135 @@
+<!--
+SPDX-FileCopyrightText: 2014 Coraline Ada Ehmke
+SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries
+SPDX-License-Identifier: CC-BY-4.0
+-->
+
+# Adafruit Community Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and leaders pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level or type of
+experience, education, socio-economic status, nationality, personal appearance,
+race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+We are committed to providing a friendly, safe and welcoming environment for
+all.
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Be kind and courteous to others
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Collaborating with other community members
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and sexual attention or advances
+* The use of inappropriate images, including in a community member's avatar
+* The use of inappropriate language, including in a community member's nickname
+* Any spamming, flaming, baiting or other attention-stealing behavior
+* Excessive or unwelcome helping; answering outside the scope of the question
+ asked
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Promoting or spreading disinformation, lies, or conspiracy theories against
+ a person, group, organisation, project, or community
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate
+
+The goal of the standards and moderation guidelines outlined here is to build
+and maintain a respectful community. We ask that you don’t just aim to be
+"technically unimpeachable", but rather try to be your best self.
+
+We value many things beyond technical expertise, including collaboration and
+supporting others within our community. Providing a positive experience for
+other community members can have a much more significant impact than simply
+providing the correct answer.
+
+## Our Responsibilities
+
+Project leaders are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project leaders have the right and responsibility to remove, edit, or
+reject messages, comments, commits, code, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any community member for other behaviors that they deem
+inappropriate, threatening, offensive, or harmful.
+
+## Moderation
+
+Instances of behaviors that violate the Adafruit Community Code of Conduct
+may be reported by any member of the community. Community members are
+encouraged to report these situations, including situations they witness
+involving other community members.
+
+You may report in the following ways:
+
+In any situation, you may send an email to <support@adafruit.com>.
+
+On the Adafruit Discord, you may send an open message from any channel
+to all Community Moderators by tagging @community moderators. You may
+also send an open message from any channel, or a direct message to
+@kattni#1507, @tannewt#4653, @Dan Halbert#1614, @cater#2442,
+@sommersoft#0222, @Mr. Certainly#0472 or @Andon#8175.
+
+Email and direct message reports will be kept confidential.
+
+In situations on Discord where the issue is particularly egregious, possibly
+illegal, requires immediate action, or violates the Discord terms of service,
+you should also report the message directly to Discord.
+
+These are the steps for upholding our community’s standards of conduct.
+
+1. Any member of the community may report any situation that violates the
+Adafruit Community Code of Conduct. All reports will be reviewed and
+investigated.
+2. If the behavior is an egregious violation, the community member who
+committed the violation may be banned immediately, without warning.
+3. Otherwise, moderators will first respond to such behavior with a warning.
+4. Moderators follow a soft "three strikes" policy - the community member may
+be given another chance, if they are receptive to the warning and change their
+behavior.
+5. If the community member is unreceptive or unreasonable when warned by a
+moderator, or the warning goes unheeded, they may be banned for a first or
+second offense. Repeated offenses will result in the community member being
+banned.
+
+## Scope
+
+This Code of Conduct and the enforcement policies listed above apply to all
+Adafruit Community venues. This includes but is not limited to any community
+spaces (both public and private), the entire Adafruit Discord server, and
+Adafruit GitHub repositories. Examples of Adafruit Community spaces include
+but are not limited to meet-ups, audio chats on the Adafruit Discord, or
+interaction at a conference.
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. As a community
+member, you are representing our community, and are expected to behave
+accordingly.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 1.4, available at
+<https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>,
+and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
+
+For other projects adopting the Adafruit Community Code of
+Conduct, please contact the maintainers of those projects for enforcement.
+If you wish to use this code of conduct for your own project, consider
+explicitly mentioning your moderation policy or making a copy with your
+own moderation policy so as to avoid confusion.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSE b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSE
new file mode 100644
index 0000000..19a9cd8
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Adafruit Industries
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/CC-BY-4.0.txt b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/CC-BY-4.0.txt
new file mode 100644
index 0000000..3f92dfc
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/CC-BY-4.0.txt
@@ -0,0 +1,324 @@
+Creative Commons Attribution 4.0 International Creative Commons Corporation
+("Creative Commons") is not a law firm and does not provide legal services
+or legal advice. Distribution of Creative Commons public licenses does not
+create a lawyer-client or other relationship. Creative Commons makes its licenses
+and related information available on an "as-is" basis. Creative Commons gives
+no warranties regarding its licenses, any material licensed under their terms
+and conditions, or any related information. Creative Commons disclaims all
+liability for damages resulting from their use to the fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and conditions
+that creators and other rights holders may use to share original works of
+authorship and other material subject to copyright and certain other rights
+specified in the public license below. The following considerations are for
+informational purposes only, are not exhaustive, and do not form part of our
+licenses.
+
+Considerations for licensors: Our public licenses are intended for use by
+those authorized to give the public permission to use material in ways otherwise
+restricted by copyright and certain other rights. Our licenses are irrevocable.
+Licensors should read and understand the terms and conditions of the license
+they choose before applying it. Licensors should also secure all rights necessary
+before applying our licenses so that the public can reuse the material as
+expected. Licensors should clearly mark any material not subject to the license.
+This includes other CC-licensed material, or material used under an exception
+or limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors
+
+Considerations for the public: By using one of our public licenses, a licensor
+grants the public permission to use the licensed material under specified
+terms and conditions. If the licensor's permission is not necessary for any
+reason–for example, because of any applicable exception or limitation to copyright–then
+that use is not regulated by the license. Our licenses grant only permissions
+under copyright and certain other rights that a licensor has authority to
+grant. Use of the licensed material may still be restricted for other reasons,
+including because others have copyright or other rights in the material. A
+licensor may make special requests, such as asking that all changes be marked
+or described. Although not required by our licenses, you are encouraged to
+respect those requests where reasonable. More considerations for the public
+: wiki.creativecommons.org/Considerations_for_licensees Creative Commons Attribution
+4.0 International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree to
+be bound by the terms and conditions of this Creative Commons Attribution
+4.0 International Public License ("Public License"). To the extent this Public
+License may be interpreted as a contract, You are granted the Licensed Rights
+in consideration of Your acceptance of these terms and conditions, and the
+Licensor grants You such rights in consideration of benefits the Licensor
+receives from making the Licensed Material available under these terms and
+conditions.
+
+Section 1 – Definitions.
+
+a. Adapted Material means material subject to Copyright and Similar Rights
+that is derived from or based upon the Licensed Material and in which the
+Licensed Material is translated, altered, arranged, transformed, or otherwise
+modified in a manner requiring permission under the Copyright and Similar
+Rights held by the Licensor. For purposes of this Public License, where the
+Licensed Material is a musical work, performance, or sound recording, Adapted
+Material is always produced where the Licensed Material is synched in timed
+relation with a moving image.
+
+b. Adapter's License means the license You apply to Your Copyright and Similar
+Rights in Your contributions to Adapted Material in accordance with the terms
+and conditions of this Public License.
+
+c. Copyright and Similar Rights means copyright and/or similar rights closely
+related to copyright including, without limitation, performance, broadcast,
+sound recording, and Sui Generis Database Rights, without regard to how the
+rights are labeled or categorized. For purposes of this Public License, the
+rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
+
+d. Effective Technological Measures means those measures that, in the absence
+of proper authority, may not be circumvented under laws fulfilling obligations
+under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996,
+and/or similar international agreements.
+
+e. Exceptions and Limitations means fair use, fair dealing, and/or any other
+exception or limitation to Copyright and Similar Rights that applies to Your
+use of the Licensed Material.
+
+f. Licensed Material means the artistic or literary work, database, or other
+material to which the Licensor applied this Public License.
+
+g. Licensed Rights means the rights granted to You subject to the terms and
+conditions of this Public License, which are limited to all Copyright and
+Similar Rights that apply to Your use of the Licensed Material and that the
+Licensor has authority to license.
+
+h. Licensor means the individual(s) or entity(ies) granting rights under this
+Public License.
+
+i. Share means to provide material to the public by any means or process that
+requires permission under the Licensed Rights, such as reproduction, public
+display, public performance, distribution, dissemination, communication, or
+importation, and to make material available to the public including in ways
+that members of the public may access the material from a place and at a time
+individually chosen by them.
+
+j. Sui Generis Database Rights means rights other than copyright resulting
+from Directive 96/9/EC of the European Parliament and of the Council of 11
+March 1996 on the legal protection of databases, as amended and/or succeeded,
+as well as other essentially equivalent rights anywhere in the world.
+
+k. You means the individual or entity exercising the Licensed Rights under
+this Public License. Your has a corresponding meaning.
+
+Section 2 – Scope.
+
+ a. License grant.
+
+1. Subject to the terms and conditions of this Public License, the Licensor
+hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive,
+irrevocable license to exercise the Licensed Rights in the Licensed Material
+to:
+
+ A. reproduce and Share the Licensed Material, in whole or in part; and
+
+ B. produce, reproduce, and Share Adapted Material.
+
+2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions
+and Limitations apply to Your use, this Public License does not apply, and
+You do not need to comply with its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section 6(a).
+
+4. Media and formats; technical modifications allowed. The Licensor authorizes
+You to exercise the Licensed Rights in all media and formats whether now known
+or hereafter created, and to make technical modifications necessary to do
+so. The Licensor waives and/or agrees not to assert any right or authority
+to forbid You from making technical modifications necessary to exercise the
+Licensed Rights, including technical modifications necessary to circumvent
+Effective Technological Measures. For purposes of this Public License, simply
+making modifications authorized by this Section 2(a)(4) never produces Adapted
+Material.
+
+ 5. Downstream recipients.
+
+A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed
+Material automatically receives an offer from the Licensor to exercise the
+Licensed Rights under the terms and conditions of this Public License.
+
+B. No downstream restrictions. You may not offer or impose any additional
+or different terms or conditions on, or apply any Effective Technological
+Measures to, the Licensed Material if doing so restricts exercise of the Licensed
+Rights by any recipient of the Licensed Material.
+
+6. No endorsement. Nothing in this Public License constitutes or may be construed
+as permission to assert or imply that You are, or that Your use of the Licensed
+Material is, connected with, or sponsored, endorsed, or granted official status
+by, the Licensor or others designated to receive attribution as provided in
+Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+1. Moral rights, such as the right of integrity, are not licensed under this
+Public License, nor are publicity, privacy, and/or other similar personality
+rights; however, to the extent possible, the Licensor waives and/or agrees
+not to assert any such rights held by the Licensor to the limited extent necessary
+to allow You to exercise the Licensed Rights, but not otherwise.
+
+2. Patent and trademark rights are not licensed under this Public License.
+
+3. To the extent possible, the Licensor waives any right to collect royalties
+from You for the exercise of the Licensed Rights, whether directly or through
+a collecting society under any voluntary or waivable statutory or compulsory
+licensing scheme. In all other cases the Licensor expressly reserves any right
+to collect such royalties.
+
+Section 3 – License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the following
+conditions.
+
+ a. Attribution.
+
+1. If You Share the Licensed Material (including in modified form), You must:
+
+A. retain the following if it is supplied by the Licensor with the Licensed
+Material:
+
+i. identification of the creator(s) of the Licensed Material and any others
+designated to receive attribution, in any reasonable manner requested by the
+Licensor (including by pseudonym if designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of warranties;
+
+v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
+
+B. indicate if You modified the Licensed Material and retain an indication
+of any previous modifications; and
+
+C. indicate the Licensed Material is licensed under this Public License, and
+include the text of, or the URI or hyperlink to, this Public License.
+
+2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner
+based on the medium, means, and context in which You Share the Licensed Material.
+For example, it may be reasonable to satisfy the conditions by providing a
+URI or hyperlink to a resource that includes the required information.
+
+3. If requested by the Licensor, You must remove any of the information required
+by Section 3(a)(1)(A) to the extent reasonably practicable.
+
+4. If You Share Adapted Material You produce, the Adapter's License You apply
+must not prevent recipients of the Adapted Material from complying with this
+Public License.
+
+Section 4 – Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that apply to
+Your use of the Licensed Material:
+
+a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract,
+reuse, reproduce, and Share all or a substantial portion of the contents of
+the database;
+
+b. if You include all or a substantial portion of the database contents in
+a database in which You have Sui Generis Database Rights, then the database
+in which You have Sui Generis Database Rights (but not its individual contents)
+is Adapted Material; and
+
+c. You must comply with the conditions in Section 3(a) if You Share all or
+a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not replace
+Your obligations under this Public License where the Licensed Rights include
+other Copyright and Similar Rights.
+
+Section 5 – Disclaimer of Warranties and Limitation of Liability.
+
+a. Unless otherwise separately undertaken by the Licensor, to the extent possible,
+the Licensor offers the Licensed Material as-is and as-available, and makes
+no representations or warranties of any kind concerning the Licensed Material,
+whether express, implied, statutory, or other. This includes, without limitation,
+warranties of title, merchantability, fitness for a particular purpose, non-infringement,
+absence of latent or other defects, accuracy, or the presence or absence of
+errors, whether or not known or discoverable. Where disclaimers of warranties
+are not allowed in full or in part, this disclaimer may not apply to You.
+
+b. To the extent possible, in no event will the Licensor be liable to You
+on any legal theory (including, without limitation, negligence) or otherwise
+for any direct, special, indirect, incidental, consequential, punitive, exemplary,
+or other losses, costs, expenses, or damages arising out of this Public License
+or use of the Licensed Material, even if the Licensor has been advised of
+the possibility of such losses, costs, expenses, or damages. Where a limitation
+of liability is not allowed in full or in part, this limitation may not apply
+to You.
+
+c. The disclaimer of warranties and limitation of liability provided above
+shall be interpreted in a manner that, to the extent possible, most closely
+approximates an absolute disclaimer and waiver of all liability.
+
+Section 6 – Term and Termination.
+
+a. This Public License applies for the term of the Copyright and Similar Rights
+licensed here. However, if You fail to comply with this Public License, then
+Your rights under this Public License terminate automatically.
+
+b. Where Your right to use the Licensed Material has terminated under Section
+6(a), it reinstates:
+
+1. automatically as of the date the violation is cured, provided it is cured
+within 30 days of Your discovery of the violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+c. For the avoidance of doubt, this Section 6(b) does not affect any right
+the Licensor may have to seek remedies for Your violations of this Public
+License.
+
+d. For the avoidance of doubt, the Licensor may also offer the Licensed Material
+under separate terms or conditions or stop distributing the Licensed Material
+at any time; however, doing so will not terminate this Public License.
+
+ e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
+
+Section 7 – Other Terms and Conditions.
+
+a. The Licensor shall not be bound by any additional or different terms or
+conditions communicated by You unless expressly agreed.
+
+b. Any arrangements, understandings, or agreements regarding the Licensed
+Material not stated herein are separate from and independent of the terms
+and conditions of this Public License.
+
+Section 8 – Interpretation.
+
+a. For the avoidance of doubt, this Public License does not, and shall not
+be interpreted to, reduce, limit, restrict, or impose conditions on any use
+of the Licensed Material that could lawfully be made without permission under
+this Public License.
+
+b. To the extent possible, if any provision of this Public License is deemed
+unenforceable, it shall be automatically reformed to the minimum extent necessary
+to make it enforceable. If the provision cannot be reformed, it shall be severed
+from this Public License without affecting the enforceability of the remaining
+terms and conditions.
+
+c. No term or condition of this Public License will be waived and no failure
+to comply consented to unless expressly agreed to by the Licensor.
+
+d. Nothing in this Public License constitutes or may be interpreted as a limitation
+upon, or waiver of, any privileges and immunities that apply to the Licensor
+or You, including from the legal processes of any jurisdiction or authority.
+
+Creative Commons is not a party to its public licenses. Notwithstanding, Creative
+Commons may elect to apply one of its public licenses to material it publishes
+and in those instances will be considered the "Licensor." The text of the
+Creative Commons public licenses is dedicated to the public domain under the
+CC0 Public Domain Dedication. Except for the limited purpose of indicating
+that material is shared under a Creative Commons public license or as otherwise
+permitted by the Creative Commons policies published at creativecommons.org/policies,
+Creative Commons does not authorize the use of the trademark "Creative Commons"
+or any other trademark or logo of Creative Commons without its prior written
+consent including, without limitation, in connection with any unauthorized
+modifications to any of its public licenses or any other arrangements, understandings,
+or agreements concerning use of licensed material. For the avoidance of doubt,
+this paragraph does not form part of the public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/MIT.txt b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/MIT.txt
new file mode 100644
index 0000000..204b93d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/MIT.txt
@@ -0,0 +1,19 @@
+MIT License Copyright (c) <year> <copyright holders>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/Unlicense.txt b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/Unlicense.txt
new file mode 100644
index 0000000..24a8f90
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/LICENSES/Unlicense.txt
@@ -0,0 +1,20 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute
+this software, either in source code form or as a compiled binary, for any
+purpose, commercial or non-commercial, and by any means.
+
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and
+to the detriment of our heirs and successors. We intend this dedication to
+be an overt act of relinquishment in perpetuity of all present and future
+rights to this software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information,
+please refer to <https://unlicense.org/>
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/README.rst b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/README.rst
new file mode 100644
index 0000000..8f5f40f
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/README.rst
@@ -0,0 +1,73 @@
+Adafruit CircuitPython BusDevice
+================================
+
+.. image:: https://readthedocs.org/projects/adafruit-circuitpython-busdevice/badge/?version=latest
+ :target: https://docs.circuitpython.org/projects/busdevice/en/latest/
+ :alt: Documentation Status
+
+.. image :: https://img.shields.io/discord/327254708534116352.svg
+ :target: https://adafru.it/discord
+ :alt: Discord
+
+.. image:: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice/workflows/Build%20CI/badge.svg
+ :target: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice/actions/
+ :alt: Build Status
+
+The ``I2CDevice`` and ``SPIDevice`` helper classes make managing transaction state
+on a bus easy. For example, they manage locking the bus to prevent other
+concurrent access. For SPI devices, it manages the chip select and protocol
+changes such as mode. For I2C, it manages the device address.
+
+.. _bus_device_installation:
+
+.. note:: On microcontroller boards using CircuitPython v6.3.0 or newer, the firmware
+ may already have the ``adafruit_bus_device`` package builtin, thus there may be no
+ need to add this package to your CIRCUITPY drive's "lib" directory. If both the
+ builtin and add-on ``adafruit_bus_device`` packages are present, then some
+ libraries that require this package *might* have problems importing it.
+
+ Please check the `CircuitPython documentation's "module support matrix"
+ <https://docs.circuitpython.org/en/latest/shared-bindings/support_matrix.html>`_
+ to make sure that your board's firmware does include the builtin ``adafruit_bus_device``
+ package.
+
+On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
+PyPI <https://pypi.org/project/adafruit-circuitpython-busdevice/>`_. To install for current user:
+
+.. code-block:: shell
+
+ pip3 install adafruit-circuitpython-busdevice
+
+To install system-wide (this may be required in some cases):
+
+.. code-block:: shell
+
+ sudo pip3 install adafruit-circuitpython-busdevice
+
+To install in a virtual environment in your current project:
+
+.. code-block:: shell
+
+ mkdir project-name && cd project-name
+ python3 -m venv .env
+ source .env/bin/activate
+ pip3 install adafruit-circuitpython-busdevice
+
+Usage Example
+=============
+
+See examples/read_register_i2c.py and examples/read_register_spi.py for examples of the module's usage.
+
+Documentation
+=============
+
+API documentation for this library can be found on `Read the Docs <https://docs.circuitpython.org/projects/busdevice/en/latest/>`_.
+
+For information on building library documentation, please check out `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.
+
+Contributing
+============
+
+Contributions are welcome! Please read our `Code of Conduct
+<https://github.com/adafruit/Adafruit_CircuitPython_BusDevice/blob/main/CODE_OF_CONDUCT.md>`_
+before contributing to help this project stay welcoming.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/README.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/README.rst.license
new file mode 100644
index 0000000..11cd75d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/README.rst.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
+
+SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/__init__.py b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/__init__.py
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/i2c_device.py b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/i2c_device.py
new file mode 100644
index 0000000..5e18849
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/i2c_device.py
@@ -0,0 +1,186 @@
+# SPDX-FileCopyrightText: 2016 Scott Shawcroft for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_bus_device.i2c_device` - I2C Bus Device
+====================================================
+"""
+
+try:
+ from typing import Optional, Type
+ from types import TracebackType
+ from circuitpython_typing import ReadableBuffer, WriteableBuffer
+
+ # Used only for type annotations.
+ from busio import I2C
+except ImportError:
+ pass
+
+
+__version__ = "0.0.0-auto.0"
+__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BusDevice.git"
+
+
+class I2CDevice:
+ """
+ Represents a single I2C device and manages locking the bus and the device
+ address.
+
+ :param ~busio.I2C i2c: The I2C bus the device is on
+ :param int device_address: The 7 bit device address
+ :param bool probe: Probe for the device upon object creation, default is true
+
+ .. note:: This class is **NOT** built into CircuitPython. See
+ :ref:`here for install instructions <bus_device_installation>`.
+
+ Example:
+
+ .. code-block:: python
+
+ import busio
+ from board import *
+ from adafruit_bus_device.i2c_device import I2CDevice
+
+ with busio.I2C(SCL, SDA) as i2c:
+ device = I2CDevice(i2c, 0x70)
+ bytes_read = bytearray(4)
+ with device:
+ device.readinto(bytes_read)
+ # A second transaction
+ with device:
+ device.write(bytes_read)
+ """
+
+ def __init__(self, i2c: I2C, device_address: int, probe: bool = True) -> None:
+
+ self.i2c = i2c
+ self.device_address = device_address
+
+ if probe:
+ self.__probe_for_device()
+
+ def readinto(
+ self, buf: WriteableBuffer, *, start: int = 0, end: Optional[int] = None
+ ) -> None:
+ """
+ Read into ``buf`` from the device. The number of bytes read will be the
+ length of ``buf``.
+
+ If ``start`` or ``end`` is provided, then the buffer will be sliced
+ as if ``buf[start:end]``. This will not cause an allocation like
+ ``buf[start:end]`` will so it saves memory.
+
+ :param ~WriteableBuffer buffer: buffer to write into
+ :param int start: Index to start writing at
+ :param int end: Index to write up to but not include; if None, use ``len(buf)``
+ """
+ if end is None:
+ end = len(buf)
+ self.i2c.readfrom_into(self.device_address, buf, start=start, end=end)
+
+ def write(
+ self, buf: ReadableBuffer, *, start: int = 0, end: Optional[int] = None
+ ) -> None:
+ """
+ Write the bytes from ``buffer`` to the device, then transmit a stop
+ bit.
+
+ If ``start`` or ``end`` is provided, then the buffer will be sliced
+ as if ``buffer[start:end]``. This will not cause an allocation like
+ ``buffer[start:end]`` will so it saves memory.
+
+ :param ~ReadableBuffer buffer: buffer containing the bytes to write
+ :param int start: Index to start writing from
+ :param int end: Index to read up to but not include; if None, use ``len(buf)``
+ """
+ if end is None:
+ end = len(buf)
+ self.i2c.writeto(self.device_address, buf, start=start, end=end)
+
+ # pylint: disable-msg=too-many-arguments
+ def write_then_readinto(
+ self,
+ out_buffer: ReadableBuffer,
+ in_buffer: WriteableBuffer,
+ *,
+ out_start: int = 0,
+ out_end: Optional[int] = None,
+ in_start: int = 0,
+ in_end: Optional[int] = None
+ ) -> None:
+ """
+ Write the bytes from ``out_buffer`` to the device, then immediately
+ reads into ``in_buffer`` from the device. The number of bytes read
+ will be the length of ``in_buffer``.
+
+ If ``out_start`` or ``out_end`` is provided, then the output buffer
+ will be sliced as if ``out_buffer[out_start:out_end]``. This will
+ not cause an allocation like ``buffer[out_start:out_end]`` will so
+ it saves memory.
+
+ If ``in_start`` or ``in_end`` is provided, then the input buffer
+ will be sliced as if ``in_buffer[in_start:in_end]``. This will not
+ cause an allocation like ``in_buffer[in_start:in_end]`` will so
+ it saves memory.
+
+ :param ~ReadableBuffer out_buffer: buffer containing the bytes to write
+ :param ~WriteableBuffer in_buffer: buffer containing the bytes to read into
+ :param int out_start: Index to start writing from
+ :param int out_end: Index to read up to but not include; if None, use ``len(out_buffer)``
+ :param int in_start: Index to start writing at
+ :param int in_end: Index to write up to but not include; if None, use ``len(in_buffer)``
+ """
+ if out_end is None:
+ out_end = len(out_buffer)
+ if in_end is None:
+ in_end = len(in_buffer)
+
+ self.i2c.writeto_then_readfrom(
+ self.device_address,
+ out_buffer,
+ in_buffer,
+ out_start=out_start,
+ out_end=out_end,
+ in_start=in_start,
+ in_end=in_end,
+ )
+
+ # pylint: enable-msg=too-many-arguments
+
+ def __enter__(self) -> "I2CDevice":
+ while not self.i2c.try_lock():
+ pass
+ return self
+
+ def __exit__(
+ self,
+ exc_type: Optional[Type[type]],
+ exc_val: Optional[BaseException],
+ exc_tb: Optional[TracebackType],
+ ) -> bool:
+ self.i2c.unlock()
+ return False
+
+ def __probe_for_device(self) -> None:
+ """
+ Try to read a byte from an address,
+ if you get an OSError it means the device is not there
+ or that the device does not support these means of probing
+ """
+ while not self.i2c.try_lock():
+ pass
+ try:
+ self.i2c.writeto(self.device_address, b"")
+ except OSError:
+ # some OS's dont like writing an empty bytesting...
+ # Retry by reading a byte
+ try:
+ result = bytearray(1)
+ self.i2c.readfrom_into(self.device_address, result)
+ except OSError:
+ # pylint: disable=raise-missing-from
+ raise ValueError("No I2C device at address: 0x%x" % self.device_address)
+ # pylint: enable=raise-missing-from
+ finally:
+ self.i2c.unlock()
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/spi_device.py b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/spi_device.py
new file mode 100644
index 0000000..f4b825a
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/adafruit_bus_device/spi_device.py
@@ -0,0 +1,117 @@
+# SPDX-FileCopyrightText: 2016 Scott Shawcroft for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+# pylint: disable=too-few-public-methods
+
+"""
+`adafruit_bus_device.spi_device` - SPI Bus Device
+====================================================
+"""
+
+try:
+ from typing import Optional, Type
+ from types import TracebackType
+
+ # Used only for type annotations.
+ from busio import SPI
+ from digitalio import DigitalInOut
+except ImportError:
+ pass
+
+
+__version__ = "0.0.0-auto.0"
+__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BusDevice.git"
+
+
+class SPIDevice:
+ """
+ Represents a single SPI device and manages locking the bus and the device
+ address.
+
+ :param ~busio.SPI spi: The SPI bus the device is on
+ :param ~digitalio.DigitalInOut chip_select: The chip select pin object that implements the
+ DigitalInOut API.
+ :param bool cs_active_value: Set to true if your device requires CS to be active high.
+ Defaults to false.
+ :param int baudrate: The SPI baudrate
+ :param int polarity: The SPI polarity
+ :param int phase: The SPI phase
+ :param int extra_clocks: The minimum number of clock cycles to cycle the bus after CS is high.
+ (Used for SD cards.)
+
+ .. note:: This class is **NOT** built into CircuitPython. See
+ :ref:`here for install instructions <bus_device_installation>`.
+
+ Example:
+
+ .. code-block:: python
+
+ import busio
+ import digitalio
+ from board import *
+ from adafruit_bus_device.spi_device import SPIDevice
+
+ with busio.SPI(SCK, MOSI, MISO) as spi_bus:
+ cs = digitalio.DigitalInOut(D10)
+ device = SPIDevice(spi_bus, cs)
+ bytes_read = bytearray(4)
+ # The object assigned to spi in the with statements below
+ # is the original spi_bus object. We are using the busio.SPI
+ # operations busio.SPI.readinto() and busio.SPI.write().
+ with device as spi:
+ spi.readinto(bytes_read)
+ # A second transaction
+ with device as spi:
+ spi.write(bytes_read)
+ """
+
+ def __init__(
+ self,
+ spi: SPI,
+ chip_select: Optional[DigitalInOut] = None,
+ *,
+ cs_active_value: bool = False,
+ baudrate: int = 100000,
+ polarity: int = 0,
+ phase: int = 0,
+ extra_clocks: int = 0
+ ) -> None:
+ self.spi = spi
+ self.baudrate = baudrate
+ self.polarity = polarity
+ self.phase = phase
+ self.extra_clocks = extra_clocks
+ self.chip_select = chip_select
+ self.cs_active_value = cs_active_value
+ if self.chip_select:
+ self.chip_select.switch_to_output(value=True)
+
+ def __enter__(self) -> SPI:
+ while not self.spi.try_lock():
+ pass
+ self.spi.configure(
+ baudrate=self.baudrate, polarity=self.polarity, phase=self.phase
+ )
+ if self.chip_select:
+ self.chip_select.value = self.cs_active_value
+ return self.spi
+
+ def __exit__(
+ self,
+ exc_type: Optional[Type[type]],
+ exc_val: Optional[BaseException],
+ exc_tb: Optional[TracebackType],
+ ) -> bool:
+ if self.chip_select:
+ self.chip_select.value = not self.cs_active_value
+ if self.extra_clocks > 0:
+ buf = bytearray(1)
+ buf[0] = 0xFF
+ clocks = self.extra_clocks // 8
+ if self.extra_clocks % 8 != 0:
+ clocks += 1
+ for _ in range(clocks):
+ self.spi.write(buf)
+ self.spi.unlock()
+ return False
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/_static/favicon.ico b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/_static/favicon.ico
new file mode 100644
index 0000000..5aca983
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/_static/favicon.ico
Binary files differ
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/_static/favicon.ico.license b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/_static/favicon.ico.license
new file mode 100644
index 0000000..86a3fbf
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/_static/favicon.ico.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2018 Phillip Torrone for Adafruit Industries
+
+SPDX-License-Identifier: CC-BY-4.0
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/api.rst b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/api.rst
new file mode 100644
index 0000000..17b4ce3
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/api.rst
@@ -0,0 +1,8 @@
+
+.. If you created a package, create one automodule per module in the package.
+
+.. automodule:: adafruit_bus_device.i2c_device
+ :members:
+
+.. automodule:: adafruit_bus_device.spi_device
+ :members:
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/api.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/api.rst.license
new file mode 100644
index 0000000..9aae48d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/api.rst.license
@@ -0,0 +1,3 @@
+# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/conf.py b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/conf.py
new file mode 100644
index 0000000..f1f440c
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/conf.py
@@ -0,0 +1,182 @@
+# -*- coding: utf-8 -*-
+
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+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.viewcode",
+]
+
+# 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 = []
+
+intersphinx_mapping = {
+ "python": ("https://docs.python.org/3", None),
+ "BusDevice": (
+ "https://docs.circuitpython.org/projects/busdevice/en/latest/",
+ None,
+ ),
+ "CircuitPython": ("https://docs.circuitpython.org/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 = "Adafruit CircuitPython Bus Device"
+copyright = "2016-2017 Scott Shawcroft and Tony Dicola for Adafruit Industries"
+author = "Scott Shawcroft and Tony Dicola"
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = "1.0"
+# The full version, including alpha/beta/rc tags.
+release = "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 = True
+
+
+# -- 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"]
+
+# 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 = "AdafruitBusDeviceLibrarydoc"
+
+# -- 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,
+ "AdafruitBusDeviceLibrary.tex",
+ "Adafruit Bus Device 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,
+ "AdafruitBusDeviceLibrary",
+ "Adafruit Bus Device 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,
+ "AdafruitBusDeviceLibrary",
+ "Adafruit Bus Device Library Documentation",
+ author,
+ "AdafruitBusDeviceLibrary",
+ "One line description of project.",
+ "Miscellaneous",
+ ),
+]
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/examples.rst b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/examples.rst
new file mode 100644
index 0000000..abd05c4
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/examples.rst
@@ -0,0 +1,12 @@
+Simple test
+------------
+
+Ensure your device works with this simple test.
+
+.. literalinclude:: ../examples/busdevice_read_register_i2c_simpletest.py
+ :caption: examples/busdevice_read_register_i2c_simpletest.py
+ :linenos:
+
+.. literalinclude:: ../examples/busdevice_read_register_spi_simpletest.py
+ :caption: examples/busdevice_read_register_spi_simpletest.py
+ :linenos:
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/examples.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/examples.rst.license
new file mode 100644
index 0000000..9aae48d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/examples.rst.license
@@ -0,0 +1,3 @@
+# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/index.rst b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/index.rst
new file mode 100644
index 0000000..dac7838
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/index.rst
@@ -0,0 +1,45 @@
+.. include:: ../README.rst
+
+Table of Contents
+=================
+
+.. toctree::
+ :maxdepth: 4
+ :hidden:
+
+ self
+
+.. toctree::
+ :caption: Examples
+
+ examples
+
+.. toctree::
+ :caption: API Reference
+ :maxdepth: 3
+
+ api
+
+.. toctree::
+ :caption: Tutorials
+
+.. toctree::
+ :caption: Related Products
+
+.. toctree::
+ :caption: Other Links
+
+ Download <https://github.com/adafruit/Adafruit_CircuitPython_BusDevice/releases/latest>
+ CircuitPython Reference Documentation <https://docs.circuitpython.org>
+ CircuitPython Support Forum <https://forums.adafruit.com/viewforum.php?f=60>
+ Discord Chat <https://adafru.it/discord>
+ Adafruit Learning System <https://learn.adafruit.com>
+ Adafruit Blog <https://blog.adafruit.com>
+ Adafruit Store <https://www.adafruit.com>
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/index.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/index.rst.license
new file mode 100644
index 0000000..9aae48d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/index.rst.license
@@ -0,0 +1,3 @@
+# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/requirements.txt b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/requirements.txt
new file mode 100644
index 0000000..88e6733
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/docs/requirements.txt
@@ -0,0 +1,5 @@
+# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+sphinx>=4.0.0
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/examples/busdevice_read_register_i2c_simpletest.py b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/examples/busdevice_read_register_i2c_simpletest.py
new file mode 100644
index 0000000..c3d78f8
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/examples/busdevice_read_register_i2c_simpletest.py
@@ -0,0 +1,20 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+# SPDX-License-Identifier: MIT
+
+import busio
+import board
+from adafruit_bus_device.i2c_device import I2CDevice
+
+DEVICE_ADDRESS = 0x68 # device address of DS3231 board
+A_DEVICE_REGISTER = 0x0E # device id register on the DS3231 board
+
+# The follow is for I2C communications
+comm_port = busio.I2C(board.SCL, board.SDA)
+device = I2CDevice(comm_port, DEVICE_ADDRESS)
+
+with device as bus_device:
+ bus_device.write(bytes([A_DEVICE_REGISTER]))
+ result = bytearray(1)
+ bus_device.readinto(result)
+
+print("".join("{:02x}".format(x) for x in result))
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/examples/busdevice_read_register_spi_simpletest.py b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/examples/busdevice_read_register_spi_simpletest.py
new file mode 100644
index 0000000..995f7de
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/examples/busdevice_read_register_spi_simpletest.py
@@ -0,0 +1,22 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+# SPDX-License-Identifier: MIT
+
+import busio
+import board
+import digitalio
+from adafruit_bus_device.spi_device import SPIDevice
+
+A_DEVICE_REGISTER = 0xD0 # device id register on the BMP280 board
+
+# The follow is for SPI communications
+cs = digitalio.DigitalInOut(board.A2)
+comm_port = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
+device = SPIDevice(comm_port, cs)
+
+# pylint: disable-msg=no-member
+with device as bus_device:
+ bus_device.write(bytes([A_DEVICE_REGISTER]))
+ result = bytearray(1)
+ bus_device.readinto(result)
+
+print("".join("{:02x}".format(x) for x in result))
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/requirements.txt b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/requirements.txt
new file mode 100644
index 0000000..f2ef0cc
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/requirements.txt
@@ -0,0 +1,6 @@
+# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+Adafruit-Blinka>=7.0.0
+adafruit-circuitpython-typing
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/setup.py b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/setup.py
new file mode 100755
index 0000000..99ded02
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_BusDevice/setup.py
@@ -0,0 +1,55 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""A setuptools based setup module.
+
+See:
+https://packaging.python.org/en/latest/distributing.html
+https://github.com/pypa/sampleproject
+"""
+
+# Always prefer setuptools over distutils
+from setuptools import setup, find_packages
+
+# To use a consistent encoding
+from codecs import open
+from os import path
+
+here = path.abspath(path.dirname(__file__))
+
+# Get the long description from the README file
+with open(path.join(here, "README.rst"), encoding="utf-8") as f:
+ long_description = f.read()
+
+setup(
+ name="adafruit-circuitpython-busdevice",
+ use_scm_version=True,
+ setup_requires=["setuptools_scm"],
+ description="CircuitPython bus device classes to manage bus sharing.",
+ long_description=long_description,
+ long_description_content_type="text/x-rst",
+ # The project's main homepage.
+ url="https://github.com/adafruit/Adafruit_CircuitPython_BusDevice",
+ # Author details
+ author="Adafruit Industries",
+ author_email="circuitpython@adafruit.com",
+ python_requires=">=3.7.0",
+ install_requires=["Adafruit-Blinka>=7.0.0", "adafruit-circuitpython-typing"],
+ # 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",
+ ],
+ # What does your project relate to?
+ keywords="adafruit spi i2c bus device micropython circuitpython",
+ # You can just specify the packages manually here if your project is
+ # simple. Or you can use find_packages().
+ packages=["adafruit_bus_device"],
+)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/.pre-commit-config.yaml b/circuitpython/frozen/Adafruit_CircuitPython_HID/.pre-commit-config.yaml
new file mode 100644
index 0000000..43d1385
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/.pre-commit-config.yaml
@@ -0,0 +1,42 @@
+# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
+#
+# SPDX-License-Identifier: Unlicense
+
+repos:
+- repo: https://github.com/python/black
+ rev: 20.8b1
+ hooks:
+ - id: black
+- repo: https://github.com/fsfe/reuse-tool
+ rev: v0.12.1
+ hooks:
+ - id: reuse
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v2.3.0
+ hooks:
+ - id: check-yaml
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
+- repo: https://github.com/pycqa/pylint
+ rev: v2.11.1
+ hooks:
+ - id: pylint
+ name: pylint (library code)
+ types: [python]
+ args:
+ - --disable=consider-using-f-string,duplicate-code
+ exclude: "^(docs/|examples/|tests/|setup.py$)"
+ - 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
+ - id: pylint
+ name: pylint (test code)
+ description: Run pylint rules on "tests/*.py" files
+ types: [python]
+ files: "^tests/"
+ args:
+ - --disable=missing-docstring,consider-using-f-string,duplicate-code
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/.pylintrc b/circuitpython/frozen/Adafruit_CircuitPython_HID/.pylintrc
new file mode 100644
index 0000000..cfd1c41
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/.pylintrc
@@ -0,0 +1,436 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+[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
+
+# 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,bad-continuation,unspecified-encoding
+
+# 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*(# )?<?https?://\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=yes
+
+# 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/circuitpython/frozen/Adafruit_CircuitPython_HID/.readthedocs.yaml b/circuitpython/frozen/Adafruit_CircuitPython_HID/.readthedocs.yaml
new file mode 100644
index 0000000..f8b2891
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/.readthedocs.yaml
@@ -0,0 +1,15 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+python:
+ version: "3.x"
+ install:
+ - requirements: docs/requirements.txt
+ - requirements: requirements.txt
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/CODE_OF_CONDUCT.md b/circuitpython/frozen/Adafruit_CircuitPython_HID/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..8a55c07
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/CODE_OF_CONDUCT.md
@@ -0,0 +1,135 @@
+<!--
+SPDX-FileCopyrightText: 2014 Coraline Ada Ehmke
+SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries
+SPDX-License-Identifier: CC-BY-4.0
+-->
+
+# Adafruit Community Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and leaders pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level or type of
+experience, education, socio-economic status, nationality, personal appearance,
+race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+We are committed to providing a friendly, safe and welcoming environment for
+all.
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Be kind and courteous to others
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Collaborating with other community members
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and sexual attention or advances
+* The use of inappropriate images, including in a community member's avatar
+* The use of inappropriate language, including in a community member's nickname
+* Any spamming, flaming, baiting or other attention-stealing behavior
+* Excessive or unwelcome helping; answering outside the scope of the question
+ asked
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Promoting or spreading disinformation, lies, or conspiracy theories against
+ a person, group, organisation, project, or community
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate
+
+The goal of the standards and moderation guidelines outlined here is to build
+and maintain a respectful community. We ask that you don’t just aim to be
+"technically unimpeachable", but rather try to be your best self.
+
+We value many things beyond technical expertise, including collaboration and
+supporting others within our community. Providing a positive experience for
+other community members can have a much more significant impact than simply
+providing the correct answer.
+
+## Our Responsibilities
+
+Project leaders are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project leaders have the right and responsibility to remove, edit, or
+reject messages, comments, commits, code, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any community member for other behaviors that they deem
+inappropriate, threatening, offensive, or harmful.
+
+## Moderation
+
+Instances of behaviors that violate the Adafruit Community Code of Conduct
+may be reported by any member of the community. Community members are
+encouraged to report these situations, including situations they witness
+involving other community members.
+
+You may report in the following ways:
+
+In any situation, you may send an email to <support@adafruit.com>.
+
+On the Adafruit Discord, you may send an open message from any channel
+to all Community Moderators by tagging @community moderators. You may
+also send an open message from any channel, or a direct message to
+@kattni#1507, @tannewt#4653, @Dan Halbert#1614, @cater#2442,
+@sommersoft#0222, @Mr. Certainly#0472 or @Andon#8175.
+
+Email and direct message reports will be kept confidential.
+
+In situations on Discord where the issue is particularly egregious, possibly
+illegal, requires immediate action, or violates the Discord terms of service,
+you should also report the message directly to Discord.
+
+These are the steps for upholding our community’s standards of conduct.
+
+1. Any member of the community may report any situation that violates the
+Adafruit Community Code of Conduct. All reports will be reviewed and
+investigated.
+2. If the behavior is an egregious violation, the community member who
+committed the violation may be banned immediately, without warning.
+3. Otherwise, moderators will first respond to such behavior with a warning.
+4. Moderators follow a soft "three strikes" policy - the community member may
+be given another chance, if they are receptive to the warning and change their
+behavior.
+5. If the community member is unreceptive or unreasonable when warned by a
+moderator, or the warning goes unheeded, they may be banned for a first or
+second offense. Repeated offenses will result in the community member being
+banned.
+
+## Scope
+
+This Code of Conduct and the enforcement policies listed above apply to all
+Adafruit Community venues. This includes but is not limited to any community
+spaces (both public and private), the entire Adafruit Discord server, and
+Adafruit GitHub repositories. Examples of Adafruit Community spaces include
+but are not limited to meet-ups, audio chats on the Adafruit Discord, or
+interaction at a conference.
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. As a community
+member, you are representing our community, and are expected to behave
+accordingly.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 1.4, available at
+<https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>,
+and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
+
+For other projects adopting the Adafruit Community Code of
+Conduct, please contact the maintainers of those projects for enforcement.
+If you wish to use this code of conduct for your own project, consider
+explicitly mentioning your moderation policy or making a copy with your
+own moderation policy so as to avoid confusion.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSE b/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSE
new file mode 100644
index 0000000..de855cb
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/CC-BY-4.0.txt b/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/CC-BY-4.0.txt
new file mode 100644
index 0000000..3f92dfc
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/CC-BY-4.0.txt
@@ -0,0 +1,324 @@
+Creative Commons Attribution 4.0 International Creative Commons Corporation
+("Creative Commons") is not a law firm and does not provide legal services
+or legal advice. Distribution of Creative Commons public licenses does not
+create a lawyer-client or other relationship. Creative Commons makes its licenses
+and related information available on an "as-is" basis. Creative Commons gives
+no warranties regarding its licenses, any material licensed under their terms
+and conditions, or any related information. Creative Commons disclaims all
+liability for damages resulting from their use to the fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and conditions
+that creators and other rights holders may use to share original works of
+authorship and other material subject to copyright and certain other rights
+specified in the public license below. The following considerations are for
+informational purposes only, are not exhaustive, and do not form part of our
+licenses.
+
+Considerations for licensors: Our public licenses are intended for use by
+those authorized to give the public permission to use material in ways otherwise
+restricted by copyright and certain other rights. Our licenses are irrevocable.
+Licensors should read and understand the terms and conditions of the license
+they choose before applying it. Licensors should also secure all rights necessary
+before applying our licenses so that the public can reuse the material as
+expected. Licensors should clearly mark any material not subject to the license.
+This includes other CC-licensed material, or material used under an exception
+or limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors
+
+Considerations for the public: By using one of our public licenses, a licensor
+grants the public permission to use the licensed material under specified
+terms and conditions. If the licensor's permission is not necessary for any
+reason–for example, because of any applicable exception or limitation to copyright–then
+that use is not regulated by the license. Our licenses grant only permissions
+under copyright and certain other rights that a licensor has authority to
+grant. Use of the licensed material may still be restricted for other reasons,
+including because others have copyright or other rights in the material. A
+licensor may make special requests, such as asking that all changes be marked
+or described. Although not required by our licenses, you are encouraged to
+respect those requests where reasonable. More considerations for the public
+: wiki.creativecommons.org/Considerations_for_licensees Creative Commons Attribution
+4.0 International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree to
+be bound by the terms and conditions of this Creative Commons Attribution
+4.0 International Public License ("Public License"). To the extent this Public
+License may be interpreted as a contract, You are granted the Licensed Rights
+in consideration of Your acceptance of these terms and conditions, and the
+Licensor grants You such rights in consideration of benefits the Licensor
+receives from making the Licensed Material available under these terms and
+conditions.
+
+Section 1 – Definitions.
+
+a. Adapted Material means material subject to Copyright and Similar Rights
+that is derived from or based upon the Licensed Material and in which the
+Licensed Material is translated, altered, arranged, transformed, or otherwise
+modified in a manner requiring permission under the Copyright and Similar
+Rights held by the Licensor. For purposes of this Public License, where the
+Licensed Material is a musical work, performance, or sound recording, Adapted
+Material is always produced where the Licensed Material is synched in timed
+relation with a moving image.
+
+b. Adapter's License means the license You apply to Your Copyright and Similar
+Rights in Your contributions to Adapted Material in accordance with the terms
+and conditions of this Public License.
+
+c. Copyright and Similar Rights means copyright and/or similar rights closely
+related to copyright including, without limitation, performance, broadcast,
+sound recording, and Sui Generis Database Rights, without regard to how the
+rights are labeled or categorized. For purposes of this Public License, the
+rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
+
+d. Effective Technological Measures means those measures that, in the absence
+of proper authority, may not be circumvented under laws fulfilling obligations
+under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996,
+and/or similar international agreements.
+
+e. Exceptions and Limitations means fair use, fair dealing, and/or any other
+exception or limitation to Copyright and Similar Rights that applies to Your
+use of the Licensed Material.
+
+f. Licensed Material means the artistic or literary work, database, or other
+material to which the Licensor applied this Public License.
+
+g. Licensed Rights means the rights granted to You subject to the terms and
+conditions of this Public License, which are limited to all Copyright and
+Similar Rights that apply to Your use of the Licensed Material and that the
+Licensor has authority to license.
+
+h. Licensor means the individual(s) or entity(ies) granting rights under this
+Public License.
+
+i. Share means to provide material to the public by any means or process that
+requires permission under the Licensed Rights, such as reproduction, public
+display, public performance, distribution, dissemination, communication, or
+importation, and to make material available to the public including in ways
+that members of the public may access the material from a place and at a time
+individually chosen by them.
+
+j. Sui Generis Database Rights means rights other than copyright resulting
+from Directive 96/9/EC of the European Parliament and of the Council of 11
+March 1996 on the legal protection of databases, as amended and/or succeeded,
+as well as other essentially equivalent rights anywhere in the world.
+
+k. You means the individual or entity exercising the Licensed Rights under
+this Public License. Your has a corresponding meaning.
+
+Section 2 – Scope.
+
+ a. License grant.
+
+1. Subject to the terms and conditions of this Public License, the Licensor
+hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive,
+irrevocable license to exercise the Licensed Rights in the Licensed Material
+to:
+
+ A. reproduce and Share the Licensed Material, in whole or in part; and
+
+ B. produce, reproduce, and Share Adapted Material.
+
+2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions
+and Limitations apply to Your use, this Public License does not apply, and
+You do not need to comply with its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section 6(a).
+
+4. Media and formats; technical modifications allowed. The Licensor authorizes
+You to exercise the Licensed Rights in all media and formats whether now known
+or hereafter created, and to make technical modifications necessary to do
+so. The Licensor waives and/or agrees not to assert any right or authority
+to forbid You from making technical modifications necessary to exercise the
+Licensed Rights, including technical modifications necessary to circumvent
+Effective Technological Measures. For purposes of this Public License, simply
+making modifications authorized by this Section 2(a)(4) never produces Adapted
+Material.
+
+ 5. Downstream recipients.
+
+A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed
+Material automatically receives an offer from the Licensor to exercise the
+Licensed Rights under the terms and conditions of this Public License.
+
+B. No downstream restrictions. You may not offer or impose any additional
+or different terms or conditions on, or apply any Effective Technological
+Measures to, the Licensed Material if doing so restricts exercise of the Licensed
+Rights by any recipient of the Licensed Material.
+
+6. No endorsement. Nothing in this Public License constitutes or may be construed
+as permission to assert or imply that You are, or that Your use of the Licensed
+Material is, connected with, or sponsored, endorsed, or granted official status
+by, the Licensor or others designated to receive attribution as provided in
+Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+1. Moral rights, such as the right of integrity, are not licensed under this
+Public License, nor are publicity, privacy, and/or other similar personality
+rights; however, to the extent possible, the Licensor waives and/or agrees
+not to assert any such rights held by the Licensor to the limited extent necessary
+to allow You to exercise the Licensed Rights, but not otherwise.
+
+2. Patent and trademark rights are not licensed under this Public License.
+
+3. To the extent possible, the Licensor waives any right to collect royalties
+from You for the exercise of the Licensed Rights, whether directly or through
+a collecting society under any voluntary or waivable statutory or compulsory
+licensing scheme. In all other cases the Licensor expressly reserves any right
+to collect such royalties.
+
+Section 3 – License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the following
+conditions.
+
+ a. Attribution.
+
+1. If You Share the Licensed Material (including in modified form), You must:
+
+A. retain the following if it is supplied by the Licensor with the Licensed
+Material:
+
+i. identification of the creator(s) of the Licensed Material and any others
+designated to receive attribution, in any reasonable manner requested by the
+Licensor (including by pseudonym if designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of warranties;
+
+v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
+
+B. indicate if You modified the Licensed Material and retain an indication
+of any previous modifications; and
+
+C. indicate the Licensed Material is licensed under this Public License, and
+include the text of, or the URI or hyperlink to, this Public License.
+
+2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner
+based on the medium, means, and context in which You Share the Licensed Material.
+For example, it may be reasonable to satisfy the conditions by providing a
+URI or hyperlink to a resource that includes the required information.
+
+3. If requested by the Licensor, You must remove any of the information required
+by Section 3(a)(1)(A) to the extent reasonably practicable.
+
+4. If You Share Adapted Material You produce, the Adapter's License You apply
+must not prevent recipients of the Adapted Material from complying with this
+Public License.
+
+Section 4 – Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that apply to
+Your use of the Licensed Material:
+
+a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract,
+reuse, reproduce, and Share all or a substantial portion of the contents of
+the database;
+
+b. if You include all or a substantial portion of the database contents in
+a database in which You have Sui Generis Database Rights, then the database
+in which You have Sui Generis Database Rights (but not its individual contents)
+is Adapted Material; and
+
+c. You must comply with the conditions in Section 3(a) if You Share all or
+a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not replace
+Your obligations under this Public License where the Licensed Rights include
+other Copyright and Similar Rights.
+
+Section 5 – Disclaimer of Warranties and Limitation of Liability.
+
+a. Unless otherwise separately undertaken by the Licensor, to the extent possible,
+the Licensor offers the Licensed Material as-is and as-available, and makes
+no representations or warranties of any kind concerning the Licensed Material,
+whether express, implied, statutory, or other. This includes, without limitation,
+warranties of title, merchantability, fitness for a particular purpose, non-infringement,
+absence of latent or other defects, accuracy, or the presence or absence of
+errors, whether or not known or discoverable. Where disclaimers of warranties
+are not allowed in full or in part, this disclaimer may not apply to You.
+
+b. To the extent possible, in no event will the Licensor be liable to You
+on any legal theory (including, without limitation, negligence) or otherwise
+for any direct, special, indirect, incidental, consequential, punitive, exemplary,
+or other losses, costs, expenses, or damages arising out of this Public License
+or use of the Licensed Material, even if the Licensor has been advised of
+the possibility of such losses, costs, expenses, or damages. Where a limitation
+of liability is not allowed in full or in part, this limitation may not apply
+to You.
+
+c. The disclaimer of warranties and limitation of liability provided above
+shall be interpreted in a manner that, to the extent possible, most closely
+approximates an absolute disclaimer and waiver of all liability.
+
+Section 6 – Term and Termination.
+
+a. This Public License applies for the term of the Copyright and Similar Rights
+licensed here. However, if You fail to comply with this Public License, then
+Your rights under this Public License terminate automatically.
+
+b. Where Your right to use the Licensed Material has terminated under Section
+6(a), it reinstates:
+
+1. automatically as of the date the violation is cured, provided it is cured
+within 30 days of Your discovery of the violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+c. For the avoidance of doubt, this Section 6(b) does not affect any right
+the Licensor may have to seek remedies for Your violations of this Public
+License.
+
+d. For the avoidance of doubt, the Licensor may also offer the Licensed Material
+under separate terms or conditions or stop distributing the Licensed Material
+at any time; however, doing so will not terminate this Public License.
+
+ e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
+
+Section 7 – Other Terms and Conditions.
+
+a. The Licensor shall not be bound by any additional or different terms or
+conditions communicated by You unless expressly agreed.
+
+b. Any arrangements, understandings, or agreements regarding the Licensed
+Material not stated herein are separate from and independent of the terms
+and conditions of this Public License.
+
+Section 8 – Interpretation.
+
+a. For the avoidance of doubt, this Public License does not, and shall not
+be interpreted to, reduce, limit, restrict, or impose conditions on any use
+of the Licensed Material that could lawfully be made without permission under
+this Public License.
+
+b. To the extent possible, if any provision of this Public License is deemed
+unenforceable, it shall be automatically reformed to the minimum extent necessary
+to make it enforceable. If the provision cannot be reformed, it shall be severed
+from this Public License without affecting the enforceability of the remaining
+terms and conditions.
+
+c. No term or condition of this Public License will be waived and no failure
+to comply consented to unless expressly agreed to by the Licensor.
+
+d. Nothing in this Public License constitutes or may be interpreted as a limitation
+upon, or waiver of, any privileges and immunities that apply to the Licensor
+or You, including from the legal processes of any jurisdiction or authority.
+
+Creative Commons is not a party to its public licenses. Notwithstanding, Creative
+Commons may elect to apply one of its public licenses to material it publishes
+and in those instances will be considered the "Licensor." The text of the
+Creative Commons public licenses is dedicated to the public domain under the
+CC0 Public Domain Dedication. Except for the limited purpose of indicating
+that material is shared under a Creative Commons public license or as otherwise
+permitted by the Creative Commons policies published at creativecommons.org/policies,
+Creative Commons does not authorize the use of the trademark "Creative Commons"
+or any other trademark or logo of Creative Commons without its prior written
+consent including, without limitation, in connection with any unauthorized
+modifications to any of its public licenses or any other arrangements, understandings,
+or agreements concerning use of licensed material. For the avoidance of doubt,
+this paragraph does not form part of the public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/MIT.txt b/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/MIT.txt
new file mode 100644
index 0000000..204b93d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/MIT.txt
@@ -0,0 +1,19 @@
+MIT License Copyright (c) <year> <copyright holders>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/Unlicense.txt b/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/Unlicense.txt
new file mode 100644
index 0000000..24a8f90
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/LICENSES/Unlicense.txt
@@ -0,0 +1,20 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute
+this software, either in source code form or as a compiled binary, for any
+purpose, commercial or non-commercial, and by any means.
+
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and
+to the detriment of our heirs and successors. We intend this dedication to
+be an overt act of relinquishment in perpetuity of all present and future
+rights to this software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information,
+please refer to <https://unlicense.org/>
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/README.rst b/circuitpython/frozen/Adafruit_CircuitPython_HID/README.rst
new file mode 100644
index 0000000..1c5780f
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/README.rst
@@ -0,0 +1,160 @@
+
+Introduction
+============
+
+.. image:: https://readthedocs.org/projects/adafruit-circuitpython-hid/badge/?version=latest
+ :target: https://docs.circuitpython.org/projects/hid/en/latest/
+ :alt: Documentation Status
+
+.. image :: https://img.shields.io/discord/327254708534116352.svg
+ :target: https://adafru.it/discord
+ :alt: Discord
+
+.. image:: https://github.com/adafruit/Adafruit_CircuitPython_HID/workflows/Build%20CI/badge.svg
+ :target: https://github.com/adafruit/Adafruit_CircuitPython_HID/actions/
+ :alt: Build Status
+
+
+This driver simulates USB HID devices. Currently keyboard and mouse are implemented.
+
+Dependencies
+=============
+This driver depends on:
+
+* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
+
+Please ensure all dependencies are available on the CircuitPython filesystem.
+This is easily achieved by downloading
+`the Adafruit library and driver bundle <https://github.com/adafruit/Adafruit_CircuitPython_Bundle>`_.
+
+Additional Layouts
+====================
+This library has an en-US layout. Please check out and expand `the library from Neradoc <https://github.com/Neradoc/Circuitpython_Keyboard_Layouts>`_ for additional layouts.
+
+Usage Example
+=============
+
+The ``Keyboard`` class sends keypress reports for a USB keyboard device to the host.
+
+The ``Keycode`` class defines USB HID keycodes to send using ``Keyboard``.
+
+.. code-block:: python
+
+ import usb_hid
+ from adafruit_hid.keyboard import Keyboard
+ from adafruit_hid.keycode import Keycode
+
+ # Set up a keyboard device.
+ kbd = Keyboard(usb_hid.devices)
+
+ # Type lowercase 'a'. Presses the 'a' key and releases it.
+ kbd.send(Keycode.A)
+
+ # Type capital 'A'.
+ kbd.send(Keycode.SHIFT, Keycode.A)
+
+ # Type control-x.
+ kbd.send(Keycode.CONTROL, Keycode.X)
+
+ # You can also control press and release actions separately.
+ kbd.press(Keycode.CONTROL, Keycode.X)
+ kbd.release_all()
+
+ # Press and hold the shifted '1' key to get '!' (exclamation mark).
+ kbd.press(Keycode.SHIFT, Keycode.ONE)
+ # Release the ONE key and send another report.
+ kbd.release(Keycode.ONE)
+ # Press shifted '2' to get '@'.
+ kbd.press(Keycode.TWO)
+ # Release all keys.
+ kbd.release_all()
+
+The ``KeyboardLayoutUS`` sends ASCII characters using keypresses. It assumes
+the host is set to accept keypresses from a US keyboard.
+
+If the host is expecting a non-US keyboard, the character to key mapping provided by
+``KeyboardLayoutUS`` will not always be correct.
+Different keypresses will be needed in some cases. For instance, to type an ``'A'`` on
+a French keyboard (AZERTY instead of QWERTY), ``Keycode.Q`` should be pressed.
+
+Currently this package provides only ``KeyboardLayoutUS``. More ``KeyboardLayout``
+classes could be added to handle non-US keyboards and the different input methods provided
+by various operating systems.
+
+.. code-block:: python
+
+ import usb_hid
+ from adafruit_hid.keyboard import Keyboard
+ from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
+
+ kbd = Keyboard(usb_hid.devices)
+ layout = KeyboardLayoutUS(kbd)
+
+ # Type 'abc' followed by Enter (a newline).
+ layout.write('abc\n')
+
+ # Get the keycodes needed to type a '$'.
+ # The method will return (Keycode.SHIFT, Keycode.FOUR).
+ keycodes = layout.keycodes('$')
+
+The ``Mouse`` class simulates a three-button mouse with a scroll wheel.
+
+.. code-block:: python
+
+ import usb_hid
+ from adafruit_hid.mouse import Mouse
+
+ m = Mouse(usb_hid.devices)
+
+ # Click the left mouse button.
+ m.click(Mouse.LEFT_BUTTON)
+
+ # Move the mouse diagonally to the upper left.
+ m.move(-100, -100, 0)
+
+ # Roll the mouse wheel away from the user one unit.
+ # Amount scrolled depends on the host.
+ m.move(0, 0, -1)
+
+ # Keyword arguments may also be used. Omitted arguments default to 0.
+ m.move(x=-100, y=-100)
+ m.move(wheel=-1)
+
+ # Move the mouse while holding down the left button. (click-drag).
+ m.press(Mouse.LEFT_BUTTON)
+ m.move(x=50, y=20)
+ m.release_all() # or m.release(Mouse.LEFT_BUTTON)
+
+The ``ConsumerControl`` class emulates consumer control devices such as
+remote controls, or the multimedia keys on certain keyboards.
+
+.. code-block:: python
+
+ import usb_hid
+ from adafruit_hid.consumer_control import ConsumerControl
+ from adafruit_hid.consumer_control_code import ConsumerControlCode
+
+ cc = ConsumerControl(usb_hid.devices)
+
+ # Raise volume.
+ cc.send(ConsumerControlCode.VOLUME_INCREMENT)
+
+ # Pause or resume playback.
+ cc.send(ConsumerControlCode.PLAY_PAUSE)
+
+Documentation
+=============
+
+API documentation for this library can be found on `Read the Docs <https://docs.circuitpython.org/projects/hid/en/latest/>`_.
+
+Contributing
+============
+
+Contributions are welcome! Please read our `Code of Conduct
+<https://github.com/adafruit/Adafruit_CircuitPython_hid/blob/main/CODE_OF_CONDUCT.md>`_
+before contributing to help this project stay welcoming.
+
+Documentation
+=============
+
+For information on building library documentation, please check out `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/README.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_HID/README.rst.license
new file mode 100644
index 0000000..11cd75d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/README.rst.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
+
+SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/__init__.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/__init__.py
new file mode 100644
index 0000000..518817d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/__init__.py
@@ -0,0 +1,45 @@
+# SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid`
+====================================================
+
+This driver simulates USB HID devices.
+
+* Author(s): Scott Shawcroft, Dan Halbert
+
+Implementation Notes
+--------------------
+**Software and Dependencies:**
+* Adafruit CircuitPython firmware for the supported boards:
+ https://github.com/adafruit/circuitpython/releases
+"""
+
+# imports
+try:
+ from typing import Sequence
+ import usb_hid
+except ImportError:
+ pass
+
+__version__ = "0.0.0-auto.0"
+__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_HID.git"
+
+
+def find_device(
+ devices: Sequence[usb_hid.Device], *, usage_page: int, usage: int
+) -> usb_hid.Device:
+ """Search through the provided sequence of devices to find the one with the matching
+ usage_page and usage."""
+ if hasattr(devices, "send_report"):
+ devices = [devices]
+ for device in devices:
+ if (
+ device.usage_page == usage_page
+ and device.usage == usage
+ and hasattr(device, "send_report")
+ ):
+ return device
+ raise ValueError("Could not find matching HID device.")
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control.py
new file mode 100644
index 0000000..d26f116
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control.py
@@ -0,0 +1,106 @@
+# SPDX-FileCopyrightText: 2018 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.consumer_control.ConsumerControl`
+====================================================
+
+* Author(s): Dan Halbert
+"""
+
+import sys
+
+if sys.implementation.version[0] < 3:
+ raise ImportError(
+ "{0} is not supported in CircuitPython 2.x or lower".format(__name__)
+ )
+
+# pylint: disable=wrong-import-position
+import struct
+import time
+from . import find_device
+
+try:
+ from typing import Sequence
+ import usb_hid
+except ImportError:
+ pass
+
+
+class ConsumerControl:
+ """Send ConsumerControl code reports, used by multimedia keyboards, remote controls, etc."""
+
+ def __init__(self, devices: Sequence[usb_hid.Device]) -> None:
+ """Create a ConsumerControl object that will send Consumer Control Device HID reports.
+
+ Devices can be a sequence of devices that includes a Consumer Control device or a CC device
+ itself. A device is any object that implements ``send_report()``, ``usage_page`` and
+ ``usage``.
+ """
+ self._consumer_device = find_device(devices, usage_page=0x0C, usage=0x01)
+
+ # Reuse this bytearray to send consumer reports.
+ self._report = bytearray(2)
+
+ # Do a no-op to test if HID device is ready.
+ # If not, wait a bit and try once more.
+ try:
+ self.send(0x0)
+ except OSError:
+ time.sleep(1)
+ self.send(0x0)
+
+ def send(self, consumer_code: int) -> None:
+ """Send a report to do the specified consumer control action,
+ and then stop the action (so it will not repeat).
+
+ :param consumer_code: a 16-bit consumer control code.
+
+ Examples::
+
+ from adafruit_hid.consumer_control_code import ConsumerControlCode
+
+ # Raise volume.
+ consumer_control.send(ConsumerControlCode.VOLUME_INCREMENT)
+
+ # Advance to next track (song).
+ consumer_control.send(ConsumerControlCode.SCAN_NEXT_TRACK)
+ """
+ self.press(consumer_code)
+ self.release()
+
+ def press(self, consumer_code: int) -> None:
+ """Send a report to indicate that the given key has been pressed.
+ Only one consumer control action can be pressed at a time, so any one
+ that was previously pressed will be released.
+
+ :param consumer_code: a 16-bit consumer control code.
+
+ Examples::
+
+ from adafruit_hid.consumer_control_code import ConsumerControlCode
+
+ # Raise volume for 0.5 seconds
+ consumer_control.press(ConsumerControlCode.VOLUME_INCREMENT)
+ time.sleep(0.5)
+ consumer_control.release()
+ """
+ struct.pack_into("<H", self._report, 0, consumer_code)
+ self._consumer_device.send_report(self._report)
+
+ def release(self) -> None:
+ """Send a report indicating that the consumer control key has been
+ released. Only one consumer control key can be pressed at a time.
+
+ Examples::
+
+ from adafruit_hid.consumer_control_code import ConsumerControlCode
+
+ # Raise volume for 0.5 seconds
+ consumer_control.press(ConsumerControlCode.VOLUME_INCREMENT)
+ time.sleep(0.5)
+ consumer_control.release()
+ """
+ self._report[0] = self._report[1] = 0x0
+ self._consumer_device.send_report(self._report)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control_code.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control_code.py
new file mode 100644
index 0000000..e49137e
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control_code.py
@@ -0,0 +1,47 @@
+# SPDX-FileCopyrightText: 2018 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.consumer_control_code.ConsumerControlCode`
+========================================================
+
+* Author(s): Dan Halbert
+"""
+
+
+class ConsumerControlCode:
+ """USB HID Consumer Control Device constants.
+
+ This list includes a few common consumer control codes from
+ https://www.usb.org/sites/default/files/hut1_21_0.pdf#page=118.
+ """
+
+ # pylint: disable-msg=too-few-public-methods
+
+ RECORD = 0xB2
+ """Record"""
+ FAST_FORWARD = 0xB3
+ """Fast Forward"""
+ REWIND = 0xB4
+ """Rewind"""
+ SCAN_NEXT_TRACK = 0xB5
+ """Skip to next track"""
+ SCAN_PREVIOUS_TRACK = 0xB6
+ """Go back to previous track"""
+ STOP = 0xB7
+ """Stop"""
+ EJECT = 0xB8
+ """Eject"""
+ PLAY_PAUSE = 0xCD
+ """Play/Pause toggle"""
+ MUTE = 0xE2
+ """Mute"""
+ VOLUME_DECREMENT = 0xEA
+ """Decrease volume"""
+ VOLUME_INCREMENT = 0xE9
+ """Increase volume"""
+ BRIGHTNESS_DECREMENT = 0x70
+ """Decrease Brightness"""
+ BRIGHTNESS_INCREMENT = 0x6F
+ """Increase Brightness"""
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard.py
new file mode 100644
index 0000000..f1240c3
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard.py
@@ -0,0 +1,189 @@
+# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.keyboard.Keyboard`
+====================================================
+
+* Author(s): Scott Shawcroft, Dan Halbert
+"""
+
+import time
+from micropython import const
+
+from .keycode import Keycode
+
+from . import find_device
+
+try:
+ from typing import Sequence
+ import usb_hid
+except ImportError:
+ pass
+
+_MAX_KEYPRESSES = const(6)
+
+
+class Keyboard:
+ """Send HID keyboard reports."""
+
+ LED_NUM_LOCK = 0x01
+ """LED Usage ID for Num Lock"""
+ LED_CAPS_LOCK = 0x02
+ """LED Usage ID for Caps Lock"""
+ LED_SCROLL_LOCK = 0x04
+ """LED Usage ID for Scroll Lock"""
+ LED_COMPOSE = 0x08
+ """LED Usage ID for Compose"""
+
+ # No more than _MAX_KEYPRESSES regular keys may be pressed at once.
+
+ def __init__(self, devices: Sequence[usb_hid.Device]) -> None:
+ """Create a Keyboard object that will send keyboard HID reports.
+
+ Devices can be a sequence of devices that includes a keyboard device or a keyboard device
+ itself. A device is any object that implements ``send_report()``, ``usage_page`` and
+ ``usage``.
+ """
+ self._keyboard_device = find_device(devices, usage_page=0x1, usage=0x06)
+
+ # Reuse this bytearray to send keyboard reports.
+ self.report = bytearray(8)
+
+ # report[0] modifiers
+ # report[1] unused
+ # report[2:8] regular key presses
+
+ # View onto byte 0 in report.
+ self.report_modifier = memoryview(self.report)[0:1]
+
+ # List of regular keys currently pressed.
+ # View onto bytes 2-7 in report.
+ self.report_keys = memoryview(self.report)[2:]
+
+ # Do a no-op to test if HID device is ready.
+ # If not, wait a bit and try once more.
+ try:
+ self.release_all()
+ except OSError:
+ time.sleep(1)
+ self.release_all()
+
+ def press(self, *keycodes: int) -> None:
+ """Send a report indicating that the given keys have been pressed.
+
+ :param keycodes: Press these keycodes all at once.
+ :raises ValueError: if more than six regular keys are pressed.
+
+ Keycodes may be modifiers or regular keys.
+ No more than six regular keys may be pressed simultaneously.
+
+ Examples::
+
+ from adafruit_hid.keycode import Keycode
+
+ # Press ctrl-x.
+ kbd.press(Keycode.LEFT_CONTROL, Keycode.X)
+
+ # Or, more conveniently, use the CONTROL alias for LEFT_CONTROL:
+ kbd.press(Keycode.CONTROL, Keycode.X)
+
+ # Press a, b, c keys all at once.
+ kbd.press(Keycode.A, Keycode.B, Keycode.C)
+ """
+ for keycode in keycodes:
+ self._add_keycode_to_report(keycode)
+ self._keyboard_device.send_report(self.report)
+
+ def release(self, *keycodes: int) -> None:
+ """Send a USB HID report indicating that the given keys have been released.
+
+ :param keycodes: Release these keycodes all at once.
+
+ If a keycode to be released was not pressed, it is ignored.
+
+ Example::
+
+ # release SHIFT key
+ kbd.release(Keycode.SHIFT)
+ """
+ for keycode in keycodes:
+ self._remove_keycode_from_report(keycode)
+ self._keyboard_device.send_report(self.report)
+
+ def release_all(self) -> None:
+ """Release all pressed keys."""
+ for i in range(8):
+ self.report[i] = 0
+ self._keyboard_device.send_report(self.report)
+
+ def send(self, *keycodes: int) -> None:
+ """Press the given keycodes and then release all pressed keys.
+
+ :param keycodes: keycodes to send together
+ """
+ self.press(*keycodes)
+ self.release_all()
+
+ def _add_keycode_to_report(self, keycode: int) -> None:
+ """Add a single keycode to the USB HID report."""
+ modifier = Keycode.modifier_bit(keycode)
+ if modifier:
+ # Set bit for this modifier.
+ self.report_modifier[0] |= modifier
+ else:
+ # Don't press twice.
+ # (I'd like to use 'not in self.report_keys' here, but that's not implemented.)
+ for i in range(_MAX_KEYPRESSES):
+ if self.report_keys[i] == keycode:
+ # Already pressed.
+ return
+ # Put keycode in first empty slot.
+ for i in range(_MAX_KEYPRESSES):
+ if self.report_keys[i] == 0:
+ self.report_keys[i] = keycode
+ return
+ # All slots are filled.
+ raise ValueError("Trying to press more than six keys at once.")
+
+ def _remove_keycode_from_report(self, keycode: int) -> None:
+ """Remove a single keycode from the report."""
+ modifier = Keycode.modifier_bit(keycode)
+ if modifier:
+ # Turn off the bit for this modifier.
+ self.report_modifier[0] &= ~modifier
+ else:
+ # Check all the slots, just in case there's a duplicate. (There should not be.)
+ for i in range(_MAX_KEYPRESSES):
+ if self.report_keys[i] == keycode:
+ self.report_keys[i] = 0
+
+ @property
+ def led_status(self) -> bytes:
+ """Returns the last received report"""
+ return self._keyboard_device.last_received_report
+
+ def led_on(self, led_code: int) -> bool:
+ """Returns whether an LED is on based on the led code
+
+ Examples::
+
+ import usb_hid
+ from adafruit_hid.keyboard import Keyboard
+ from adafruit_hid.keycode import Keycode
+ import time
+
+ # Initialize Keybaord
+ kbd = Keyboard(usb_hid.devices)
+
+ # Press and release CapsLock.
+ kbd.press(Keycode.CAPS_LOCK)
+ time.sleep(.09)
+ kbd.release(Keycode.CAPS_LOCK)
+
+ # Check status of the LED_CAPS_LOCK
+ print(kbd.led_on(Keyboard.LED_CAPS_LOCK))
+
+ """
+ return bool(self.led_status[0] & led_code)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_base.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_base.py
new file mode 100755
index 0000000..54de33d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_base.py
@@ -0,0 +1,186 @@
+# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.keyboard_layout_base.KeyboardLayoutBase`
+=======================================================
+
+* Author(s): Dan Halbert, AngainorDev, Neradoc
+"""
+
+
+try:
+ from typing import Tuple
+ from .keyboard import Keyboard
+except ImportError:
+ pass
+
+
+__version__ = "0.0.0-auto.0"
+__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_HID.git"
+
+
+class KeyboardLayoutBase:
+ """Base class for keyboard layouts. Uses the tables defined in the subclass
+ to map UTF-8 characters to appropriate keypresses.
+
+ Non-supported characters and most control characters will raise an exception.
+ """
+
+ SHIFT_FLAG = 0x80
+ """Bit set in any keycode byte if the shift key is required for the character."""
+ ALTGR_FLAG = 0x80
+ """Bit set in the combined keys table if altgr is required for the first key."""
+ SHIFT_CODE = 0xE1
+ """The SHIFT keycode, to avoid dependency to the Keycode class."""
+ RIGHT_ALT_CODE = 0xE6
+ """The ALTGR keycode, to avoid dependency to the Keycode class."""
+ ASCII_TO_KEYCODE = ()
+ """Bytes string of keycodes for low ASCII characters, indexed by the ASCII value.
+ Keycodes use the `SHIFT_FLAG` if needed.
+ Dead keys are excluded by assigning the keycode 0."""
+ HIGHER_ASCII = {}
+ """Dictionary that associates the ord() int value of high ascii and utf8 characters
+ to their keycode. Keycodes use the `SHIFT_FLAG` if needed."""
+ NEED_ALTGR = ""
+ """Characters in `ASCII_TO_KEYCODE` and `HIGHER_ASCII` that need
+ the ALTGR key pressed to type."""
+ COMBINED_KEYS = {}
+ """
+ Dictionary of characters (indexed by ord() value) that can be accessed by typing first
+ a dead key followed by a regular key, like ``ñ`` as ``~ + n``. The value is a 2-bytes int:
+ the high byte is the dead-key keycode (including SHIFT_FLAG), the low byte is the ascii code
+ of the second character, with ALTGR_FLAG set if the dead key (the first key) needs ALTGR.
+
+ The combined-key codes bits are: ``0b SDDD DDDD AKKK KKKK``:
+ ``S`` is the shift flag for the **first** key,
+ ``DDD DDDD`` is the keycode for the **first** key,
+ ``A`` is the altgr flag for the **first** key,
+ ``KKK KKKK`` is the (low) ASCII code for the second character.
+ """
+
+ def __init__(self, keyboard: Keyboard) -> None:
+ """Specify the layout for the given keyboard.
+
+ :param keyboard: a Keyboard object. Write characters to this keyboard when requested.
+
+ Example::
+
+ kbd = Keyboard(usb_hid.devices)
+ layout = KeyboardLayout(kbd)
+ """
+ self.keyboard = keyboard
+
+ def _write(self, keycode: int, altgr: bool = False) -> None:
+ """Type a key combination based on shift bit and altgr bool
+
+ :param keycode: int value of the keycode, with the shift bit.
+ :param altgr: bool indicating if the altgr key should be pressed too.
+ """
+ # Add altgr modifier if needed
+ if altgr:
+ self.keyboard.press(self.RIGHT_ALT_CODE)
+ # If this is a shifted char, clear the SHIFT flag and press the SHIFT key.
+ if keycode & self.SHIFT_FLAG:
+ keycode &= ~self.SHIFT_FLAG
+ self.keyboard.press(self.SHIFT_CODE)
+ self.keyboard.press(keycode)
+ self.keyboard.release_all()
+
+ def write(self, string: str) -> None:
+ """Type the string by pressing and releasing keys on my keyboard.
+
+ :param string: A string of UTF-8 characters to convert to key presses and send.
+ :raises ValueError: if any of the characters has no keycode
+ (such as some control characters).
+
+ Example::
+
+ # Write abc followed by Enter to the keyboard
+ layout.write('abc\\n')
+ """
+ for char in string:
+ # find easy ones first
+ keycode = self._char_to_keycode(char)
+ if keycode > 0:
+ self._write(keycode, char in self.NEED_ALTGR)
+ # find combined keys
+ elif ord(char) in self.COMBINED_KEYS:
+ # first key (including shift bit)
+ cchar = self.COMBINED_KEYS[ord(char)]
+ self._write(cchar >> 8, cchar & self.ALTGR_FLAG)
+ # second key (removing the altgr bit)
+ char = chr(cchar & 0xFF & (~self.ALTGR_FLAG))
+ keycode = self._char_to_keycode(char)
+ # assume no altgr needed for second key
+ self._write(keycode, False)
+ else:
+ raise ValueError(
+ "No keycode available for character {letter} ({num}/0x{num:02x}).".format(
+ letter=repr(char), num=ord(char)
+ )
+ )
+
+ def keycodes(self, char: str) -> Tuple[int, ...]:
+ """Return a tuple of keycodes needed to type the given character.
+
+ :param char: A single UTF8 character in a string.
+ :type char: str of length one.
+ :returns: tuple of Keycode keycodes.
+ :raises ValueError: if there is no keycode for ``char``.
+
+ Examples::
+
+ # Returns (Keycode.TAB,)
+ keycodes('\t')
+ # Returns (Keycode.A,)
+ keycode('a')
+ # Returns (Keycode.SHIFT, Keycode.A)
+ keycode('A')
+ # Raises ValueError with a US layout because it's an unknown character
+ keycode('é')
+ """
+ keycode = self._char_to_keycode(char)
+ if keycode == 0:
+ raise ValueError(
+ "No keycode available for character {letter} ({num}/0x{num:02x}).".format(
+ letter=repr(char), num=ord(char)
+ )
+ )
+
+ codes = []
+ if char in self.NEED_ALTGR:
+ codes.append(self.RIGHT_ALT_CODE)
+ if keycode & self.SHIFT_FLAG:
+ codes.extend((self.SHIFT_CODE, keycode & ~self.SHIFT_FLAG))
+ else:
+ codes.append(keycode)
+
+ return codes
+
+ def _above128char_to_keycode(self, char: str) -> int:
+ """Return keycode for above 128 utf8 codes.
+
+ A character can be indexed by the char itself or its int ord() value.
+
+ :param char_val: char value
+ :return: keycode, with modifiers if needed
+ """
+ if ord(char) in self.HIGHER_ASCII:
+ return self.HIGHER_ASCII[ord(char)]
+ if char in self.HIGHER_ASCII:
+ return self.HIGHER_ASCII[char]
+ return 0
+
+ def _char_to_keycode(self, char: str) -> int:
+ """Return the HID keycode for the given character, with the SHIFT_FLAG possibly set.
+
+ If the character requires pressing the Shift key, the SHIFT_FLAG bit is set.
+ You must clear this bit before passing the keycode in a USB report.
+ """
+ char_val = ord(char)
+ if char_val > len(self.ASCII_TO_KEYCODE):
+ return self._above128char_to_keycode(char)
+ keycode = self.ASCII_TO_KEYCODE[char_val]
+ return keycode
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_us.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_us.py
new file mode 100755
index 0000000..35b163b
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_us.py
@@ -0,0 +1,166 @@
+# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.keyboard_layout_us.KeyboardLayoutUS`
+=======================================================
+
+* Author(s): Dan Halbert
+"""
+
+from .keyboard_layout_base import KeyboardLayoutBase
+
+
+class KeyboardLayoutUS(KeyboardLayoutBase):
+ """Map ASCII characters to appropriate keypresses on a standard US PC keyboard.
+
+ Non-ASCII characters and most control characters will raise an exception.
+ """
+
+ # The ASCII_TO_KEYCODE bytes object is used as a table to maps ASCII 0-127
+ # to the corresponding # keycode on a US 104-key keyboard.
+ # The user should not normally need to use this table,
+ # but it is not marked as private.
+ #
+ # Because the table only goes to 127, we use the top bit of each byte (ox80) to indicate
+ # that the shift key should be pressed. So any values 0x{8,9,a,b}* are shifted characters.
+ #
+ # The Python compiler will concatenate all these bytes literals into a single bytes object.
+ # Micropython/CircuitPython will store the resulting bytes constant in flash memory
+ # if it's in a .mpy file, so it doesn't use up valuable RAM.
+ #
+ # \x00 entries have no keyboard key and so won't be sent.
+ ASCII_TO_KEYCODE = (
+ b"\x00" # NUL
+ b"\x00" # SOH
+ b"\x00" # STX
+ b"\x00" # ETX
+ b"\x00" # EOT
+ b"\x00" # ENQ
+ b"\x00" # ACK
+ b"\x00" # BEL \a
+ b"\x2a" # BS BACKSPACE \b (called DELETE in the usb.org document)
+ b"\x2b" # TAB \t
+ b"\x28" # LF \n (called Return or ENTER in the usb.org document)
+ b"\x00" # VT \v
+ b"\x00" # FF \f
+ b"\x00" # CR \r
+ b"\x00" # SO
+ b"\x00" # SI
+ b"\x00" # DLE
+ b"\x00" # DC1
+ b"\x00" # DC2
+ b"\x00" # DC3
+ b"\x00" # DC4
+ b"\x00" # NAK
+ b"\x00" # SYN
+ b"\x00" # ETB
+ b"\x00" # CAN
+ b"\x00" # EM
+ b"\x00" # SUB
+ b"\x29" # ESC
+ b"\x00" # FS
+ b"\x00" # GS
+ b"\x00" # RS
+ b"\x00" # US
+ b"\x2c" # SPACE
+ b"\x9e" # ! x1e|SHIFT_FLAG (shift 1)
+ b"\xb4" # " x34|SHIFT_FLAG (shift ')
+ b"\xa0" # # x20|SHIFT_FLAG (shift 3)
+ b"\xa1" # $ x21|SHIFT_FLAG (shift 4)
+ b"\xa2" # % x22|SHIFT_FLAG (shift 5)
+ b"\xa4" # & x24|SHIFT_FLAG (shift 7)
+ b"\x34" # '
+ b"\xa6" # ( x26|SHIFT_FLAG (shift 9)
+ b"\xa7" # ) x27|SHIFT_FLAG (shift 0)
+ b"\xa5" # * x25|SHIFT_FLAG (shift 8)
+ b"\xae" # + x2e|SHIFT_FLAG (shift =)
+ b"\x36" # ,
+ b"\x2d" # -
+ b"\x37" # .
+ b"\x38" # /
+ b"\x27" # 0
+ b"\x1e" # 1
+ b"\x1f" # 2
+ b"\x20" # 3
+ b"\x21" # 4
+ b"\x22" # 5
+ b"\x23" # 6
+ b"\x24" # 7
+ b"\x25" # 8
+ b"\x26" # 9
+ b"\xb3" # : x33|SHIFT_FLAG (shift ;)
+ b"\x33" # ;
+ b"\xb6" # < x36|SHIFT_FLAG (shift ,)
+ b"\x2e" # =
+ b"\xb7" # > x37|SHIFT_FLAG (shift .)
+ b"\xb8" # ? x38|SHIFT_FLAG (shift /)
+ b"\x9f" # @ x1f|SHIFT_FLAG (shift 2)
+ b"\x84" # A x04|SHIFT_FLAG (shift a)
+ b"\x85" # B x05|SHIFT_FLAG (etc.)
+ b"\x86" # C x06|SHIFT_FLAG
+ b"\x87" # D x07|SHIFT_FLAG
+ b"\x88" # E x08|SHIFT_FLAG
+ b"\x89" # F x09|SHIFT_FLAG
+ b"\x8a" # G x0a|SHIFT_FLAG
+ b"\x8b" # H x0b|SHIFT_FLAG
+ b"\x8c" # I x0c|SHIFT_FLAG
+ b"\x8d" # J x0d|SHIFT_FLAG
+ b"\x8e" # K x0e|SHIFT_FLAG
+ b"\x8f" # L x0f|SHIFT_FLAG
+ b"\x90" # M x10|SHIFT_FLAG
+ b"\x91" # N x11|SHIFT_FLAG
+ b"\x92" # O x12|SHIFT_FLAG
+ b"\x93" # P x13|SHIFT_FLAG
+ b"\x94" # Q x14|SHIFT_FLAG
+ b"\x95" # R x15|SHIFT_FLAG
+ b"\x96" # S x16|SHIFT_FLAG
+ b"\x97" # T x17|SHIFT_FLAG
+ b"\x98" # U x18|SHIFT_FLAG
+ b"\x99" # V x19|SHIFT_FLAG
+ b"\x9a" # W x1a|SHIFT_FLAG
+ b"\x9b" # X x1b|SHIFT_FLAG
+ b"\x9c" # Y x1c|SHIFT_FLAG
+ b"\x9d" # Z x1d|SHIFT_FLAG
+ b"\x2f" # [
+ b"\x31" # \ backslash
+ b"\x30" # ]
+ b"\xa3" # ^ x23|SHIFT_FLAG (shift 6)
+ b"\xad" # _ x2d|SHIFT_FLAG (shift -)
+ b"\x35" # `
+ b"\x04" # a
+ b"\x05" # b
+ b"\x06" # c
+ b"\x07" # d
+ b"\x08" # e
+ b"\x09" # f
+ b"\x0a" # g
+ b"\x0b" # h
+ b"\x0c" # i
+ b"\x0d" # j
+ b"\x0e" # k
+ b"\x0f" # l
+ b"\x10" # m
+ b"\x11" # n
+ b"\x12" # o
+ b"\x13" # p
+ b"\x14" # q
+ b"\x15" # r
+ b"\x16" # s
+ b"\x17" # t
+ b"\x18" # u
+ b"\x19" # v
+ b"\x1a" # w
+ b"\x1b" # x
+ b"\x1c" # y
+ b"\x1d" # z
+ b"\xaf" # { x2f|SHIFT_FLAG (shift [)
+ b"\xb1" # | x31|SHIFT_FLAG (shift \)
+ b"\xb0" # } x30|SHIFT_FLAG (shift ])
+ b"\xb5" # ~ x35|SHIFT_FLAG (shift `)
+ b"\x4c" # DEL DELETE (called Forward Delete in usb.org document)
+ )
+
+
+KeyboardLayout = KeyboardLayoutUS
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keycode.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keycode.py
new file mode 100644
index 0000000..14c8aa1
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keycode.py
@@ -0,0 +1,312 @@
+# SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.keycode.Keycode`
+====================================================
+
+* Author(s): Scott Shawcroft, Dan Halbert
+"""
+
+try:
+ import typing # pylint: disable=unused-import
+except ImportError:
+ pass
+
+
+class Keycode:
+ """USB HID Keycode constants.
+
+ This list is modeled after the names for USB keycodes defined in
+ https://usb.org/sites/default/files/hut1_21_0.pdf#page=83.
+ This list does not include every single code, but does include all the keys on
+ a regular PC or Mac keyboard.
+
+ Remember that keycodes are the names for key *positions* on a US keyboard, and may
+ not correspond to the character that you mean to send if you want to emulate non-US keyboard.
+ For instance, on a French keyboard (AZERTY instead of QWERTY),
+ the keycode for 'q' is used to indicate an 'a'. Likewise, 'y' represents 'z' on
+ a German keyboard. This is historical: the idea was that the keycaps could be changed
+ without changing the keycodes sent, so that different firmware was not needed for
+ different variations of a keyboard.
+ """
+
+ # pylint: disable-msg=invalid-name
+ A = 0x04
+ """``a`` and ``A``"""
+ B = 0x05
+ """``b`` and ``B``"""
+ C = 0x06
+ """``c`` and ``C``"""
+ D = 0x07
+ """``d`` and ``D``"""
+ E = 0x08
+ """``e`` and ``E``"""
+ F = 0x09
+ """``f`` and ``F``"""
+ G = 0x0A
+ """``g`` and ``G``"""
+ H = 0x0B
+ """``h`` and ``H``"""
+ I = 0x0C
+ """``i`` and ``I``"""
+ J = 0x0D
+ """``j`` and ``J``"""
+ K = 0x0E
+ """``k`` and ``K``"""
+ L = 0x0F
+ """``l`` and ``L``"""
+ M = 0x10
+ """``m`` and ``M``"""
+ N = 0x11
+ """``n`` and ``N``"""
+ O = 0x12
+ """``o`` and ``O``"""
+ P = 0x13
+ """``p`` and ``P``"""
+ Q = 0x14
+ """``q`` and ``Q``"""
+ R = 0x15
+ """``r`` and ``R``"""
+ S = 0x16
+ """``s`` and ``S``"""
+ T = 0x17
+ """``t`` and ``T``"""
+ U = 0x18
+ """``u`` and ``U``"""
+ V = 0x19
+ """``v`` and ``V``"""
+ W = 0x1A
+ """``w`` and ``W``"""
+ X = 0x1B
+ """``x`` and ``X``"""
+ Y = 0x1C
+ """``y`` and ``Y``"""
+ Z = 0x1D
+ """``z`` and ``Z``"""
+
+ ONE = 0x1E
+ """``1`` and ``!``"""
+ TWO = 0x1F
+ """``2`` and ``@``"""
+ THREE = 0x20
+ """``3`` and ``#``"""
+ FOUR = 0x21
+ """``4`` and ``$``"""
+ FIVE = 0x22
+ """``5`` and ``%``"""
+ SIX = 0x23
+ """``6`` and ``^``"""
+ SEVEN = 0x24
+ """``7`` and ``&``"""
+ EIGHT = 0x25
+ """``8`` and ``*``"""
+ NINE = 0x26
+ """``9`` and ``(``"""
+ ZERO = 0x27
+ """``0`` and ``)``"""
+ ENTER = 0x28
+ """Enter (Return)"""
+ RETURN = ENTER
+ """Alias for ``ENTER``"""
+ ESCAPE = 0x29
+ """Escape"""
+ BACKSPACE = 0x2A
+ """Delete backward (Backspace)"""
+ TAB = 0x2B
+ """Tab and Backtab"""
+ SPACEBAR = 0x2C
+ """Spacebar"""
+ SPACE = SPACEBAR
+ """Alias for SPACEBAR"""
+ MINUS = 0x2D
+ """``-` and ``_``"""
+ EQUALS = 0x2E
+ """``=` and ``+``"""
+ LEFT_BRACKET = 0x2F
+ """``[`` and ``{``"""
+ RIGHT_BRACKET = 0x30
+ """``]`` and ``}``"""
+ BACKSLASH = 0x31
+ r"""``\`` and ``|``"""
+ POUND = 0x32
+ """``#`` and ``~`` (Non-US keyboard)"""
+ SEMICOLON = 0x33
+ """``;`` and ``:``"""
+ QUOTE = 0x34
+ """``'`` and ``"``"""
+ GRAVE_ACCENT = 0x35
+ r""":literal:`\`` and ``~``"""
+ COMMA = 0x36
+ """``,`` and ``<``"""
+ PERIOD = 0x37
+ """``.`` and ``>``"""
+ FORWARD_SLASH = 0x38
+ """``/`` and ``?``"""
+
+ CAPS_LOCK = 0x39
+ """Caps Lock"""
+
+ F1 = 0x3A
+ """Function key F1"""
+ F2 = 0x3B
+ """Function key F2"""
+ F3 = 0x3C
+ """Function key F3"""
+ F4 = 0x3D
+ """Function key F4"""
+ F5 = 0x3E
+ """Function key F5"""
+ F6 = 0x3F
+ """Function key F6"""
+ F7 = 0x40
+ """Function key F7"""
+ F8 = 0x41
+ """Function key F8"""
+ F9 = 0x42
+ """Function key F9"""
+ F10 = 0x43
+ """Function key F10"""
+ F11 = 0x44
+ """Function key F11"""
+ F12 = 0x45
+ """Function key F12"""
+
+ PRINT_SCREEN = 0x46
+ """Print Screen (SysRq)"""
+ SCROLL_LOCK = 0x47
+ """Scroll Lock"""
+ PAUSE = 0x48
+ """Pause (Break)"""
+
+ INSERT = 0x49
+ """Insert"""
+ HOME = 0x4A
+ """Home (often moves to beginning of line)"""
+ PAGE_UP = 0x4B
+ """Go back one page"""
+ DELETE = 0x4C
+ """Delete forward"""
+ END = 0x4D
+ """End (often moves to end of line)"""
+ PAGE_DOWN = 0x4E
+ """Go forward one page"""
+
+ RIGHT_ARROW = 0x4F
+ """Move the cursor right"""
+ LEFT_ARROW = 0x50
+ """Move the cursor left"""
+ DOWN_ARROW = 0x51
+ """Move the cursor down"""
+ UP_ARROW = 0x52
+ """Move the cursor up"""
+
+ KEYPAD_NUMLOCK = 0x53
+ """Num Lock (Clear on Mac)"""
+ KEYPAD_FORWARD_SLASH = 0x54
+ """Keypad ``/``"""
+ KEYPAD_ASTERISK = 0x55
+ """Keypad ``*``"""
+ KEYPAD_MINUS = 0x56
+ """Keyapd ``-``"""
+ KEYPAD_PLUS = 0x57
+ """Keypad ``+``"""
+ KEYPAD_ENTER = 0x58
+ """Keypad Enter"""
+ KEYPAD_ONE = 0x59
+ """Keypad ``1`` and End"""
+ KEYPAD_TWO = 0x5A
+ """Keypad ``2`` and Down Arrow"""
+ KEYPAD_THREE = 0x5B
+ """Keypad ``3`` and PgDn"""
+ KEYPAD_FOUR = 0x5C
+ """Keypad ``4`` and Left Arrow"""
+ KEYPAD_FIVE = 0x5D
+ """Keypad ``5``"""
+ KEYPAD_SIX = 0x5E
+ """Keypad ``6`` and Right Arrow"""
+ KEYPAD_SEVEN = 0x5F
+ """Keypad ``7`` and Home"""
+ KEYPAD_EIGHT = 0x60
+ """Keypad ``8`` and Up Arrow"""
+ KEYPAD_NINE = 0x61
+ """Keypad ``9`` and PgUp"""
+ KEYPAD_ZERO = 0x62
+ """Keypad ``0`` and Ins"""
+ KEYPAD_PERIOD = 0x63
+ """Keypad ``.`` and Del"""
+ KEYPAD_BACKSLASH = 0x64
+ """Keypad ``\\`` and ``|`` (Non-US)"""
+
+ APPLICATION = 0x65
+ """Application: also known as the Menu key (Windows)"""
+ POWER = 0x66
+ """Power (Mac)"""
+ KEYPAD_EQUALS = 0x67
+ """Keypad ``=`` (Mac)"""
+ F13 = 0x68
+ """Function key F13 (Mac)"""
+ F14 = 0x69
+ """Function key F14 (Mac)"""
+ F15 = 0x6A
+ """Function key F15 (Mac)"""
+ F16 = 0x6B
+ """Function key F16 (Mac)"""
+ F17 = 0x6C
+ """Function key F17 (Mac)"""
+ F18 = 0x6D
+ """Function key F18 (Mac)"""
+ F19 = 0x6E
+ """Function key F19 (Mac)"""
+
+ F20 = 0x6F
+ """Function key F20"""
+ F21 = 0x70
+ """Function key F21"""
+ F22 = 0x71
+ """Function key F22"""
+ F23 = 0x72
+ """Function key F23"""
+ F24 = 0x73
+ """Function key F24"""
+
+ LEFT_CONTROL = 0xE0
+ """Control modifier left of the spacebar"""
+ CONTROL = LEFT_CONTROL
+ """Alias for LEFT_CONTROL"""
+ LEFT_SHIFT = 0xE1
+ """Shift modifier left of the spacebar"""
+ SHIFT = LEFT_SHIFT
+ """Alias for LEFT_SHIFT"""
+ LEFT_ALT = 0xE2
+ """Alt modifier left of the spacebar"""
+ ALT = LEFT_ALT
+ """Alias for LEFT_ALT; Alt is also known as Option (Mac)"""
+ OPTION = ALT
+ """Labeled as Option on some Mac keyboards"""
+ LEFT_GUI = 0xE3
+ """GUI modifier left of the spacebar"""
+ GUI = LEFT_GUI
+ """Alias for LEFT_GUI; GUI is also known as the Windows key, Command (Mac), or Meta"""
+ WINDOWS = GUI
+ """Labeled with a Windows logo on Windows keyboards"""
+ COMMAND = GUI
+ """Labeled as Command on Mac keyboards, with a clover glyph"""
+ RIGHT_CONTROL = 0xE4
+ """Control modifier right of the spacebar"""
+ RIGHT_SHIFT = 0xE5
+ """Shift modifier right of the spacebar"""
+ RIGHT_ALT = 0xE6
+ """Alt modifier right of the spacebar"""
+ RIGHT_GUI = 0xE7
+ """GUI modifier right of the spacebar"""
+
+ # pylint: enable-msg=invalid-name
+ @classmethod
+ def modifier_bit(cls, keycode: int) -> int:
+ """Return the modifer bit to be set in an HID keycode report if this is a
+ modifier key; otherwise return 0."""
+ return (
+ 1 << (keycode - 0xE0) if cls.LEFT_CONTROL <= keycode <= cls.RIGHT_GUI else 0
+ )
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/mouse.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/mouse.py
new file mode 100644
index 0000000..3b324db
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/mouse.py
@@ -0,0 +1,152 @@
+# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.mouse.Mouse`
+====================================================
+
+* Author(s): Dan Halbert
+"""
+import time
+
+from . import find_device
+
+try:
+ from typing import Sequence
+ import usb_hid
+except ImportError:
+ pass
+
+
+class Mouse:
+ """Send USB HID mouse reports."""
+
+ LEFT_BUTTON = 1
+ """Left mouse button."""
+ RIGHT_BUTTON = 2
+ """Right mouse button."""
+ MIDDLE_BUTTON = 4
+ """Middle mouse button."""
+
+ def __init__(self, devices: Sequence[usb_hid.Device]):
+ """Create a Mouse object that will send USB mouse HID reports.
+
+ Devices can be a sequence of devices that includes a keyboard device or a keyboard device
+ itself. A device is any object that implements ``send_report()``, ``usage_page`` and
+ ``usage``.
+ """
+ self._mouse_device = find_device(devices, usage_page=0x1, usage=0x02)
+
+ # Reuse this bytearray to send mouse reports.
+ # report[0] buttons pressed (LEFT, MIDDLE, RIGHT)
+ # report[1] x movement
+ # report[2] y movement
+ # report[3] wheel movement
+ self.report = bytearray(4)
+
+ # Do a no-op to test if HID device is ready.
+ # If not, wait a bit and try once more.
+ try:
+ self._send_no_move()
+ except OSError:
+ time.sleep(1)
+ self._send_no_move()
+
+ def press(self, buttons: int) -> None:
+ """Press the given mouse buttons.
+
+ :param buttons: a bitwise-or'd combination of ``LEFT_BUTTON``,
+ ``MIDDLE_BUTTON``, and ``RIGHT_BUTTON``.
+
+ Examples::
+
+ # Press the left button.
+ m.press(Mouse.LEFT_BUTTON)
+
+ # Press the left and right buttons simultaneously.
+ m.press(Mouse.LEFT_BUTTON | Mouse.RIGHT_BUTTON)
+ """
+ self.report[0] |= buttons
+ self._send_no_move()
+
+ def release(self, buttons: int) -> None:
+ """Release the given mouse buttons.
+
+ :param buttons: a bitwise-or'd combination of ``LEFT_BUTTON``,
+ ``MIDDLE_BUTTON``, and ``RIGHT_BUTTON``.
+ """
+ self.report[0] &= ~buttons
+ self._send_no_move()
+
+ def release_all(self) -> None:
+ """Release all the mouse buttons."""
+ self.report[0] = 0
+ self._send_no_move()
+
+ def click(self, buttons: int) -> None:
+ """Press and release the given mouse buttons.
+
+ :param buttons: a bitwise-or'd combination of ``LEFT_BUTTON``,
+ ``MIDDLE_BUTTON``, and ``RIGHT_BUTTON``.
+
+ Examples::
+
+ # Click the left button.
+ m.click(Mouse.LEFT_BUTTON)
+
+ # Double-click the left button.
+ m.click(Mouse.LEFT_BUTTON)
+ m.click(Mouse.LEFT_BUTTON)
+ """
+ self.press(buttons)
+ self.release(buttons)
+
+ def move(self, x: int = 0, y: int = 0, wheel: int = 0) -> None:
+ """Move the mouse and turn the wheel as directed.
+
+ :param x: Move the mouse along the x axis. Negative is to the left, positive
+ is to the right.
+ :param y: Move the mouse along the y axis. Negative is upwards on the display,
+ positive is downwards.
+ :param wheel: Rotate the wheel this amount. Negative is toward the user, positive
+ is away from the user. The scrolling effect depends on the host.
+
+ Examples::
+
+ # Move 100 to the left. Do not move up and down. Do not roll the scroll wheel.
+ m.move(-100, 0, 0)
+ # Same, with keyword arguments.
+ m.move(x=-100)
+
+ # Move diagonally to the upper right.
+ m.move(50, 20)
+ # Same.
+ m.move(x=50, y=-20)
+
+ # Roll the mouse wheel away from the user.
+ m.move(wheel=1)
+ """
+ # Send multiple reports if necessary to move or scroll requested amounts.
+ while x != 0 or y != 0 or wheel != 0:
+ partial_x = self._limit(x)
+ partial_y = self._limit(y)
+ partial_wheel = self._limit(wheel)
+ self.report[1] = partial_x & 0xFF
+ self.report[2] = partial_y & 0xFF
+ self.report[3] = partial_wheel & 0xFF
+ self._mouse_device.send_report(self.report)
+ x -= partial_x
+ y -= partial_y
+ wheel -= partial_wheel
+
+ def _send_no_move(self) -> None:
+ """Send a button-only report."""
+ self.report[1] = 0
+ self.report[2] = 0
+ self.report[3] = 0
+ self._mouse_device.send_report(self.report)
+
+ @staticmethod
+ def _limit(dist: int) -> int:
+ return min(127, max(-127, dist))
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/_static/favicon.ico b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/_static/favicon.ico
new file mode 100644
index 0000000..5aca983
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/_static/favicon.ico
Binary files differ
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/_static/favicon.ico.license b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/_static/favicon.ico.license
new file mode 100644
index 0000000..86a3fbf
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/_static/favicon.ico.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2018 Phillip Torrone for Adafruit Industries
+
+SPDX-License-Identifier: CC-BY-4.0
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/api.rst b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/api.rst
new file mode 100644
index 0000000..03b92bc
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/api.rst
@@ -0,0 +1,23 @@
+
+.. If you created a package, create one automodule per module in the package.
+
+.. automodule:: adafruit_hid.keyboard
+ :members:
+
+.. automodule:: adafruit_hid.keycode
+ :members:
+
+.. automodule:: adafruit_hid.keyboard_layout_us
+ :members:
+
+.. automodule:: adafruit_hid.keyboard_layout_base
+ :members:
+
+.. automodule:: adafruit_hid.mouse
+ :members:
+
+.. automodule:: adafruit_hid.consumer_control
+ :members:
+
+.. automodule:: adafruit_hid.consumer_control_code
+ :members:
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/api.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/api.rst.license
new file mode 100644
index 0000000..9aae48d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/api.rst.license
@@ -0,0 +1,3 @@
+# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/conf.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/conf.py
new file mode 100644
index 0000000..c35d131
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/conf.py
@@ -0,0 +1,176 @@
+# -*- coding: utf-8 -*-
+
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+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.viewcode",
+]
+
+intersphinx_mapping = {
+ "python": ("https://docs.python.org/3", None),
+ "CircuitPython": ("https://docs.circuitpython.org/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 = "Adafruit HID Library"
+copyright = "2017 Scott Shawcroft"
+author = "Scott Shawcroft"
+
+# Ignore imports of these modules, which sphinx will not know about.
+autodoc_mock_imports = ["usb_hid"]
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = "1.0"
+# The full version, including alpha/beta/rc tags.
+release = "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 = True
+
+
+# -- 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"]
+
+# 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 = "AdafruitHIDLibrarydoc"
+
+# -- 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,
+ "AdafruitHIDLibrary.tex",
+ "Adafruit HID Library Documentation",
+ "Scott Shawcroft",
+ "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,
+ "adafruitHIDlibrary",
+ "Adafruit HID 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,
+ "AdafruitHIDLibrary",
+ "Adafruit HID Library Documentation",
+ author,
+ "AdafruitHIDLibrary",
+ "One line description of project.",
+ "Miscellaneous",
+ ),
+]
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/examples.rst b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/examples.rst
new file mode 100644
index 0000000..549b4bb
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/examples.rst
@@ -0,0 +1,44 @@
+Simple test
+------------
+
+Ensure your device works with this simple test.
+
+.. literalinclude:: ../examples/hid_simpletest.py
+ :caption: examples/hid_simpletest.py
+ :linenos:
+
+Keyboard Shortcuts
+-------------------
+
+Send ALT+Tab for swapping windows, and CTRL+K for searching in a browser.
+
+.. literalinclude:: ../examples/hid_keyboard_shortcuts.py
+ :caption: examples/hid_keyboard_shortcuts.py
+ :linenos:
+
+Simple Gamepad
+---------------
+
+Send gamepad buttons and joystick to the host.
+
+.. literalinclude:: ../examples/hid_simple_gamepad.py
+ :caption: examples/hid_simple_gamepad.py
+ :linenos:
+
+HID Joywing
+------------
+
+Use Joy FeatherWing to drive Gamepad.
+
+.. literalinclude:: ../examples/hid_joywing_gamepad.py
+ :caption: examples/hid_joywing_gamepad.py
+ :linenos:
+
+Consumer Control Brightness
+----------------------------
+
+Send brightness up and down consumer codes to the host.
+
+.. literalinclude:: ../examples/hid_consumer_control_brightness.py
+ :caption: examples/hid_consumer_control_brightness.py
+ :linenos:
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/examples.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/examples.rst.license
new file mode 100644
index 0000000..9aae48d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/examples.rst.license
@@ -0,0 +1,3 @@
+# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/index.rst b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/index.rst
new file mode 100644
index 0000000..5ddac8b
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/index.rst
@@ -0,0 +1,45 @@
+.. include:: ../README.rst
+
+Table of Contents
+=================
+
+.. toctree::
+ :maxdepth: 4
+ :hidden:
+
+ self
+
+.. toctree::
+ :caption: Examples
+
+ examples
+
+.. toctree::
+ :caption: API Reference
+ :maxdepth: 3
+
+ api
+
+.. toctree::
+ :caption: Tutorials
+
+.. toctree::
+ :caption: Related Products
+
+.. toctree::
+ :caption: Other Links
+
+ Download <https://github.com/adafruit/Adafruit_CircuitPython_HID/releases/latest>
+ CircuitPython Reference Documentation <https://docs.circuitpython.org>
+ CircuitPython Support Forum <https://forums.adafruit.com/viewforum.php?f=60>
+ Discord Chat <https://adafru.it/discord>
+ Adafruit Learning System <https://learn.adafruit.com>
+ Adafruit Blog <https://blog.adafruit.com>
+ Adafruit Store <https://www.adafruit.com>
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/index.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/index.rst.license
new file mode 100644
index 0000000..9aae48d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/index.rst.license
@@ -0,0 +1,3 @@
+# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/requirements.txt b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/requirements.txt
new file mode 100644
index 0000000..88e6733
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/docs/requirements.txt
@@ -0,0 +1,5 @@
+# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+sphinx>=4.0.0
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_consumer_control_brightness.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_consumer_control_brightness.py
new file mode 100644
index 0000000..1cf922c
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_consumer_control_brightness.py
@@ -0,0 +1,32 @@
+# SPDX-FileCopyrightText: 2021 Tim C for Adafruit Industries
+# SPDX-License-Identifier: MIT
+
+import time
+import board
+import digitalio
+import usb_hid
+from adafruit_hid.consumer_control import ConsumerControl
+from adafruit_hid.consumer_control_code import ConsumerControlCode
+
+cc = ConsumerControl(usb_hid.devices)
+
+# define buttons. these can be any physical switches/buttons, but the values
+# here work out-of-the-box with a FunHouse UP and DOWN buttons.
+button_up = digitalio.DigitalInOut(board.BUTTON_UP)
+button_up.switch_to_input(pull=digitalio.Pull.DOWN)
+
+button_down = digitalio.DigitalInOut(board.BUTTON_DOWN)
+button_down.switch_to_input(pull=digitalio.Pull.DOWN)
+
+while True:
+ if button_up.value:
+ print("Button up pressed!")
+ # send brightness up button press
+ cc.send(ConsumerControlCode.BRIGHTNESS_INCREMENT)
+
+ if button_down.value:
+ print("Button down pressed!")
+ # send brightness down button press
+ cc.send(ConsumerControlCode.BRIGHTNESS_DECREMENT)
+
+ time.sleep(0.1)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py
new file mode 100644
index 0000000..01a9653
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_gamepad.py
@@ -0,0 +1,157 @@
+# SPDX-FileCopyrightText: 2018 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`Gamepad`
+====================================================
+
+* Author(s): Dan Halbert
+"""
+
+import struct
+import time
+
+from adafruit_hid import find_device
+
+
+class Gamepad:
+ """Emulate a generic gamepad controller with 16 buttons,
+ numbered 1-16, and two joysticks, one controlling
+ ``x` and ``y`` values, and the other controlling ``z`` and
+ ``r_z`` (z rotation or ``Rz``) values.
+
+ The joystick values could be interpreted
+ differently by the receiving program: those are just the names used here.
+ The joystick values are in the range -127 to 127."""
+
+ def __init__(self, devices):
+ """Create a Gamepad object that will send USB gamepad HID reports.
+
+ Devices can be a list of devices that includes a gamepad device or a gamepad device
+ itself. A device is any object that implements ``send_report()``, ``usage_page`` and
+ ``usage``.
+ """
+ self._gamepad_device = find_device(devices, usage_page=0x1, usage=0x05)
+
+ # Reuse this bytearray to send mouse reports.
+ # Typically controllers start numbering buttons at 1 rather than 0.
+ # report[0] buttons 1-8 (LSB is button 1)
+ # report[1] buttons 9-16
+ # report[2] joystick 0 x: -127 to 127
+ # report[3] joystick 0 y: -127 to 127
+ # report[4] joystick 1 x: -127 to 127
+ # report[5] joystick 1 y: -127 to 127
+ self._report = bytearray(6)
+
+ # Remember the last report as well, so we can avoid sending
+ # duplicate reports.
+ self._last_report = bytearray(6)
+
+ # Store settings separately before putting into report. Saves code
+ # especially for buttons.
+ self._buttons_state = 0
+ self._joy_x = 0
+ self._joy_y = 0
+ self._joy_z = 0
+ self._joy_r_z = 0
+
+ # Send an initial report to test if HID device is ready.
+ # If not, wait a bit and try once more.
+ try:
+ self.reset_all()
+ except OSError:
+ time.sleep(1)
+ self.reset_all()
+
+ def press_buttons(self, *buttons):
+ """Press and hold the given buttons."""
+ for button in buttons:
+ self._buttons_state |= 1 << self._validate_button_number(button) - 1
+ self._send()
+
+ def release_buttons(self, *buttons):
+ """Release the given buttons."""
+ for button in buttons:
+ self._buttons_state &= ~(1 << self._validate_button_number(button) - 1)
+ self._send()
+
+ def release_all_buttons(self):
+ """Release all the buttons."""
+
+ self._buttons_state = 0
+ self._send()
+
+ def click_buttons(self, *buttons):
+ """Press and release the given buttons."""
+ self.press_buttons(*buttons)
+ self.release_buttons(*buttons)
+
+ def move_joysticks(self, x=None, y=None, z=None, r_z=None):
+ """Set and send the given joystick values.
+ The joysticks will remain set with the given values until changed
+
+ One joystick provides ``x`` and ``y`` values,
+ and the other provides ``z`` and ``r_z`` (z rotation).
+ Any values left as ``None`` will not be changed.
+
+ All values must be in the range -127 to 127 inclusive.
+
+ Examples::
+
+ # Change x and y values only.
+ gp.move_joysticks(x=100, y=-50)
+
+ # Reset all joystick values to center position.
+ gp.move_joysticks(0, 0, 0, 0)
+ """
+ if x is not None:
+ self._joy_x = self._validate_joystick_value(x)
+ if y is not None:
+ self._joy_y = self._validate_joystick_value(y)
+ if z is not None:
+ self._joy_z = self._validate_joystick_value(z)
+ if r_z is not None:
+ self._joy_r_z = self._validate_joystick_value(r_z)
+ self._send()
+
+ def reset_all(self):
+ """Release all buttons and set joysticks to zero."""
+ self._buttons_state = 0
+ self._joy_x = 0
+ self._joy_y = 0
+ self._joy_z = 0
+ self._joy_r_z = 0
+ self._send(always=True)
+
+ def _send(self, always=False):
+ """Send a report with all the existing settings.
+ If ``always`` is ``False`` (the default), send only if there have been changes.
+ """
+ struct.pack_into(
+ "<Hbbbb",
+ self._report,
+ 0,
+ self._buttons_state,
+ self._joy_x,
+ self._joy_y,
+ self._joy_z,
+ self._joy_r_z,
+ )
+
+ if always or self._last_report != self._report:
+ self._gamepad_device.send_report(self._report)
+ # Remember what we sent, without allocating new storage.
+ self._last_report[:] = self._report
+
+ @staticmethod
+ def _validate_button_number(button):
+ if not 1 <= button <= 16:
+ raise ValueError("Button number must in range 1 to 16")
+ return button
+
+ @staticmethod
+ def _validate_joystick_value(value):
+ if not -127 <= value <= 127:
+ raise ValueError("Joystick value must be in range -127 to 127")
+ return value
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_joywing_gamepad.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_joywing_gamepad.py
new file mode 100644
index 0000000..2473675
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_joywing_gamepad.py
@@ -0,0 +1,76 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+# SPDX-License-Identifier: MIT
+
+# Use Joy FeatherWing to drive Gamepad.
+# https://www.adafruit.com/product/3632
+# https://learn.adafruit.com/joy-featherwing
+
+# You must add a gamepad HID device inside your boot.py file
+# in order to use this example.
+# See this Learn Guide for details:
+# https://learn.adafruit.com/customizing-usb-devices-in-circuitpython/hid-devices#custom-hid-devices-3096614-9
+
+import time
+
+import board
+import busio
+from micropython import const
+from adafruit_seesaw.seesaw import Seesaw
+import usb_hid
+from hid_gamepad import Gamepad
+
+
+def range_map(value, in_min, in_max, out_min, out_max):
+ return (value - in_min) * (out_max - out_min) // (in_max - in_min) + out_min
+
+
+BUTTON_RIGHT = const(6)
+BUTTON_DOWN = const(7)
+BUTTON_LEFT = const(9)
+BUTTON_UP = const(10)
+BUTTON_SEL = const(14)
+button_mask = const(
+ (1 << BUTTON_RIGHT)
+ | (1 << BUTTON_DOWN)
+ | (1 << BUTTON_LEFT)
+ | (1 << BUTTON_UP)
+ | (1 << BUTTON_SEL)
+)
+
+i2c = busio.I2C(board.SCL, board.SDA)
+
+ss = Seesaw(i2c)
+
+ss.pin_mode_bulk(button_mask, ss.INPUT_PULLUP)
+
+last_game_x = 0
+last_game_y = 0
+
+g = Gamepad(usb_hid.devices)
+
+while True:
+ x = ss.analog_read(2)
+ y = ss.analog_read(3)
+
+ game_x = range_map(x, 0, 1023, -127, 127)
+ game_y = range_map(y, 0, 1023, -127, 127)
+ if last_game_x != game_x or last_game_y != game_y:
+ last_game_x = game_x
+ last_game_y = game_y
+ print(game_x, game_y)
+ g.move_joysticks(x=game_x, y=game_y)
+
+ buttons = (BUTTON_RIGHT, BUTTON_DOWN, BUTTON_LEFT, BUTTON_UP, BUTTON_SEL)
+ button_state = [False] * len(buttons)
+ for i, button in enumerate(buttons):
+ buttons = ss.digital_read_bulk(button_mask)
+ if not (buttons & (1 << button) and not button_state[i]):
+ g.press_buttons(i + 1)
+ print("Press", i + 1)
+ button_state[i] = True
+ elif button_state[i]:
+ g.release_buttons(i + 1)
+ print("Release", i + 1)
+ button_state[i] = False
+
+ time.sleep(0.01)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_keyboard_shortcuts.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_keyboard_shortcuts.py
new file mode 100644
index 0000000..8a25bd5
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_keyboard_shortcuts.py
@@ -0,0 +1,32 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+# SPDX-License-Identifier: MIT
+
+import time
+import board
+import digitalio
+import usb_hid
+from adafruit_hid.keyboard import Keyboard
+from adafruit_hid.keycode import Keycode
+
+kbd = Keyboard(usb_hid.devices)
+
+# define buttons. these can be any physical switches/buttons, but the values
+# here work out-of-the-box with a CircuitPlayground Express' A and B buttons.
+swap = digitalio.DigitalInOut(board.D4)
+swap.direction = digitalio.Direction.INPUT
+swap.pull = digitalio.Pull.DOWN
+
+search = digitalio.DigitalInOut(board.D5)
+search.direction = digitalio.Direction.INPUT
+search.pull = digitalio.Pull.DOWN
+
+while True:
+ # press ALT+TAB to swap windows
+ if swap.value:
+ kbd.send(Keycode.ALT, Keycode.TAB)
+
+ # press CTRL+K, which in a web browser will open the search dialog
+ elif search.value:
+ kbd.send(Keycode.CONTROL, Keycode.K)
+
+ time.sleep(0.1)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_simple_gamepad.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_simple_gamepad.py
new file mode 100644
index 0000000..614cc84
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_simple_gamepad.py
@@ -0,0 +1,57 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+# SPDX-License-Identifier: MIT
+
+# You must add a gamepad HID device inside your boot.py file
+# in order to use this example.
+# See this Learn Guide for details:
+# https://learn.adafruit.com/customizing-usb-devices-in-circuitpython/hid-devices#custom-hid-devices-3096614-9
+
+import board
+import digitalio
+import analogio
+import usb_hid
+
+from hid_gamepad import Gamepad
+
+gp = Gamepad(usb_hid.devices)
+
+# Create some buttons. The physical buttons are connected
+# to ground on one side and these and these pins on the other.
+button_pins = (board.D2, board.D3, board.D4, board.D5)
+
+# Map the buttons to button numbers on the Gamepad.
+# gamepad_buttons[i] will send that button number when buttons[i]
+# is pushed.
+gamepad_buttons = (1, 2, 8, 15)
+
+buttons = [digitalio.DigitalInOut(pin) for pin in button_pins]
+for button in buttons:
+ button.direction = digitalio.Direction.INPUT
+ button.pull = digitalio.Pull.UP
+
+# Connect an analog two-axis joystick to A4 and A5.
+ax = analogio.AnalogIn(board.A4)
+ay = analogio.AnalogIn(board.A5)
+
+# Equivalent of Arduino's map() function.
+def range_map(x, in_min, in_max, out_min, out_max):
+ return (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min
+
+
+while True:
+ # Buttons are grounded when pressed (.value = False).
+ for i, button in enumerate(buttons):
+ gamepad_button_num = gamepad_buttons[i]
+ if button.value:
+ gp.release_buttons(gamepad_button_num)
+ print(" release", gamepad_button_num, end="")
+ else:
+ gp.press_buttons(gamepad_button_num)
+ print(" press", gamepad_button_num, end="")
+
+ # Convert range[0, 65535] to -127 to 127
+ gp.move_joysticks(
+ x=range_map(ax.value, 0, 65535, -127, 127),
+ y=range_map(ay.value, 0, 65535, -127, 127),
+ )
+ print(" x", ax.value, "y", ay.value)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_simpletest.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_simpletest.py
new file mode 100644
index 0000000..3c5f651
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/examples/hid_simpletest.py
@@ -0,0 +1,31 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+# SPDX-License-Identifier: MIT
+
+import time
+import board
+import digitalio
+import usb_hid
+from adafruit_hid.mouse import Mouse
+
+mouse = Mouse(usb_hid.devices)
+
+# define buttons. these can be any physical switches/buttons, but the values
+# here work out-of-the-box with a CircuitPlayground Express' A and B buttons.
+up = digitalio.DigitalInOut(board.D4)
+up.direction = digitalio.Direction.INPUT
+up.pull = digitalio.Pull.DOWN
+
+down = digitalio.DigitalInOut(board.D5)
+down.direction = digitalio.Direction.INPUT
+down.pull = digitalio.Pull.DOWN
+
+while True:
+ # scroll up one unit (varies with host/OS)
+ if up.value:
+ mouse.move(wheel=1)
+
+ # scroll down one unit (varies with host/OS)
+ elif down.value:
+ mouse.move(wheel=-1)
+
+ time.sleep(0.1)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/requirements.txt b/circuitpython/frozen/Adafruit_CircuitPython_HID/requirements.txt
new file mode 100644
index 0000000..17a850d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/requirements.txt
@@ -0,0 +1,5 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+Adafruit-Blinka
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/setup.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/setup.py
new file mode 100644
index 0000000..3fb2a36
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/setup.py
@@ -0,0 +1,55 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""A setuptools based setup module.
+
+See:
+https://packaging.python.org/en/latest/distributing.html
+https://github.com/pypa/sampleproject
+"""
+
+# Always prefer setuptools over distutils
+from setuptools import setup, find_packages
+
+# To use a consistent encoding
+from codecs import open
+from os import path
+
+here = path.abspath(path.dirname(__file__))
+
+# Get the long description from the README file
+with open(path.join(here, "README.rst"), encoding="utf-8") as f:
+ long_description = f.read()
+
+setup(
+ name="adafruit-circuitpython-hid",
+ use_scm_version=True,
+ setup_requires=["setuptools_scm"],
+ description="CircuitPython helper library for simulating HID devices.",
+ long_description=long_description,
+ long_description_content_type="text/x-rst",
+ # The project's main homepage.
+ url="https://github.com/adafruit/Adafruit_CircuitPython_HID",
+ # Author details
+ author="Adafruit Industries",
+ author_email="circuitpython@adafruit.com",
+ install_requires=["Adafruit-Blinka"],
+ # 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",
+ ],
+ # What does your project relate to?
+ keywords="adafruit hid human interface device keyboard mouse keycode keypad"
+ "hardware micropython circuitpython",
+ # You can just specify the packages manually here if your project is
+ # simple. Or you can use find_packages().
+ packages=["adafruit_hid"],
+)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.pre-commit-config.yaml b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.pre-commit-config.yaml
new file mode 100644
index 0000000..1b9fadc
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.pre-commit-config.yaml
@@ -0,0 +1,42 @@
+# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
+#
+# SPDX-License-Identifier: Unlicense
+
+repos:
+- repo: https://github.com/python/black
+ rev: 20.8b1
+ hooks:
+ - id: black
+- repo: https://github.com/fsfe/reuse-tool
+ rev: v0.12.1
+ hooks:
+ - id: reuse
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v2.3.0
+ hooks:
+ - id: check-yaml
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
+- repo: https://github.com/pycqa/pylint
+ rev: v2.11.1
+ hooks:
+ - id: pylint
+ name: pylint (library code)
+ types: [python]
+ args:
+ - --disable=consider-using-f-string
+ exclude: "^(docs/|examples/|tests/|setup.py$)"
+ - 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
+ - id: pylint
+ name: pylint (test code)
+ description: Run pylint rules on "tests/*.py" files
+ types: [python]
+ files: "^tests/"
+ args:
+ - --disable=missing-docstring,consider-using-f-string,duplicate-code
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.pylintrc b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.pylintrc
new file mode 100644
index 0000000..cfd1c41
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.pylintrc
@@ -0,0 +1,436 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+[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
+
+# 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,bad-continuation,unspecified-encoding
+
+# 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*(# )?<?https?://\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=yes
+
+# 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/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.readthedocs.yaml b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.readthedocs.yaml
new file mode 100644
index 0000000..f8b2891
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/.readthedocs.yaml
@@ -0,0 +1,15 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+python:
+ version: "3.x"
+ install:
+ - requirements: docs/requirements.txt
+ - requirements: requirements.txt
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/CODE_OF_CONDUCT.md b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..8a55c07
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/CODE_OF_CONDUCT.md
@@ -0,0 +1,135 @@
+<!--
+SPDX-FileCopyrightText: 2014 Coraline Ada Ehmke
+SPDX-FileCopyrightText: 2019 Kattni Rembor for Adafruit Industries
+SPDX-License-Identifier: CC-BY-4.0
+-->
+
+# Adafruit Community Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and leaders pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level or type of
+experience, education, socio-economic status, nationality, personal appearance,
+race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+We are committed to providing a friendly, safe and welcoming environment for
+all.
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Be kind and courteous to others
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Collaborating with other community members
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and sexual attention or advances
+* The use of inappropriate images, including in a community member's avatar
+* The use of inappropriate language, including in a community member's nickname
+* Any spamming, flaming, baiting or other attention-stealing behavior
+* Excessive or unwelcome helping; answering outside the scope of the question
+ asked
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Promoting or spreading disinformation, lies, or conspiracy theories against
+ a person, group, organisation, project, or community
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate
+
+The goal of the standards and moderation guidelines outlined here is to build
+and maintain a respectful community. We ask that you don’t just aim to be
+"technically unimpeachable", but rather try to be your best self.
+
+We value many things beyond technical expertise, including collaboration and
+supporting others within our community. Providing a positive experience for
+other community members can have a much more significant impact than simply
+providing the correct answer.
+
+## Our Responsibilities
+
+Project leaders are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project leaders have the right and responsibility to remove, edit, or
+reject messages, comments, commits, code, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any community member for other behaviors that they deem
+inappropriate, threatening, offensive, or harmful.
+
+## Moderation
+
+Instances of behaviors that violate the Adafruit Community Code of Conduct
+may be reported by any member of the community. Community members are
+encouraged to report these situations, including situations they witness
+involving other community members.
+
+You may report in the following ways:
+
+In any situation, you may send an email to <support@adafruit.com>.
+
+On the Adafruit Discord, you may send an open message from any channel
+to all Community Moderators by tagging @community moderators. You may
+also send an open message from any channel, or a direct message to
+@kattni#1507, @tannewt#4653, @Dan Halbert#1614, @cater#2442,
+@sommersoft#0222, @Mr. Certainly#0472 or @Andon#8175.
+
+Email and direct message reports will be kept confidential.
+
+In situations on Discord where the issue is particularly egregious, possibly
+illegal, requires immediate action, or violates the Discord terms of service,
+you should also report the message directly to Discord.
+
+These are the steps for upholding our community’s standards of conduct.
+
+1. Any member of the community may report any situation that violates the
+Adafruit Community Code of Conduct. All reports will be reviewed and
+investigated.
+2. If the behavior is an egregious violation, the community member who
+committed the violation may be banned immediately, without warning.
+3. Otherwise, moderators will first respond to such behavior with a warning.
+4. Moderators follow a soft "three strikes" policy - the community member may
+be given another chance, if they are receptive to the warning and change their
+behavior.
+5. If the community member is unreceptive or unreasonable when warned by a
+moderator, or the warning goes unheeded, they may be banned for a first or
+second offense. Repeated offenses will result in the community member being
+banned.
+
+## Scope
+
+This Code of Conduct and the enforcement policies listed above apply to all
+Adafruit Community venues. This includes but is not limited to any community
+spaces (both public and private), the entire Adafruit Discord server, and
+Adafruit GitHub repositories. Examples of Adafruit Community spaces include
+but are not limited to meet-ups, audio chats on the Adafruit Discord, or
+interaction at a conference.
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. As a community
+member, you are representing our community, and are expected to behave
+accordingly.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 1.4, available at
+<https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>,
+and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
+
+For other projects adopting the Adafruit Community Code of
+Conduct, please contact the maintainers of those projects for enforcement.
+If you wish to use this code of conduct for your own project, consider
+explicitly mentioning your moderation policy or making a copy with your
+own moderation policy so as to avoid confusion.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSE b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSE
new file mode 100644
index 0000000..de855cb
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/CC-BY-4.0.txt b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/CC-BY-4.0.txt
new file mode 100644
index 0000000..3f92dfc
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/CC-BY-4.0.txt
@@ -0,0 +1,324 @@
+Creative Commons Attribution 4.0 International Creative Commons Corporation
+("Creative Commons") is not a law firm and does not provide legal services
+or legal advice. Distribution of Creative Commons public licenses does not
+create a lawyer-client or other relationship. Creative Commons makes its licenses
+and related information available on an "as-is" basis. Creative Commons gives
+no warranties regarding its licenses, any material licensed under their terms
+and conditions, or any related information. Creative Commons disclaims all
+liability for damages resulting from their use to the fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and conditions
+that creators and other rights holders may use to share original works of
+authorship and other material subject to copyright and certain other rights
+specified in the public license below. The following considerations are for
+informational purposes only, are not exhaustive, and do not form part of our
+licenses.
+
+Considerations for licensors: Our public licenses are intended for use by
+those authorized to give the public permission to use material in ways otherwise
+restricted by copyright and certain other rights. Our licenses are irrevocable.
+Licensors should read and understand the terms and conditions of the license
+they choose before applying it. Licensors should also secure all rights necessary
+before applying our licenses so that the public can reuse the material as
+expected. Licensors should clearly mark any material not subject to the license.
+This includes other CC-licensed material, or material used under an exception
+or limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors
+
+Considerations for the public: By using one of our public licenses, a licensor
+grants the public permission to use the licensed material under specified
+terms and conditions. If the licensor's permission is not necessary for any
+reason–for example, because of any applicable exception or limitation to copyright–then
+that use is not regulated by the license. Our licenses grant only permissions
+under copyright and certain other rights that a licensor has authority to
+grant. Use of the licensed material may still be restricted for other reasons,
+including because others have copyright or other rights in the material. A
+licensor may make special requests, such as asking that all changes be marked
+or described. Although not required by our licenses, you are encouraged to
+respect those requests where reasonable. More considerations for the public
+: wiki.creativecommons.org/Considerations_for_licensees Creative Commons Attribution
+4.0 International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree to
+be bound by the terms and conditions of this Creative Commons Attribution
+4.0 International Public License ("Public License"). To the extent this Public
+License may be interpreted as a contract, You are granted the Licensed Rights
+in consideration of Your acceptance of these terms and conditions, and the
+Licensor grants You such rights in consideration of benefits the Licensor
+receives from making the Licensed Material available under these terms and
+conditions.
+
+Section 1 – Definitions.
+
+a. Adapted Material means material subject to Copyright and Similar Rights
+that is derived from or based upon the Licensed Material and in which the
+Licensed Material is translated, altered, arranged, transformed, or otherwise
+modified in a manner requiring permission under the Copyright and Similar
+Rights held by the Licensor. For purposes of this Public License, where the
+Licensed Material is a musical work, performance, or sound recording, Adapted
+Material is always produced where the Licensed Material is synched in timed
+relation with a moving image.
+
+b. Adapter's License means the license You apply to Your Copyright and Similar
+Rights in Your contributions to Adapted Material in accordance with the terms
+and conditions of this Public License.
+
+c. Copyright and Similar Rights means copyright and/or similar rights closely
+related to copyright including, without limitation, performance, broadcast,
+sound recording, and Sui Generis Database Rights, without regard to how the
+rights are labeled or categorized. For purposes of this Public License, the
+rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
+
+d. Effective Technological Measures means those measures that, in the absence
+of proper authority, may not be circumvented under laws fulfilling obligations
+under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996,
+and/or similar international agreements.
+
+e. Exceptions and Limitations means fair use, fair dealing, and/or any other
+exception or limitation to Copyright and Similar Rights that applies to Your
+use of the Licensed Material.
+
+f. Licensed Material means the artistic or literary work, database, or other
+material to which the Licensor applied this Public License.
+
+g. Licensed Rights means the rights granted to You subject to the terms and
+conditions of this Public License, which are limited to all Copyright and
+Similar Rights that apply to Your use of the Licensed Material and that the
+Licensor has authority to license.
+
+h. Licensor means the individual(s) or entity(ies) granting rights under this
+Public License.
+
+i. Share means to provide material to the public by any means or process that
+requires permission under the Licensed Rights, such as reproduction, public
+display, public performance, distribution, dissemination, communication, or
+importation, and to make material available to the public including in ways
+that members of the public may access the material from a place and at a time
+individually chosen by them.
+
+j. Sui Generis Database Rights means rights other than copyright resulting
+from Directive 96/9/EC of the European Parliament and of the Council of 11
+March 1996 on the legal protection of databases, as amended and/or succeeded,
+as well as other essentially equivalent rights anywhere in the world.
+
+k. You means the individual or entity exercising the Licensed Rights under
+this Public License. Your has a corresponding meaning.
+
+Section 2 – Scope.
+
+ a. License grant.
+
+1. Subject to the terms and conditions of this Public License, the Licensor
+hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive,
+irrevocable license to exercise the Licensed Rights in the Licensed Material
+to:
+
+ A. reproduce and Share the Licensed Material, in whole or in part; and
+
+ B. produce, reproduce, and Share Adapted Material.
+
+2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions
+and Limitations apply to Your use, this Public License does not apply, and
+You do not need to comply with its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section 6(a).
+
+4. Media and formats; technical modifications allowed. The Licensor authorizes
+You to exercise the Licensed Rights in all media and formats whether now known
+or hereafter created, and to make technical modifications necessary to do
+so. The Licensor waives and/or agrees not to assert any right or authority
+to forbid You from making technical modifications necessary to exercise the
+Licensed Rights, including technical modifications necessary to circumvent
+Effective Technological Measures. For purposes of this Public License, simply
+making modifications authorized by this Section 2(a)(4) never produces Adapted
+Material.
+
+ 5. Downstream recipients.
+
+A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed
+Material automatically receives an offer from the Licensor to exercise the
+Licensed Rights under the terms and conditions of this Public License.
+
+B. No downstream restrictions. You may not offer or impose any additional
+or different terms or conditions on, or apply any Effective Technological
+Measures to, the Licensed Material if doing so restricts exercise of the Licensed
+Rights by any recipient of the Licensed Material.
+
+6. No endorsement. Nothing in this Public License constitutes or may be construed
+as permission to assert or imply that You are, or that Your use of the Licensed
+Material is, connected with, or sponsored, endorsed, or granted official status
+by, the Licensor or others designated to receive attribution as provided in
+Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+1. Moral rights, such as the right of integrity, are not licensed under this
+Public License, nor are publicity, privacy, and/or other similar personality
+rights; however, to the extent possible, the Licensor waives and/or agrees
+not to assert any such rights held by the Licensor to the limited extent necessary
+to allow You to exercise the Licensed Rights, but not otherwise.
+
+2. Patent and trademark rights are not licensed under this Public License.
+
+3. To the extent possible, the Licensor waives any right to collect royalties
+from You for the exercise of the Licensed Rights, whether directly or through
+a collecting society under any voluntary or waivable statutory or compulsory
+licensing scheme. In all other cases the Licensor expressly reserves any right
+to collect such royalties.
+
+Section 3 – License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the following
+conditions.
+
+ a. Attribution.
+
+1. If You Share the Licensed Material (including in modified form), You must:
+
+A. retain the following if it is supplied by the Licensor with the Licensed
+Material:
+
+i. identification of the creator(s) of the Licensed Material and any others
+designated to receive attribution, in any reasonable manner requested by the
+Licensor (including by pseudonym if designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of warranties;
+
+v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
+
+B. indicate if You modified the Licensed Material and retain an indication
+of any previous modifications; and
+
+C. indicate the Licensed Material is licensed under this Public License, and
+include the text of, or the URI or hyperlink to, this Public License.
+
+2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner
+based on the medium, means, and context in which You Share the Licensed Material.
+For example, it may be reasonable to satisfy the conditions by providing a
+URI or hyperlink to a resource that includes the required information.
+
+3. If requested by the Licensor, You must remove any of the information required
+by Section 3(a)(1)(A) to the extent reasonably practicable.
+
+4. If You Share Adapted Material You produce, the Adapter's License You apply
+must not prevent recipients of the Adapted Material from complying with this
+Public License.
+
+Section 4 – Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that apply to
+Your use of the Licensed Material:
+
+a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract,
+reuse, reproduce, and Share all or a substantial portion of the contents of
+the database;
+
+b. if You include all or a substantial portion of the database contents in
+a database in which You have Sui Generis Database Rights, then the database
+in which You have Sui Generis Database Rights (but not its individual contents)
+is Adapted Material; and
+
+c. You must comply with the conditions in Section 3(a) if You Share all or
+a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not replace
+Your obligations under this Public License where the Licensed Rights include
+other Copyright and Similar Rights.
+
+Section 5 – Disclaimer of Warranties and Limitation of Liability.
+
+a. Unless otherwise separately undertaken by the Licensor, to the extent possible,
+the Licensor offers the Licensed Material as-is and as-available, and makes
+no representations or warranties of any kind concerning the Licensed Material,
+whether express, implied, statutory, or other. This includes, without limitation,
+warranties of title, merchantability, fitness for a particular purpose, non-infringement,
+absence of latent or other defects, accuracy, or the presence or absence of
+errors, whether or not known or discoverable. Where disclaimers of warranties
+are not allowed in full or in part, this disclaimer may not apply to You.
+
+b. To the extent possible, in no event will the Licensor be liable to You
+on any legal theory (including, without limitation, negligence) or otherwise
+for any direct, special, indirect, incidental, consequential, punitive, exemplary,
+or other losses, costs, expenses, or damages arising out of this Public License
+or use of the Licensed Material, even if the Licensor has been advised of
+the possibility of such losses, costs, expenses, or damages. Where a limitation
+of liability is not allowed in full or in part, this limitation may not apply
+to You.
+
+c. The disclaimer of warranties and limitation of liability provided above
+shall be interpreted in a manner that, to the extent possible, most closely
+approximates an absolute disclaimer and waiver of all liability.
+
+Section 6 – Term and Termination.
+
+a. This Public License applies for the term of the Copyright and Similar Rights
+licensed here. However, if You fail to comply with this Public License, then
+Your rights under this Public License terminate automatically.
+
+b. Where Your right to use the Licensed Material has terminated under Section
+6(a), it reinstates:
+
+1. automatically as of the date the violation is cured, provided it is cured
+within 30 days of Your discovery of the violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+c. For the avoidance of doubt, this Section 6(b) does not affect any right
+the Licensor may have to seek remedies for Your violations of this Public
+License.
+
+d. For the avoidance of doubt, the Licensor may also offer the Licensed Material
+under separate terms or conditions or stop distributing the Licensed Material
+at any time; however, doing so will not terminate this Public License.
+
+ e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
+
+Section 7 – Other Terms and Conditions.
+
+a. The Licensor shall not be bound by any additional or different terms or
+conditions communicated by You unless expressly agreed.
+
+b. Any arrangements, understandings, or agreements regarding the Licensed
+Material not stated herein are separate from and independent of the terms
+and conditions of this Public License.
+
+Section 8 – Interpretation.
+
+a. For the avoidance of doubt, this Public License does not, and shall not
+be interpreted to, reduce, limit, restrict, or impose conditions on any use
+of the Licensed Material that could lawfully be made without permission under
+this Public License.
+
+b. To the extent possible, if any provision of this Public License is deemed
+unenforceable, it shall be automatically reformed to the minimum extent necessary
+to make it enforceable. If the provision cannot be reformed, it shall be severed
+from this Public License without affecting the enforceability of the remaining
+terms and conditions.
+
+c. No term or condition of this Public License will be waived and no failure
+to comply consented to unless expressly agreed to by the Licensor.
+
+d. Nothing in this Public License constitutes or may be interpreted as a limitation
+upon, or waiver of, any privileges and immunities that apply to the Licensor
+or You, including from the legal processes of any jurisdiction or authority.
+
+Creative Commons is not a party to its public licenses. Notwithstanding, Creative
+Commons may elect to apply one of its public licenses to material it publishes
+and in those instances will be considered the "Licensor." The text of the
+Creative Commons public licenses is dedicated to the public domain under the
+CC0 Public Domain Dedication. Except for the limited purpose of indicating
+that material is shared under a Creative Commons public license or as otherwise
+permitted by the Creative Commons policies published at creativecommons.org/policies,
+Creative Commons does not authorize the use of the trademark "Creative Commons"
+or any other trademark or logo of Creative Commons without its prior written
+consent including, without limitation, in connection with any unauthorized
+modifications to any of its public licenses or any other arrangements, understandings,
+or agreements concerning use of licensed material. For the avoidance of doubt,
+this paragraph does not form part of the public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/MIT.txt b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/MIT.txt
new file mode 100644
index 0000000..204b93d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/MIT.txt
@@ -0,0 +1,19 @@
+MIT License Copyright (c) <year> <copyright holders>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/Unlicense.txt b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/Unlicense.txt
new file mode 100644
index 0000000..24a8f90
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/LICENSES/Unlicense.txt
@@ -0,0 +1,20 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute
+this software, either in source code form or as a compiled binary, for any
+purpose, commercial or non-commercial, and by any means.
+
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and
+to the detriment of our heirs and successors. We intend this dedication to
+be an overt act of relinquishment in perpetuity of all present and future
+rights to this software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information,
+please refer to <https://unlicense.org/>
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/README.rst b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/README.rst
new file mode 100644
index 0000000..2988777
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/README.rst
@@ -0,0 +1,76 @@
+
+Introduction
+============
+
+.. image:: https://readthedocs.org/projects/adafruit-circuitpython-simpleio/badge/?version=latest
+ :target: https://docs.circuitpython.org/projects/simpleio/en/latest/
+ :alt: Documentation Status
+
+.. image :: https://img.shields.io/discord/327254708534116352.svg
+ :target: https://adafru.it/discord
+ :alt: Discord
+
+.. image:: https://github.com/adafruit/Adafruit_CircuitPython_SimpleIO/workflows/Build%20CI/badge.svg
+ :target: https://github.com/adafruit/Adafruit_CircuitPython_SimpleIO/actions/
+ :alt: Build Status
+
+SimpleIO features a number of helpers to simplify hardware interactions. Many
+of the functions and classes are inspired by Arduino APIs to make it easier to
+move to CircuitPython from Arduino.
+
+Dependencies
+=============
+This driver depends on:
+
+* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
+
+Please ensure all dependencies are available on the CircuitPython filesystem.
+This is easily achieved by downloading
+`the Adafruit library and driver bundle <https://circuitpython.org/libraries>`_.
+
+Installing from PyPI
+====================
+
+On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
+PyPI <https://pypi.org/project/adafruit-circuitpython-simpleio/>`_. To install for current user:
+
+.. code-block:: shell
+
+ pip3 install adafruit-circuitpython-simpleio
+
+To install system-wide (this may be required in some cases):
+
+.. code-block:: shell
+
+ sudo pip3 install adafruit-circuitpython-simpleio
+
+To install in a virtual environment in your current project:
+
+.. code-block:: shell
+
+ mkdir project-name && cd project-name
+ python3 -m venv .env
+ source .env/bin/activate
+ pip3 install adafruit-circuitpython-simpleio
+
+Usage Example
+=============
+
+See the examples in the `examples/` folder for usage.
+
+Documentation
+=============
+
+API documentation for this library can be found on `Read the Docs <https://docs.circuitpython.org/projects/simpleio/en/latest/>`_.
+
+Contributing
+============
+
+Contributions are welcome! Please read our `Code of Conduct
+<https://github.com/adafruit/Adafruit_CircuitPython_SimpleIO/blob/main/CODE_OF_CONDUCT.md>`_
+before contributing to help this project stay welcoming.
+
+Documentation
+=============
+
+For information on building library documentation, please check out `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/README.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/README.rst.license
new file mode 100644
index 0000000..11cd75d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/README.rst.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
+
+SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/_static/favicon.ico b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/_static/favicon.ico
new file mode 100644
index 0000000..5aca983
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/_static/favicon.ico
Binary files differ
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/_static/favicon.ico.license b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/_static/favicon.ico.license
new file mode 100644
index 0000000..86a3fbf
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/_static/favicon.ico.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2018 Phillip Torrone for Adafruit Industries
+
+SPDX-License-Identifier: CC-BY-4.0
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/api.rst b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/api.rst
new file mode 100644
index 0000000..67c1b45
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/api.rst
@@ -0,0 +1,5 @@
+
+.. If you created a package, create one automodule per module in the package.
+
+.. automodule:: simpleio
+ :members:
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/api.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/api.rst.license
new file mode 100644
index 0000000..9aae48d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/api.rst.license
@@ -0,0 +1,3 @@
+# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/conf.py b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/conf.py
new file mode 100644
index 0000000..46eb31f
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/conf.py
@@ -0,0 +1,175 @@
+# -*- coding: utf-8 -*-
+
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+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.viewcode",
+]
+
+autodoc_mock_imports = ["pulseio"]
+
+intersphinx_mapping = {
+ "python": ("https://docs.python.org/3", None),
+ "CircuitPython": ("https://docs.circuitpython.org/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 = "Adafruit CircuitPython SimpleIO Library"
+copyright = "2017 Scott Shawcroft"
+author = "Scott Shawcroft"
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = "1.0"
+# The full version, including alpha/beta/rc tags.
+release = "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 = True
+
+
+# -- 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"]
+
+# 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 = "AdafruitSimpleIOLibrarydoc"
+
+# -- 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,
+ "AdafruitSimpleIOLibrary.tex",
+ "Adafruit SimpleIO Library Documentation",
+ "Scott Shawcroft",
+ "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,
+ "adafruitSimpleIOlibrary",
+ "Adafruit SimpleIO 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,
+ "AdafruitSimpleIOLibrary",
+ "Adafruit SimpleIO Library Documentation",
+ author,
+ "AdafruitSimpleIOLibrary",
+ "One line description of project.",
+ "Miscellaneous",
+ ),
+]
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/examples.rst b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/examples.rst
new file mode 100644
index 0000000..61359aa
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/examples.rst
@@ -0,0 +1,16 @@
+Simple tests
+-------------
+
+Ensure your device works with these simple tests.
+
+.. literalinclude:: ../examples/simpleio_tone_demo.py
+ :caption: examples/simpleio_tone_demo.py
+ :linenos:
+
+.. literalinclude:: ../examples/simpleio_shift_in_out_demo.py
+ :caption: examples/simpleio_shift_in_out_demo.py
+ :linenos:
+
+.. literalinclude:: ../examples/simpleio_map_range_simpletest.py
+ :caption: examples/simpleio_map_range_simpletest.py
+ :linenos:
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/examples.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/examples.rst.license
new file mode 100644
index 0000000..9aae48d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/examples.rst.license
@@ -0,0 +1,3 @@
+# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/index.rst b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/index.rst
new file mode 100644
index 0000000..28e5b1a
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/index.rst
@@ -0,0 +1,45 @@
+.. include:: ../README.rst
+
+Table of Contents
+=================
+
+.. toctree::
+ :maxdepth: 4
+ :hidden:
+
+ self
+
+.. toctree::
+ :caption: Examples
+
+ examples
+
+.. toctree::
+ :caption: API Reference
+ :maxdepth: 3
+
+ api
+
+.. toctree::
+ :caption: Tutorials
+
+.. toctree::
+ :caption: Related Products
+
+.. toctree::
+ :caption: Other Links
+
+ Download <https://github.com/adafruit/Adafruit_CircuitPython_SimpleIO/releases/latest>
+ CircuitPython Reference Documentation <https://docs.circuitpython.org>
+ CircuitPython Support Forum <https://forums.adafruit.com/viewforum.php?f=60>
+ Discord Chat <https://adafru.it/discord>
+ Adafruit Learning System <https://learn.adafruit.com>
+ Adafruit Blog <https://blog.adafruit.com>
+ Adafruit Store <https://www.adafruit.com>
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/index.rst.license b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/index.rst.license
new file mode 100644
index 0000000..9aae48d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/index.rst.license
@@ -0,0 +1,3 @@
+# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/requirements.txt b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/requirements.txt
new file mode 100644
index 0000000..88e6733
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/docs/requirements.txt
@@ -0,0 +1,5 @@
+# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+sphinx>=4.0.0
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_map_range_simpletest.py b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_map_range_simpletest.py
new file mode 100644
index 0000000..dd2f72e
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_map_range_simpletest.py
@@ -0,0 +1,25 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+# SPDX-License-Identifier: MIT
+
+"""
+'map_range_demo.py'.
+
+=================================================
+maps a number from one range to another
+"""
+import time
+import simpleio
+
+while True:
+ sensor_value = 150
+
+ # Map the sensor's range from 0<=sensor_value<=255 to 0<=sensor_value<=1023
+ print("original sensor value: ", sensor_value)
+ mapped_value = simpleio.map_range(sensor_value, 0, 255, 0, 1023)
+ print("mapped sensor value: ", mapped_value)
+ time.sleep(2)
+
+ # Map the new sensor value back to the old range
+ sensor_value = simpleio.map_range(mapped_value, 0, 1023, 0, 255)
+ print("original value returned: ", sensor_value)
+ time.sleep(2)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_shift_in_out_demo.py b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_shift_in_out_demo.py
new file mode 100644
index 0000000..7a01f79
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_shift_in_out_demo.py
@@ -0,0 +1,38 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+# SPDX-License-Identifier: MIT
+
+"""
+'shift_in_out_demo.py'.
+
+=================================================
+shifts data into and out of a data pin
+"""
+
+import time
+import board
+import digitalio
+import simpleio
+
+# set up clock, data, and latch pins
+clk = digitalio.DigitalInOut(board.D12)
+data = digitalio.DigitalInOut(board.D11)
+latch = digitalio.DigitalInOut(board.D10)
+clk.direction = digitalio.Direction.OUTPUT
+latch.direction = digitalio.Direction.OUTPUT
+
+while True:
+ data_to_send = 256
+ # shifting 256 bits out of data pin
+ latch.value = False
+ data.direction = digitalio.Direction.OUTPUT
+ print("shifting out...")
+ simpleio.shift_out(data, clk, data_to_send, msb_first=False)
+ latch.value = True
+ time.sleep(3)
+
+ # shifting 256 bits into the data pin
+ latch.value = False
+ data.direction = digitalio.Direction.INPUT
+ print("shifting in...")
+ simpleio.shift_in(data, clk)
+ time.sleep(3)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_tone_demo.py b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_tone_demo.py
new file mode 100644
index 0000000..4c3a8b4
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/examples/simpleio_tone_demo.py
@@ -0,0 +1,18 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+# SPDX-License-Identifier: MIT
+
+"""
+'tone_demo.py'.
+
+=================================================
+a short piezo song using tone()
+"""
+import time
+import board
+import simpleio
+
+
+while True:
+ for f in (262, 294, 330, 349, 392, 440, 494, 523):
+ simpleio.tone(board.A0, f, 0.25)
+ time.sleep(1)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/requirements.txt b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/requirements.txt
new file mode 100644
index 0000000..17a850d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/requirements.txt
@@ -0,0 +1,5 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: Unlicense
+
+Adafruit-Blinka
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/setup.py b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/setup.py
new file mode 100644
index 0000000..bc63e8b
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/setup.py
@@ -0,0 +1,54 @@
+# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""A setuptools based setup module.
+
+See:
+https://packaging.python.org/en/latest/distributing.html
+https://github.com/pypa/sampleproject
+"""
+
+# Always prefer setuptools over distutils
+from setuptools import setup, find_packages
+
+# To use a consistent encoding
+from codecs import open
+from os import path
+
+here = path.abspath(path.dirname(__file__))
+
+# Get the long description from the README file
+with open(path.join(here, "README.rst"), encoding="utf-8") as f:
+ long_description = f.read()
+
+setup(
+ name="adafruit-circuitpython-simpleio",
+ use_scm_version=True,
+ setup_requires=["setuptools_scm"],
+ description="CircuitPython helper library to simplify hardware interactions.",
+ long_description=long_description,
+ long_description_content_type="text/x-rst",
+ # The project's main homepage.
+ url="https://github.com/adafruit/Adafruit_CircuitPython_SimpleIO",
+ # Author details
+ author="Adafruit Industries",
+ author_email="circuitpython@adafruit.com",
+ install_requires=["Adafruit-Blinka"],
+ # 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",
+ ],
+ # What does your project relate to?
+ keywords="adafruit simpleio servo map range bitwrite hardware micropython circuitpython",
+ # You can just specify the packages manually here if your project is
+ # simple. Or you can use find_packages().
+ py_modules=["simpleio"],
+)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/simpleio.py b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/simpleio.py
new file mode 100644
index 0000000..5aa014c
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_SimpleIO/simpleio.py
@@ -0,0 +1,252 @@
+# SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`simpleio` - Simple, beginner friendly IO.
+=================================================
+
+The `simpleio` module contains classes to provide simple access to IO.
+
+* Author(s): Scott Shawcroft
+"""
+import time
+import sys
+import array
+import digitalio
+import pwmio
+
+try:
+ # RawSample was moved in CircuitPython 5.x.
+ if sys.implementation.version[0] >= 5:
+ import audiocore
+ else:
+ import audioio as audiocore
+ # Some boards have AudioOut (true DAC), others have PWMAudioOut.
+ try:
+ from audioio import AudioOut
+ except ImportError:
+ from audiopwmio import PWMAudioOut as AudioOut
+except ImportError:
+ pass # not always supported by every board!
+
+__version__ = "0.0.0-auto.0"
+__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_SimpleIO.git"
+
+
+def tone(pin, frequency, duration=1, length=100):
+ """
+ Generates a square wave of the specified frequency on a pin
+
+ :param ~microcontroller.Pin pin: Pin on which to output the tone
+ :param float frequency: Frequency of tone in Hz
+ :param int length: Variable size buffer (optional)
+ :param int duration: Duration of tone in seconds (optional)
+ """
+ if length * frequency > 350000:
+ length = 350000 // frequency
+ try:
+ # pin with PWM
+ # pylint: disable=no-member
+ with pwmio.PWMOut(
+ pin, frequency=int(frequency), variable_frequency=False
+ ) as pwm:
+ pwm.duty_cycle = 0x8000
+ time.sleep(duration)
+ # pylint: enable=no-member
+ except ValueError:
+ # pin without PWM
+ sample_length = length
+ square_wave = array.array("H", [0] * sample_length)
+ for i in range(sample_length / 2):
+ square_wave[i] = 0xFFFF
+ square_wave_sample = audiocore.RawSample(square_wave)
+ square_wave_sample.sample_rate = int(len(square_wave) * frequency)
+ with AudioOut(pin) as dac:
+ if not dac.playing:
+ dac.play(square_wave_sample, loop=True)
+ time.sleep(duration)
+ dac.stop()
+
+
+def bitWrite(x, n, b): # pylint: disable-msg=invalid-name
+ """
+ Based on the Arduino bitWrite function, changes a specific bit of a value to 0 or 1.
+ The return value is the original value with the changed bit.
+ This function is written for use with 8-bit shift registers
+
+ :param x: numeric value
+ :param n: position to change starting with least-significant (right-most) bit as 0
+ :param b: value to write (0 or 1)
+ """
+ if b == 1:
+ x |= 1 << n & 255
+ else:
+ x &= ~(1 << n) & 255
+ return x
+
+
+def shift_in(data_pin, clock, msb_first=True):
+ """
+ Shifts in a byte of data one bit at a time. Starts from either the LSB or
+ MSB.
+
+ .. warning:: Data and clock are swapped compared to other CircuitPython libraries
+ in order to match Arduino.
+
+ :param ~digitalio.DigitalInOut data_pin: pin on which to input each bit
+ :param ~digitalio.DigitalInOut clock: toggles to signal data_pin reads
+ :param bool msb_first: True when the first bit is most significant
+ :return: returns the value read
+ :rtype: int
+ """
+
+ value = 0
+ i = 0
+
+ for i in range(0, 8):
+ if msb_first:
+ value |= (data_pin.value) << (7 - i)
+ else:
+ value |= (data_pin.value) << i
+ # toggle clock True/False
+ clock.value = True
+ clock.value = False
+ i += 1
+ return value
+
+
+def shift_out(data_pin, clock, value, msb_first=True, bitcount=8):
+ """
+ Shifts out a byte of data one bit at a time. Data gets written to a data
+ pin. Then, the clock pulses hi then low
+
+ .. warning:: Data and clock are swapped compared to other CircuitPython libraries
+ in order to match Arduino.
+
+ :param ~digitalio.DigitalInOut data_pin: value bits get output on this pin
+ :param ~digitalio.DigitalInOut clock: toggled once the data pin is set
+ :param bool msb_first: True when the first bit is most significant
+ :param int value: byte to be shifted
+ :param unsigned bitcount: number of bits to shift
+
+ Example for Metro M0 Express:
+
+ .. code-block:: python
+
+ import digitalio
+ import simpleio
+ from board import *
+ clock = digitalio.DigitalInOut(D12)
+ data_pin = digitalio.DigitalInOut(D11)
+ latchPin = digitalio.DigitalInOut(D10)
+ clock.direction = digitalio.Direction.OUTPUT
+ data_pin.direction = digitalio.Direction.OUTPUT
+ latchPin.direction = digitalio.Direction.OUTPUT
+
+ while True:
+ valueSend = 500
+ # shifting out least significant bits
+ # must toggle latchPin.value before and after shift_out to push to IC chip
+ # this sample code was tested using
+ latchPin.value = False
+ simpleio.shift_out(data_pin, clock, (valueSend>>8), msb_first = False)
+ latchPin.value = True
+ time.sleep(1.0)
+ latchPin.value = False
+ simpleio.shift_out(data_pin, clock, valueSend, msb_first = False)
+ latchPin.value = True
+ time.sleep(1.0)
+
+ # shifting out most significant bits
+ latchPin.value = False
+ simpleio.shift_out(data_pin, clock, (valueSend>>8))
+ latchPin.value = True
+ time.sleep(1.0)
+ latchpin.value = False
+ simpleio.shift_out(data_pin, clock, valueSend)
+ latchpin.value = True
+ time.sleep(1.0)
+ """
+ if bitcount < 0 or bitcount > 32:
+ raise ValueError("bitcount must be in range 0..32 inclusive")
+
+ if msb_first:
+ bitsequence = lambda: range(bitcount - 1, -1, -1)
+ else:
+ bitsequence = lambda: range(0, bitcount)
+
+ for i in bitsequence():
+ tmpval = bool(value & (1 << i))
+ data_pin.value = tmpval
+ # toggle clock pin True/False
+ clock.value = True
+ clock.value = False
+
+
+class DigitalOut:
+ """
+ Simple digital output that is valid until reload.
+
+ :param pin microcontroller.Pin: output pin
+ :param value bool: default value
+ :param drive_mode digitalio.DriveMode: drive mode for the output
+ """
+
+ def __init__(self, pin, **kwargs):
+ self.iopin = digitalio.DigitalInOut(pin)
+ self.iopin.switch_to_output(**kwargs)
+
+ @property
+ def value(self):
+ """The digital logic level of the output pin."""
+ return self.iopin.value
+
+ @value.setter
+ def value(self, value):
+ self.iopin.value = value
+
+
+class DigitalIn:
+ """
+ Simple digital input that is valid until reload.
+
+ :param pin microcontroller.Pin: input pin
+ :param pull digitalio.Pull: pull configuration for the input
+ """
+
+ def __init__(self, pin, **kwargs):
+ self.iopin = digitalio.DigitalInOut(pin)
+ self.iopin.switch_to_input(**kwargs)
+
+ @property
+ def value(self):
+ """The digital logic level of the input pin."""
+ return self.iopin.value
+
+ @value.setter
+ def value(self, value): # pylint: disable-msg=no-self-use, unused-argument
+ raise AttributeError("Cannot set the value on a digital input.")
+
+
+def map_range(x, in_min, in_max, out_min, out_max):
+ """
+ Maps a number from one range to another.
+ Note: This implementation handles values < in_min differently than arduino's map function does.
+
+ :return: Returns value mapped to new range
+ :rtype: float
+ """
+ in_range = in_max - in_min
+ in_delta = x - in_min
+ if in_range != 0:
+ mapped = in_delta / in_range
+ elif in_delta != 0:
+ mapped = in_delta
+ else:
+ mapped = 0.5
+ mapped *= out_max - out_min
+ mapped += out_min
+ if out_min <= out_max:
+ return max(min(mapped, out_max), out_min)
+ return min(max(mapped, out_max), out_min)
diff --git a/circuitpython/frozen/circuitpython-stage/LICENSE b/circuitpython/frozen/circuitpython-stage/LICENSE
new file mode 100644
index 0000000..acd9e28
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Radomir Dopieralski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/circuitpython/frozen/circuitpython-stage/README.rst b/circuitpython/frozen/circuitpython-stage/README.rst
new file mode 100644
index 0000000..dfadce4
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/README.rst
@@ -0,0 +1,44 @@
+Stage – a Tile and Sprite Engine
+********************************
+
+Stage is a library that lets you display tile grids and sprites on SPI-based
+RGB displays in CircuitPython. It is mostly made with video games in mind, but
+it can be useful in making any kind of graphical user interface too.
+
+For performance reasons, a part of this library has been written in C and has
+to be compiled as part of the CircuitPython firmware as the ``_stage`` module.
+For memory saving reasons, it's best if this library is also included in the
+firmware, as a frozen module.
+
+
+API Reference
+*************
+
+The API reference is available at `<http://circuitpython-stage.readthedocs.io>`_.
+
+stage
+=====
+.. automodule:: stage
+ :members:
+
+
+ugame
+=======
+.. module:: ugame
+
+.. data:: display
+
+ An initialized display, that can be used for creating Stage objects.
+
+.. data:: buttons
+
+ An instance of ``GamePad`` or other similar class, that has a
+ ``get_pressed`` method for retrieving a bit mask of pressed buttons. That
+ value can be then checked with & operator against the constants: ``K_UP``,
+ ``K_DOWN``, ``K_LEFT``, ``K_RIGHT``, ``K_X``, ``K_O`` and on some platforms
+ also: ``K_START`` and ``K_SELECT``.
+
+.. data:: audio
+
+ And instance of the ``Audio`` or other similar class, that has ``play``,
+ ``stop`` and ``mute`` methods.
diff --git a/circuitpython/frozen/circuitpython-stage/docs/.buildinfo b/circuitpython/frozen/circuitpython-stage/docs/.buildinfo
new file mode 100644
index 0000000..30130b6
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/.buildinfo
@@ -0,0 +1,4 @@
+# Sphinx build info version 1
+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
+config: bbefe5630918a9d58757bbc0b225e223
+tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/circuitpython/frozen/circuitpython-stage/docs/.doctrees/README.doctree b/circuitpython/frozen/circuitpython-stage/docs/.doctrees/README.doctree
new file mode 100644
index 0000000..6b058e6
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/.doctrees/README.doctree
Binary files differ
diff --git a/circuitpython/frozen/circuitpython-stage/docs/.doctrees/environment.pickle b/circuitpython/frozen/circuitpython-stage/docs/.doctrees/environment.pickle
new file mode 100644
index 0000000..d290392
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/.doctrees/environment.pickle
Binary files differ
diff --git a/circuitpython/frozen/circuitpython-stage/docs/README.rst b/circuitpython/frozen/circuitpython-stage/docs/README.rst
new file mode 120000
index 0000000..89a0106
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/README.rst
@@ -0,0 +1 @@
+../README.rst \ No newline at end of file
diff --git a/circuitpython/frozen/circuitpython-stage/docs/_stage.py b/circuitpython/frozen/circuitpython-stage/docs/_stage.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/_stage.py
diff --git a/circuitpython/frozen/circuitpython-stage/docs/audioio.py b/circuitpython/frozen/circuitpython-stage/docs/audioio.py
new file mode 100644
index 0000000..3a1213c
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/audioio.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
diff --git a/circuitpython/frozen/circuitpython-stage/docs/board.py b/circuitpython/frozen/circuitpython-stage/docs/board.py
new file mode 100644
index 0000000..ab4195e
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/board.py
@@ -0,0 +1,10 @@
+X = None
+DOWN = None
+LEFT = None
+RIGHT = None
+UP = None
+O = None
+SCK = None
+MOSI = None
+DC = None
+SPEAKER = None
diff --git a/circuitpython/frozen/circuitpython-stage/docs/busio.py b/circuitpython/frozen/circuitpython-stage/docs/busio.py
new file mode 100644
index 0000000..c419fea
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/busio.py
@@ -0,0 +1,12 @@
+class SPI:
+ def __init__(self, clock, MOSI):
+ pass
+
+ def try_lock(self):
+ pass
+
+ def write(self, buffer):
+ pass
+
+ def configure(self, baudrate=None, polarity=None, phase=None):
+ pass
diff --git a/circuitpython/frozen/circuitpython-stage/docs/conf.py b/circuitpython/frozen/circuitpython-stage/docs/conf.py
new file mode 100644
index 0000000..585fe6b
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/conf.py
@@ -0,0 +1,145 @@
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+sys.path.insert(0, os.path.abspath('.'))
+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.viewcode',
+]
+
+intersphinx_mapping = {
+ 'python': ('https://docs.python.org/3.4', 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 = 'README'
+
+# General information about the project.
+project = u'Stage'
+copyright = u'2017 Radomir Dopieralski'
+author = u'Radomir Dopieralski'
+
+# 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']
+
+# 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
+
+
+# -- 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']
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Stagedoc'
+
+# -- 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, 'Stage.tex', u'Stage Documentation',
+ u'Radomir Dopieralski', '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, 'stage', u'Stage 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, 'Stage', u'Stage Documentation',
+ author, 'Stage', 'Tile and sprite engine.', 'Miscellaneous'),
+]
diff --git a/circuitpython/frozen/circuitpython-stage/docs/digitalio.py b/circuitpython/frozen/circuitpython-stage/docs/digitalio.py
new file mode 100644
index 0000000..5b5ab80
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/digitalio.py
@@ -0,0 +1,6 @@
+class DigitalInOut:
+ def __init__(self, pin):
+ pass
+
+ def switch_to_output(self, value=None):
+ pass
diff --git a/circuitpython/frozen/circuitpython-stage/docs/gamepad.py b/circuitpython/frozen/circuitpython-stage/docs/gamepad.py
new file mode 100644
index 0000000..8cf5bb4
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/gamepad.py
@@ -0,0 +1,3 @@
+class GamePad:
+ def __init__(self, *args):
+ pass
diff --git a/circuitpython/frozen/circuitpython-stage/docs/ustruct.py b/circuitpython/frozen/circuitpython-stage/docs/ustruct.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/docs/ustruct.py
diff --git a/circuitpython/frozen/circuitpython-stage/examples/ball/ball.bmp b/circuitpython/frozen/circuitpython-stage/examples/ball/ball.bmp
new file mode 100644
index 0000000..67de048
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/examples/ball/ball.bmp
Binary files differ
diff --git a/circuitpython/frozen/circuitpython-stage/examples/ball/ball.py b/circuitpython/frozen/circuitpython-stage/examples/ball/ball.py
new file mode 100644
index 0000000..66cc52c
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/examples/ball/ball.py
@@ -0,0 +1,38 @@
+import ugame
+import stage
+
+
+class Ball(stage.Sprite):
+ def __init__(self, x, y):
+ super().__init__(bank, 1, x, y)
+ self.dx = 2
+ self.dy = 1
+
+ def update(self):
+ super().update()
+ self.set_frame(self.frame % 4 + 1)
+ self.move(self.x + self.dx, self.y + self.dy)
+ if not 0 < self.x < 112:
+ self.dx = -self.dx
+ if not 0 < self.y < 112:
+ self.dy = -self.dy
+
+
+bank = stage.Bank.from_bmp16("ball.bmp")
+background = stage.Grid(bank)
+text = stage.Text(12, 1)
+text.move(16, 60)
+text.text("Hello world!")
+ball1 = Ball(64, 0)
+ball2 = Ball(0, 76)
+ball3 = Ball(111, 64)
+game = stage.Stage(ugame.display, 12)
+sprites = [ball1, ball2, ball3]
+game.layers = [text, ball1, ball2, ball3, background]
+game.render_block(0, 0, 128, 128)
+
+while True:
+ for sprite in sprites:
+ sprite.update()
+ game.render_sprites(sprites)
+ game.tick()
diff --git a/circuitpython/frozen/circuitpython-stage/examples/ball/main.py b/circuitpython/frozen/circuitpython-stage/examples/ball/main.py
new file mode 100644
index 0000000..66cc52c
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/examples/ball/main.py
@@ -0,0 +1,38 @@
+import ugame
+import stage
+
+
+class Ball(stage.Sprite):
+ def __init__(self, x, y):
+ super().__init__(bank, 1, x, y)
+ self.dx = 2
+ self.dy = 1
+
+ def update(self):
+ super().update()
+ self.set_frame(self.frame % 4 + 1)
+ self.move(self.x + self.dx, self.y + self.dy)
+ if not 0 < self.x < 112:
+ self.dx = -self.dx
+ if not 0 < self.y < 112:
+ self.dy = -self.dy
+
+
+bank = stage.Bank.from_bmp16("ball.bmp")
+background = stage.Grid(bank)
+text = stage.Text(12, 1)
+text.move(16, 60)
+text.text("Hello world!")
+ball1 = Ball(64, 0)
+ball2 = Ball(0, 76)
+ball3 = Ball(111, 64)
+game = stage.Stage(ugame.display, 12)
+sprites = [ball1, ball2, ball3]
+game.layers = [text, ball1, ball2, ball3, background]
+game.render_block(0, 0, 128, 128)
+
+while True:
+ for sprite in sprites:
+ sprite.update()
+ game.render_sprites(sprites)
+ game.tick()
diff --git a/circuitpython/frozen/circuitpython-stage/examples/rpg/ground.bmp b/circuitpython/frozen/circuitpython-stage/examples/rpg/ground.bmp
new file mode 100644
index 0000000..d7e5f16
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/examples/rpg/ground.bmp
Binary files differ
diff --git a/circuitpython/frozen/circuitpython-stage/examples/rpg/main.py b/circuitpython/frozen/circuitpython-stage/examples/rpg/main.py
new file mode 100644
index 0000000..37dfd87
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/examples/rpg/main.py
@@ -0,0 +1,68 @@
+import random
+import ugame
+import stage
+
+
+g = stage.Bank.from_bmp16("ground.bmp")
+b = stage.Bank.from_bmp16("tiles.bmp")
+l1 = stage.Grid(g)
+l0 = stage.Grid(b, 10, 9)
+l0.tile(0, 0, 13)
+l0.move(-8, -8)
+for y in range(8):
+ for x in range(8):
+ l1.tile(x, y, random.randint(0, 4))
+for y in range(9):
+ for x in range(9):
+ t = 0
+ bit = 1
+ for dx in (0, -1):
+ for dy in (-1, 0):
+ if l1.tile(x + dx, y + dy) == 4:
+ t |= bit
+ bit <<= 1
+ l0.tile(x, y, 15 - t)
+p = stage.Sprite(g, 15, 10, 10)
+t = stage.Text(14, 14)
+t.move(8, 8)
+t.text("Hello world!")
+
+game = stage.Stage(ugame.display, 12)
+sprites = [
+ stage.Sprite(g, 15, 60, 50),
+ stage.Sprite(g, 15, 70, 60),
+ stage.Sprite(g, 15, 80, 70),
+ stage.Sprite(g, 15, 90, 80),
+ stage.Sprite(g, 15, 100, 90),
+ p,
+]
+game.layers = [t, l0] + sprites + [l1]
+game.render(0, 0, 128, 128)
+
+frame = 0
+while True:
+ frame = (frame + 1) % 8
+ keys = ugame.buttons.get_pressed()
+ if keys & ugame.K_RIGHT:
+ p.move(p.x, p.y + 2)
+ p.set_frame(12 + frame // 4, 0)
+ elif keys & ugame.K_LEFT:
+ p.move(p.x, p.y - 2)
+ p.set_frame(12 + frame // 4, 4)
+ elif keys & ugame.K_UP:
+ p.move(p.x + 2, p.y)
+ p.set_frame(14, (frame // 4) * 4)
+ elif keys & ugame.K_DOWN:
+ p.move(p.x - 2, p.y)
+ p.set_frame(15, (frame // 4) * 4)
+ else:
+ p.set_frame(15, (frame // 4) * 4)
+ for sprite in sprites:
+ if sprite != p:
+ sprite.set_frame(15, (frame // 4) * 4)
+ x0 = min(sprite.px, sprite.x)
+ y0 = min(sprite.py, sprite.y)
+ x1 = max(sprite.px, sprite.x) + 16
+ y1 = max(sprite.py, sprite.y) + 16
+ game.render(x0, y0, x1, y1)
+ game.tick()
diff --git a/circuitpython/frozen/circuitpython-stage/examples/rpg/tiles.bmp b/circuitpython/frozen/circuitpython-stage/examples/rpg/tiles.bmp
new file mode 100644
index 0000000..0e50ae3
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/examples/rpg/tiles.bmp
Binary files differ
diff --git a/circuitpython/frozen/circuitpython-stage/feather_m4_minitft_featherwing/stage.py b/circuitpython/frozen/circuitpython-stage/feather_m4_minitft_featherwing/stage.py
new file mode 120000
index 0000000..2dedc93
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/feather_m4_minitft_featherwing/stage.py
@@ -0,0 +1 @@
+../stage.py \ No newline at end of file
diff --git a/circuitpython/frozen/circuitpython-stage/feather_m4_minitft_featherwing/ugame.py b/circuitpython/frozen/circuitpython-stage/feather_m4_minitft_featherwing/ugame.py
new file mode 100644
index 0000000..728e014
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/feather_m4_minitft_featherwing/ugame.py
@@ -0,0 +1,82 @@
+import board
+from micropython import const
+from adafruit_seesaw.seesaw import Seesaw
+from adafruit_seesaw.pwmout import PWMOut
+import stage
+import displayio
+
+
+K_UP = const(4)
+K_LEFT = const(8)
+K_DOWN = const(16)
+K_RIGHT = const(128)
+K_X = const(512)
+K_O = const(1024)
+K_SELECT = const(2048)
+K_START = const(0)
+
+_INIT_SEQUENCE = (
+ b"\x01\x80\x96" # SWRESET and Delay 150ms
+ b"\x11\x80\xff" # SLPOUT and Delay
+ b"\xb1\x03\x01\x2C\x2D" # _FRMCTR1
+ b"\xb2\x03\x01\x2C\x2D" # _FRMCTR2
+ b"\xb3\x06\x01\x2C\x2D\x01\x2C\x2D" # _FRMCTR3
+ b"\xb4\x01\x07" # _INVCTR line inversion
+ b"\xc0\x03\xa2\x02\x84" # _PWCTR1 GVDD = 4.7V, 1.0uA
+ b"\xc1\x01\xc5" # _PWCTR2 VGH=14.7V, VGL=-7.35V
+ b"\xc2\x02\x0a\x00" # _PWCTR3 Opamp current small, Boost frequency
+ b"\xc3\x02\x8a\x2a"
+ b"\xc4\x02\x8a\xee"
+ b"\xc5\x01\x0e" # _VMCTR1 VCOMH = 4V, VOML = -1.1V
+ b"\x20\x00" # _INVOFF
+ b"\x36\x01\x60" # _MADCTL bottom to top refresh
+ # 1 clk cycle nonoverlap, 2 cycle gate rise, 3 sycle osc equalie,
+ # fix on VTL
+ b"\x3a\x01\x05" # COLMOD - 16bit color
+ b"\xe0\x10\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10" # _GMCTRP1 Gamma
+ b"\xe1\x10\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10" # _GMCTRN1
+ b"\x13\x80\x0a" # _NORON
+ b"\x29\x80\x64" # _DISPON
+)
+
+
+class GamePadSeesaw:
+ mask = K_RIGHT | K_DOWN | K_LEFT | K_UP | K_SELECT | K_O | K_X
+
+ def __init__(self, ss):
+ ss.pin_mode_bulk(self.mask, ss.INPUT_PULLUP)
+ self.ss = ss
+
+ def get_pressed(self):
+ return ~self.ss.digital_read_bulk(self.mask)
+
+
+class DummyAudio:
+ def play(self, f, loop=False):
+ pass
+
+ def stop(self):
+ pass
+
+ def mute(self, mute):
+ pass
+
+
+i2c = board.I2C()
+ss = Seesaw(i2c, 0x5E)
+spi = board.SPI()
+displayio.release_displays()
+while not spi.try_lock():
+ pass
+spi.configure(baudrate=24000000)
+spi.unlock()
+ss.pin_mode(8, ss.OUTPUT)
+ss.digital_write(8, True) # reset display
+display_bus = displayio.FourWire(spi, command=board.D6, chip_select=board.D5)
+display = displayio.Display(display_bus, _INIT_SEQUENCE, width=160, height=80,
+ rowstart=24)
+del _INIT_SEQUENCE
+buttons = GamePadSeesaw(ss)
+audio = DummyAudio()
+backlight = PWMOut(ss, 5)
+backlight.duty_cycle = 0
diff --git a/circuitpython/frozen/circuitpython-stage/font/font.bmp b/circuitpython/frozen/circuitpython-stage/font/font.bmp
new file mode 100644
index 0000000..c576e8b
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/font/font.bmp
Binary files differ
diff --git a/circuitpython/frozen/circuitpython-stage/font/font2.bmp b/circuitpython/frozen/circuitpython-stage/font/font2.bmp
new file mode 100644
index 0000000..7d41ca6
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/font/font2.bmp
Binary files differ
diff --git a/circuitpython/frozen/circuitpython-stage/font/genfont.py b/circuitpython/frozen/circuitpython-stage/font/genfont.py
new file mode 100644
index 0000000..74e0fcd
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/font/genfont.py
@@ -0,0 +1,89 @@
+import array
+import pprint
+
+
+def color565(r, g, b):
+ return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3
+
+
+class BMP16:
+ """Read 16-color BMP files."""
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.colors = 0
+
+ def read_header(self):
+ """Read the file's header information."""
+
+ if self.colors:
+ return
+ with open(self.filename, 'rb') as f:
+ f.seek(10)
+ self.data = int.from_bytes(f.read(4), 'little')
+ f.seek(18)
+ self.width = int.from_bytes(f.read(4), 'little')
+ self.height = int.from_bytes(f.read(4), 'little')
+ f.seek(46)
+ self.colors = int.from_bytes(f.read(4), 'little')
+
+ def read_palette(self):
+ """Read the color palette information."""
+
+ palette = array.array('H', (0 for i in range(16)))
+ with open(self.filename, 'rb') as f:
+ f.seek(self.data - self.colors * 4)
+ for color in range(self.colors):
+ buffer = f.read(4)
+ c = color565(buffer[2], buffer[1], buffer[0])
+ palette[color] = ((c & 0xff) << 8) | (c >> 8)
+ return palette
+
+ def read_data(self, offset=0, size=-1):
+ """Read the image data."""
+
+ with open(self.filename, 'rb') as f:
+ f.seek(self.data + offset)
+ return f.read(size)
+
+
+class Font:
+ def __init__(self, buffer):
+ self.buffer = buffer
+
+ @classmethod
+ def from_bmp16(cls, filename):
+ bmp = BMP16(filename)
+ bmp.read_header()
+ if bmp.width != 8 or bmp.height != 1024:
+ raise ValueError("A 8x1024 16-color BMP expected!")
+ data = bmp.read_data()
+ self = cls(bytearray(2048))
+ c = 0
+ x = 0
+ y = 7
+ for b in data:
+ self.pixel(c, x, y, b >> 4)
+ x += 1
+ self.pixel(c, x, y, b & 0x0f)
+ x += 1
+ if x >= 8:
+ x = 0
+ y -= 1
+ if y < 0:
+ y = 7
+ c += 1
+ del data
+ self.palette = bmp.read_palette()
+ return self
+
+ def pixel(self, c, x, y, color):
+ index = (127 - c) * 16 + 2 * y + x // 4
+ bit = (x % 4) * 2
+ color = color & 0x03
+ self.buffer[index] |= color << bit
+
+
+font = Font.from_bmp16("font.bmp")
+pprint.pprint(font.buffer)
+pprint.pprint(font.palette.tobytes())
diff --git a/circuitpython/frozen/circuitpython-stage/font/genfont2.py b/circuitpython/frozen/circuitpython-stage/font/genfont2.py
new file mode 100644
index 0000000..158d5e9
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/font/genfont2.py
@@ -0,0 +1,89 @@
+import array
+import pprint
+
+
+def color565(r, g, b):
+ return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3
+
+
+class BMP16:
+ """Read 16-color BMP files."""
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.colors = 0
+
+ def read_header(self):
+ """Read the file's header information."""
+
+ if self.colors:
+ return
+ with open(self.filename, 'rb') as f:
+ f.seek(10)
+ self.data = int.from_bytes(f.read(4), 'little')
+ f.seek(18)
+ self.width = int.from_bytes(f.read(4), 'little')
+ self.height = int.from_bytes(f.read(4), 'little')
+ f.seek(46)
+ self.colors = int.from_bytes(f.read(4), 'little')
+
+ def read_palette(self):
+ """Read the color palette information."""
+
+ palette = array.array('H', (0 for i in range(16)))
+ with open(self.filename, 'rb') as f:
+ f.seek(self.data - self.colors * 4)
+ for color in range(self.colors):
+ buffer = f.read(4)
+ c = color565(buffer[2], buffer[1], buffer[0])
+ palette[color] = ((c & 0xff) << 8) | (c >> 8)
+ return palette
+
+ def read_data(self, offset=0, size=-1):
+ """Read the image data."""
+
+ with open(self.filename, 'rb') as f:
+ f.seek(self.data + offset)
+ return f.read(size)
+
+
+class Font:
+ def __init__(self, buffer):
+ self.buffer = buffer
+
+ @classmethod
+ def from_bmp16(cls, filename):
+ bmp = BMP16(filename)
+ bmp.read_header()
+ if bmp.width != 8 or bmp.height != 1024:
+ raise ValueError("A 8x1024 16-color BMP expected!")
+ data = bmp.read_data()
+ self = cls(bytearray(2048))
+ c = 0
+ x = 0
+ y = 7
+ for b in data:
+ self.pixel(c, x, y, b >> 4)
+ x += 1
+ self.pixel(c, x, y, b & 0x0f)
+ x += 1
+ if x >= 8:
+ x = 0
+ y -= 1
+ if y < 0:
+ y = 7
+ c += 1
+ del data
+ self.palette = bmp.read_palette()
+ return self
+
+ def pixel(self, c, x, y, color):
+ index = (127 - c) * 16 + 2 * y + x // 4
+ bit = (x % 4) * 2
+ color = color & 0x03
+ self.buffer[index] |= color << bit
+
+
+font = Font.from_bmp16("font2.bmp")
+pprint.pprint(font.buffer)
+pprint.pprint(font.palette.tobytes())
diff --git a/circuitpython/frozen/circuitpython-stage/itsybitsy_m4_express/stage.py b/circuitpython/frozen/circuitpython-stage/itsybitsy_m4_express/stage.py
new file mode 120000
index 0000000..2dedc93
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/itsybitsy_m4_express/stage.py
@@ -0,0 +1 @@
+../stage.py \ No newline at end of file
diff --git a/circuitpython/frozen/circuitpython-stage/itsybitsy_m4_express/ugame.py b/circuitpython/frozen/circuitpython-stage/itsybitsy_m4_express/ugame.py
new file mode 100644
index 0000000..20d4d05
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/itsybitsy_m4_express/ugame.py
@@ -0,0 +1,79 @@
+"""
+A helper module that initializes the display and buttons for the uGame
+game console. See https://hackaday.io/project/27629-game
+"""
+
+import board
+import digitalio
+import gamepad
+import stage
+import displayio
+import busio
+
+
+K_X = 0x01
+K_DOWN = 0x02
+K_LEFT = 0x04
+K_RIGHT = 0x08
+K_UP = 0x10
+K_O = 0x20
+K_START = 0x40
+K_SELECT = 0x00
+
+
+_INIT_SEQUENCE = (
+ b"\x01\x80\x96" # SWRESET and Delay 150ms
+ b"\x11\x80\xff" # SLPOUT and Delay
+ b"\xb1\x03\x01\x2C\x2D" # _FRMCTR1
+ b"\xb2\x03\x01\x2C\x2D" # _FRMCTR2
+ b"\xb3\x06\x01\x2C\x2D\x01\x2C\x2D" # _FRMCTR3
+ b"\xb4\x01\x07" # _INVCTR line inversion
+ b"\xc0\x03\xa2\x02\x84" # _PWCTR1 GVDD = 4.7V, 1.0uA
+ b"\xc1\x01\xc5" # _PWCTR2 VGH=14.7V, VGL=-7.35V
+ b"\xc2\x02\x0a\x00" # _PWCTR3 Opamp current small, Boost frequency
+ b"\xc3\x02\x8a\x2a"
+ b"\xc4\x02\x8a\xee"
+ b"\xc5\x01\x0e" # _VMCTR1 VCOMH = 4V, VOML = -1.1V
+ b"\x20\x00" # _INVOFF
+ b"\x36\x01\x10" # _MADCTL bottom to top refresh
+ # 1 clk cycle nonoverlap, 2 cycle gate rise, 3 sycle osc equalie,
+ # fix on VTL
+ b"\x3a\x01\x05" # COLMOD - 16bit color
+ b"\xe0\x10\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10" # _GMCTRP1 Gamma
+ b"\xe1\x10\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10" # _GMCTRN1
+ b"\x13\x80\x0a" # _NORON
+ b"\x29\x80\x64" # _DISPON
+)
+
+
+class DummyAudio:
+ def play(self, f, loop=False):
+ pass
+
+ def stop(self):
+ pass
+
+ def mute(self, mute):
+ pass
+
+
+displayio.release_displays()
+_tft_spi = busio.SPI(clock=board.SCK, MOSI=board.MOSI)
+_tft_spi.try_lock()
+_tft_spi.configure(baudrate=24000000)
+_tft_spi.unlock()
+_fourwire = displayio.FourWire(_tft_spi, command=board.A3,
+ chip_select=board.A2, reset=board.A4)
+display = displayio.Display(_fourwire, _INIT_SEQUENCE, width=160, height=128,
+ rotation=0, backlight_pin=board.A5)
+display.auto_brightness = True
+buttons = gamepad.GamePad(
+ digitalio.DigitalInOut(board.SCL),
+ digitalio.DigitalInOut(board.D12),
+ digitalio.DigitalInOut(board.D11),
+ digitalio.DigitalInOut(board.D9),
+ digitalio.DigitalInOut(board.D10),
+ digitalio.DigitalInOut(board.D7),
+ digitalio.DigitalInOut(board.SDA),
+)
+audio = DummyAudio()
diff --git a/circuitpython/frozen/circuitpython-stage/meowbit/stage.py b/circuitpython/frozen/circuitpython-stage/meowbit/stage.py
new file mode 120000
index 0000000..2dedc93
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/meowbit/stage.py
@@ -0,0 +1 @@
+../stage.py \ No newline at end of file
diff --git a/circuitpython/frozen/circuitpython-stage/meowbit/ugame.py b/circuitpython/frozen/circuitpython-stage/meowbit/ugame.py
new file mode 100644
index 0000000..62dc378
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/meowbit/ugame.py
@@ -0,0 +1,78 @@
+import board
+import stage
+import busio
+import time
+import keypad
+import audiocore
+
+
+K_X = 0x01
+K_O = 0x02
+K_DOWN = 0x04
+K_LEFT = 0x08
+K_RIGHT = 0x10
+K_UP = 0x20
+K_Z = 0x40
+
+display = board.DISPLAY
+display.auto_brightness = True
+display.auto_refresh = False
+
+
+class _Buttons:
+ def __init__(self):
+ self.keys = keypad.Keys((board.BTNA, board.BTNB, board.DOWN,
+ board.LEFT, board.RIGHT, board.UP),
+ value_when_pressed=False, interval=0.05)
+ self.last_state = 0
+ self.event = keypad.Event(0, False)
+ self.last_z_press = None
+
+ def get_pressed(self):
+ buttons = self.last_state
+ events = self.keys.events
+ while events:
+ if events.get_into(self.event):
+ bit = 1 << self.event.key_number
+ if self.event.pressed:
+ buttons |= bit
+ self.last_state |= bit
+ else:
+ self.last_state &= ~bit
+ if buttons & K_Z:
+ now = time.monotonic()
+ if self.last_z_press:
+ if now - self.last_z_press > 2:
+ supervisor.set_next_code_file(None)
+ supervisor.reload()
+ else:
+ self.last_z_press = now
+ else:
+ self.last_z_press = None
+ return buttons
+
+
+class _Audio:
+ last_audio = None
+
+ def __init__(self):
+ self.muted = True
+ self.buffer = bytearray(128)
+ self.audio = board.BUZZ
+
+ def play(self, audio_file, loop=False):
+ if self.muted:
+ return
+ self.stop()
+ wave = audiocore.WaveFile(audio_file, self.buffer)
+ self.audio.play(wave, loop=loop)
+
+ def stop(self):
+ self.audio.stop()
+
+ def mute(self, value=True):
+ self.muted = value
+
+
+audio = _Audio()
+buttons = _Buttons()
diff --git a/circuitpython/frozen/circuitpython-stage/pewpew_m4/pew.py b/circuitpython/frozen/circuitpython-stage/pewpew_m4/pew.py
new file mode 100644
index 0000000..19e3937
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/pewpew_m4/pew.py
@@ -0,0 +1,203 @@
+from micropython import const
+import board
+import busio
+import digitalio
+import time
+import ugame
+import stage
+import array
+
+
+_FONT = (
+ b'{{{{{{wws{w{HY{{{{YDYDY{sUtGUsH[wyH{uHgHE{ws{{{{vyxyv{g[K[g{{]f]{{{wDw{{'
+ b'{{{wy{{{D{{{{{{{w{K_w}x{VHLHe{wuwww{`KfyD{UKgKU{w}XDK{DxTKT{VxUHU{D[wyx{'
+ b'UHfHU{UHEKe{{w{w{{{w{wy{KwxwK{{D{D{{xwKwx{eKg{w{VIHyB{fYH@H{dHdHd{FyxyF{'
+ b'`XHX`{DxtxD{Dxtxx{FyxIF{HHDHH{wwwww{KKKHU{HXpXH{xxxxD{Y@DLH{IL@LX{fYHYf{'
+ b'`HH`x{fYHIF{`HH`H{UxUKU{Dwwww{HHHIR{HHH]w{HHLD@{HYsYH{HYbww{D[wyD{txxxt{'
+ b'x}w_K{GKKKG{wLY{{{{{{{{Dxs{{{{{BIIB{x`XX`{{ByyB{KBIIB{{WIpF{OwUwww{`YB[`'
+ b'x`XHH{w{vwc{K{OKHUxHpXH{vwws_{{dD@H{{`XHH{{fYYf{{`XX`x{bYIBK{Ipxx{{F}_d{'
+ b'wUws_{{HHIV{{HH]s{{HLD@{{HbbH{{HHV[a{D_}D{Cw|wC{wwwwwwpwOwp{WKfxu{@YYY@{'
+)
+_SALT = const(132)
+
+_PALETTE = array.array('H', (0x0, 0x4a29, 0x6004, 0xf8, 0xfd, 0xf42, 0x825b,
+ 0xf8, 0xfe, 0x125b, 0xcffb, 0xe0cf, 0xffff,
+ 0x1ff8, 0xdbff, 0xffff))
+
+K_X = ugame.K_X
+K_DOWN = ugame.K_DOWN
+K_LEFT = ugame.K_LEFT
+K_RIGHT = ugame.K_RIGHT
+K_UP = ugame.K_UP
+K_O = ugame.K_O
+
+_tick = None
+_display = None
+
+
+def brightness(level):
+ pass
+
+
+def show(pix):
+ for y in range(8):
+ for x in range(8):
+ _grid.tile(x + 1, y, 1 + (pix.pixel(x, y) & 0x03))
+ _game.render_block(16, 0, 144, 128)
+
+keys = ugame.buttons.get_pressed
+
+
+def tick(delay):
+ global _tick
+
+ now = time.monotonic()
+ _tick += delay
+ if _tick < now:
+ _tick = now
+ else:
+ time.sleep(_tick - now)
+
+
+class GameOver(SystemExit):
+ pass
+
+
+class Pix:
+ __slots__ = ('buffer', 'width', 'height')
+
+ def __init__(self, width=8, height=8, buffer=None):
+ if buffer is None:
+ buffer = bytearray(width * height)
+ self.buffer = buffer
+ self.width = width
+ self.height = height
+
+ @classmethod
+ def from_text(cls, string, color=None, bgcolor=0, colors=None):
+ pix = cls(4 * len(string), 6)
+ font = memoryview(_FONT)
+ if colors is None:
+ if color is None:
+ colors = (3, 2, bgcolor, bgcolor)
+ else:
+ colors = (color, color, bgcolor, bgcolor)
+ x = 0
+ for c in string:
+ index = ord(c) - 0x20
+ if not 0 <= index <= 95:
+ continue
+ row = 0
+ for byte in font[index * 6:index * 6 + 6]:
+ unsalted = byte ^ _SALT
+ for col in range(4):
+ pix.pixel(x + col, row, colors[unsalted & 0x03])
+ unsalted >>= 2
+ row += 1
+ x += 4
+ return pix
+
+ @classmethod
+ def from_iter(cls, lines):
+ pix = cls(len(lines[0]), len(lines))
+ y = 0
+ for line in lines:
+ x = 0
+ for pixel in line:
+ pix.pixel(x, y, pixel)
+ x += 1
+ y += 1
+ return pix
+
+ def pixel(self, x, y, color=None):
+ if not 0 <= x < self.width or not 0 <= y < self.height:
+ return 0
+ if color is None:
+ return self.buffer[x + y * self.width]
+ self.buffer[x + y * self.width] = color
+
+ def box(self, color, x=0, y=0, width=None, height=None):
+ x = min(max(x, 0), self.width - 1)
+ y = min(max(y, 0), self.height - 1)
+ width = max(0, min(width or self.width, self.width - x))
+ height = max(0, min(height or self.height, self.height - y))
+ for y in range(y, y + height):
+ xx = y * self.width + x
+ for i in range(width):
+ self.buffer[xx] = color
+ xx += 1
+
+ def blit(self, source, dx=0, dy=0, x=0, y=0,
+ width=None, height=None, key=None):
+ if dx < 0:
+ x -= dx
+ dx = 0
+ if x < 0:
+ dx -= x
+ x = 0
+ if dy < 0:
+ y -= dy
+ dy = 0
+ if y < 0:
+ dy -= y
+ y = 0
+ width = min(min(width or source.width, source.width - x),
+ self.width - dx)
+ height = min(min(height or source.height, source.height - y),
+ self.height - dy)
+ source_buffer = memoryview(source.buffer)
+ self_buffer = self.buffer
+ if key is None:
+ for row in range(height):
+ xx = y * source.width + x
+ dxx = dy * self.width + dx
+ self_buffer[dxx:dxx + width] = source_buffer[xx:xx + width]
+ y += 1
+ dy += 1
+ else:
+ for row in range(height):
+ xx = y * source.width + x
+ dxx = dy * self.width + dx
+ for col in range(width):
+ color = source_buffer[xx]
+ if color != key:
+ self_buffer[dxx] = color
+ dxx += 1
+ xx += 1
+ y += 1
+ dy += 1
+
+ def __str__(self):
+ return "\n".join(
+ "".join(
+ ('.', '+', '*', '@')[self.pixel(x, y)]
+ for x in range(self.width)
+ )
+ for y in range(self.height)
+ )
+
+
+def init():
+ global _tick, _display, _bitmap, _grid, _game
+
+ if _tick is not None:
+ return
+
+ _tick = time.monotonic()
+
+ _game = stage.Stage(ugame.display, 12)
+ _bank = bytearray(2048)
+ for c in range(16):
+ for y in range(0, 15):
+ for x in range(0, 7):
+ _bank[c * 128 + y * 8 + x] = c | c << 4
+ _bank[c * 128 + y * 8 + 7] = c << 4
+ _bank[c * 128] = c
+ _bank[c * 128 + 7] = 0
+ _bank[c * 128 + 14 * 8] = c
+ _bank[c * 128 + 14 * 8 + 7] = 0
+ tiles = stage.Bank(_bank, _PALETTE)
+ _grid = stage.Grid(tiles, 10, 8)
+ _grid.move(0, 0)
+ _game.layers = [_grid]
+ _game.render_block()
diff --git a/circuitpython/frozen/circuitpython-stage/pewpew_m4/stage.py b/circuitpython/frozen/circuitpython-stage/pewpew_m4/stage.py
new file mode 120000
index 0000000..2dedc93
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/pewpew_m4/stage.py
@@ -0,0 +1 @@
+../stage.py \ No newline at end of file
diff --git a/circuitpython/frozen/circuitpython-stage/pewpew_m4/ugame.py b/circuitpython/frozen/circuitpython-stage/pewpew_m4/ugame.py
new file mode 100644
index 0000000..f92a6e5
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/pewpew_m4/ugame.py
@@ -0,0 +1,79 @@
+import board
+import stage
+import supervisor
+import time
+import keypad
+import audioio
+import audiocore
+
+
+K_X = 0x01
+K_DOWN = 0x02
+K_LEFT = 0x04
+K_RIGHT = 0x08
+K_UP = 0x10
+K_O = 0x20
+K_START = 0x40
+K_Z = 0x40
+K_SELECT = 0x80
+
+
+class _Buttons:
+ def __init__(self):
+ self.keys = keypad.Keys((board.BUTTON_X, board.BUTTON_DOWN,
+ board.BUTTON_LEFT, board.BUTTON_RIGHT, board.BUTTON_UP,
+ board.BUTTON_O, board.BUTTON_Z), value_when_pressed=False,
+ interval=0.05)
+ self.last_state = 0
+ self.event = keypad.Event(0, False)
+ self.last_z_press = None
+
+ def get_pressed(self):
+ buttons = self.last_state
+ events = self.keys.events
+ while events:
+ if events.get_into(self.event):
+ bit = 1 << self.event.key_number
+ if self.event.pressed:
+ buttons |= bit
+ self.last_state |= bit
+ else:
+ self.last_state &= ~bit
+ if buttons & K_Z:
+ now = time.monotonic()
+ if self.last_z_press:
+ if now - self.last_z_press > 2:
+ supervisor.set_next_code_file(None)
+ supervisor.reload()
+ else:
+ self.last_z_press = now
+ else:
+ self.last_z_press = None
+ return buttons
+
+
+class _Audio:
+ last_audio = None
+
+ def __init__(self, speaker_pin):
+ self.muted = True
+ self.buffer = bytearray(128)
+ self.audio = audioio.AudioOut(speaker_pin)
+
+ def play(self, audio_file, loop=False):
+ if self.muted:
+ return
+ self.stop()
+ wave = audiocore.WaveFile(audio_file, self.buffer)
+ self.audio.play(wave, loop=loop)
+
+ def stop(self):
+ self.audio.stop()
+
+ def mute(self, value=True):
+ self.muted = value
+
+
+display = board.DISPLAY
+buttons = _Buttons()
+audio = _Audio(board.SPEAKER)
diff --git a/circuitpython/frozen/circuitpython-stage/picosystem/stage.py b/circuitpython/frozen/circuitpython-stage/picosystem/stage.py
new file mode 120000
index 0000000..2dedc93
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/picosystem/stage.py
@@ -0,0 +1 @@
+../stage.py \ No newline at end of file
diff --git a/circuitpython/frozen/circuitpython-stage/picosystem/ugame.py b/circuitpython/frozen/circuitpython-stage/picosystem/ugame.py
new file mode 100644
index 0000000..b0b2fd1
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/picosystem/ugame.py
@@ -0,0 +1,86 @@
+import board
+import analogio
+import stage
+import keypad
+import audiocore
+import audiopwmio
+import time
+import supervisor
+
+
+K_O = 0x01 # A
+K_X = 0x02 # B
+K_SELECT = 0x04 # X
+K_START = 0x08 # Y
+K_Z = 0x08 # Y
+K_DOWN = 0x10
+K_LEFT = 0x20
+K_RIGHT = 0x40
+K_UP = 0x80
+
+
+class _Buttons:
+ def __init__(self):
+ self.keys = keypad.Keys((
+ board.SW_A,
+ board.SW_B,
+ board.SW_X,
+ board.SW_Y,
+ board.SW_DOWN,
+ board.SW_LEFT,
+ board.SW_RIGHT,
+ board.SW_UP
+ ), value_when_pressed=False, pull=True, interval=0.05)
+ self.last_state = 0
+ self.event = keypad.Event(0, False)
+ self.last_z_press = None
+
+ def get_pressed(self):
+ buttons = self.last_state
+ events = self.keys.events
+ while events:
+ if events.get_into(self.event):
+ bit = 1 << self.event.key_number
+ if self.event.pressed:
+ buttons |= bit
+ self.last_state |= bit
+ else:
+ self.last_state &= ~bit
+ if buttons & K_Z:
+ now = time.monotonic()
+ if self.last_z_press:
+ if now - self.last_z_press > 2:
+ supervisor.set_next_code_file(None)
+ supervisor.reload()
+ else:
+ self.last_z_press = now
+ else:
+ self.last_z_press = None
+ return buttons
+
+class _Audio:
+ last_audio = None
+
+ def __init__(self):
+ self.muted = True
+ self.buffer = bytearray(128)
+ self.audio = audiopwmio.PWMAudioOut(board.AUDIO)
+
+ def play(self, audio_file, loop=False):
+ if self.muted:
+ return
+ self.stop()
+ wave = audiocore.WaveFile(audio_file, self.buffer)
+ self.audio.play(wave, loop=loop)
+
+ def stop(self):
+ self.audio.stop()
+
+ def mute(self, value=True):
+ self.muted = value
+
+
+audio = _Audio()
+display = board.DISPLAY
+buttons = _Buttons()
+battery = analogio.AnalogIn(board.BAT_SENSE)
diff --git a/circuitpython/frozen/circuitpython-stage/pybadge/stage.py b/circuitpython/frozen/circuitpython-stage/pybadge/stage.py
new file mode 120000
index 0000000..2dedc93
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/pybadge/stage.py
@@ -0,0 +1 @@
+../stage.py \ No newline at end of file
diff --git a/circuitpython/frozen/circuitpython-stage/pybadge/ugame.py b/circuitpython/frozen/circuitpython-stage/pybadge/ugame.py
new file mode 100644
index 0000000..1384de0
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/pybadge/ugame.py
@@ -0,0 +1,122 @@
+import board
+import stage
+import displayio
+import busio
+import time
+import keypad
+import audioio
+import audiocore
+import digitalio
+import supervisor
+
+
+K_X = 0x01
+K_O = 0x02
+K_DOWN = 0x20
+K_LEFT = 0x80
+K_RIGHT = 0x10
+K_UP = 0x40
+K_START = 0x04
+K_SELECT = 0x08
+
+# re-initialize the display for correct rotation and RGB mode
+
+_TFT_INIT = (
+ b"\x01\x80\x96" # SWRESET and Delay 150ms
+ b"\x11\x80\xff" # SLPOUT and Delay
+ b"\xb1\x03\x01\x2C\x2D" # _FRMCTR1
+ b"\xb2\x03\x01\x2C\x2D" # _FRMCTR2
+ b"\xb3\x06\x01\x2C\x2D\x01\x2C\x2D" # _FRMCTR3
+ b"\xb4\x01\x07" # _INVCTR line inversion
+ b"\xc0\x03\xa2\x02\x84" # _PWCTR1 GVDD = 4.7V, 1.0uA
+ b"\xc1\x01\xc5" # _PWCTR2 VGH=14.7V, VGL=-7.35V
+ b"\xc2\x02\x0a\x00" # _PWCTR3 Opamp current small, Boost frequency
+ b"\xc3\x02\x8a\x2a"
+ b"\xc4\x02\x8a\xee"
+ b"\xc5\x01\x0e" # _VMCTR1 VCOMH = 4V, VOML = -1.1V
+ b"\x20\x00" # _INVOFF
+ b"\x36\x01\xa0" # _MADCTL
+ # 1 clk cycle nonoverlap, 2 cycle gate rise, 3 sycle osc equalie,
+ # fix on VTL
+ b"\x3a\x01\x05" # COLMOD - 16bit color
+ b"\xe0\x10\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10" # _GMCTRP1 Gamma
+ b"\xe1\x10\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10" # _GMCTRN1
+ b"\x13\x80\x0a" # _NORON
+ b"\x29\x80\x64" # _DISPON
+)
+
+
+class _Buttons:
+ def __init__(self):
+ self.keys = keypad.ShiftRegisterKeys(clock=board.BUTTON_CLOCK,
+ data=board.BUTTON_OUT, latch=board.BUTTON_LATCH, key_count=8,
+ interval=0.05, value_when_pressed=True)
+ self.last_state = 0
+ self.event = keypad.Event(0, False)
+ self.last_z_press = None
+
+ def get_pressed(self):
+ buttons = self.last_state
+ events = self.keys.events
+ while events:
+ if events.get_into(self.event):
+ bit = 1 << self.event.key_number
+ if self.event.pressed:
+ buttons |= bit
+ self.last_state |= bit
+ else:
+ self.last_state &= ~bit
+ if buttons & K_START:
+ now = time.monotonic()
+ if self.last_z_press:
+ if now - self.last_z_press > 2:
+ supervisor.set_next_code_file(None)
+ supervisor.reload()
+ else:
+ self.last_z_press = now
+ else:
+ self.last_z_press = None
+ return buttons
+
+
+class _Audio:
+ last_audio = None
+
+ def __init__(self, speaker_pin, mute_pin=None):
+ self.muted = True
+ self.buffer = bytearray(128)
+ if mute_pin:
+ self.mute_pin = digitalio.DigitalInOut(mute_pin)
+ self.mute_pin.switch_to_output(value=not self.muted)
+ else:
+ self.mute_pin = None
+ self.audio = audioio.AudioOut(speaker_pin)
+
+ def play(self, audio_file, loop=False):
+ if self.muted:
+ return
+ self.stop()
+ wave = audiocore.WaveFile(audio_file, self.buffer)
+ self.audio.play(wave, loop=loop)
+
+ def stop(self):
+ self.audio.stop()
+
+ def mute(self, value=True):
+ self.muted = value
+ if self.mute_pin:
+ self.mute_pin.value = not value
+
+
+displayio.release_displays()
+_tft_spi = busio.SPI(clock=board.TFT_SCK, MOSI=board.TFT_MOSI)
+_fourwire = displayio.FourWire(_tft_spi, command=board.TFT_DC,
+ chip_select=board.TFT_CS, reset=board.TFT_RST)
+display = displayio.Display(_fourwire, _TFT_INIT, width=160, height=128,
+ rotation=0, auto_refresh=False)
+# Work around broken backlight in CP 7.0
+_backlight = digitalio.DigitalInOut(board.TFT_LITE)
+_backlight.switch_to_output(value=1)
+del _TFT_INIT
+buttons = _Buttons()
+audio = _Audio(board.SPEAKER, board.SPEAKER_ENABLE)
diff --git a/circuitpython/frozen/circuitpython-stage/pygamer/stage.py b/circuitpython/frozen/circuitpython-stage/pygamer/stage.py
new file mode 120000
index 0000000..2dedc93
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/pygamer/stage.py
@@ -0,0 +1 @@
+../stage.py \ No newline at end of file
diff --git a/circuitpython/frozen/circuitpython-stage/pygamer/ugame.py b/circuitpython/frozen/circuitpython-stage/pygamer/ugame.py
new file mode 100644
index 0000000..931f7f2
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/pygamer/ugame.py
@@ -0,0 +1,136 @@
+import board
+import analogio
+import stage
+import displayio
+import busio
+import time
+import keypad
+import audioio
+import audiocore
+import supervisor
+import digitalio
+
+
+K_X = 0x01
+K_O = 0x02
+K_START = 0x04
+K_SELECT = 0x08
+K_DOWN = 0x10
+K_LEFT = 0x20
+K_RIGHT = 0x40
+K_UP = 0x80
+
+# re-initialize the display for correct rotation and RGB mode
+
+_TFT_INIT = (
+ b"\x01\x80\x96" # SWRESET and Delay 150ms
+ b"\x11\x80\xff" # SLPOUT and Delay
+ b"\xb1\x03\x01\x2C\x2D" # _FRMCTR1
+ b"\xb2\x03\x01\x2C\x2D" # _FRMCTR2
+ b"\xb3\x06\x01\x2C\x2D\x01\x2C\x2D" # _FRMCTR3
+ b"\xb4\x01\x07" # _INVCTR line inversion
+ b"\xc0\x03\xa2\x02\x84" # _PWCTR1 GVDD = 4.7V, 1.0uA
+ b"\xc1\x01\xc5" # _PWCTR2 VGH=14.7V, VGL=-7.35V
+ b"\xc2\x02\x0a\x00" # _PWCTR3 Opamp current small, Boost frequency
+ b"\xc3\x02\x8a\x2a"
+ b"\xc4\x02\x8a\xee"
+ b"\xc5\x01\x0e" # _VMCTR1 VCOMH = 4V, VOML = -1.1V
+ b"\x20\x00" # _INVOFF
+ b"\x36\x01\xa0" # _MADCTL
+ # 1 clk cycle nonoverlap, 2 cycle gate rise, 3 sycle osc equalie,
+ # fix on VTL
+ b"\x3a\x01\x05" # COLMOD - 16bit color
+ b"\xe0\x10\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10" # _GMCTRP1 Gamma
+ b"\xe1\x10\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10" # _GMCTRN1
+ b"\x13\x80\x0a" # _NORON
+ b"\x29\x80\x64" # _DISPON
+)
+
+
+class _Buttons:
+ def __init__(self):
+ self.keys = keypad.ShiftRegisterKeys(clock=board.BUTTON_CLOCK,
+ data=board.BUTTON_OUT, latch=board.BUTTON_LATCH, key_count=4,
+ interval=0.05, value_when_pressed=True)
+ self.last_state = 0
+ self.event = keypad.Event(0, False)
+ self.last_z_press = None
+ self.joy_x = analogio.AnalogIn(board.JOYSTICK_X)
+ self.joy_y = analogio.AnalogIn(board.JOYSTICK_Y)
+
+ def get_pressed(self):
+ buttons = self.last_state
+ events = self.keys.events
+ while events:
+ if events.get_into(self.event):
+ bit = 1 << self.event.key_number
+ if self.event.pressed:
+ buttons |= bit
+ self.last_state |= bit
+ else:
+ self.last_state &= ~bit
+ if buttons & K_START:
+ now = time.monotonic()
+ if self.last_z_press:
+ if now - self.last_z_press > 2:
+ supervisor.set_next_code_file(None)
+ supervisor.reload()
+ else:
+ self.last_z_press = now
+ else:
+ self.last_z_press = None
+ dead = 15000
+ x = self.joy_x.value - 32767
+ if x < -dead:
+ buttons |= K_LEFT
+ elif x > dead:
+ buttons |= K_RIGHT
+ y = self.joy_y.value - 32767
+ if y < -dead:
+ buttons |= K_UP
+ elif y > dead:
+ buttons |= K_DOWN
+ return buttons
+
+
+class _Audio:
+ last_audio = None
+
+ def __init__(self, speaker_pin, mute_pin=None):
+ self.muted = True
+ self.buffer = bytearray(128)
+ if mute_pin:
+ self.mute_pin = digitalio.DigitalInOut(mute_pin)
+ self.mute_pin.switch_to_output(value=not self.muted)
+ else:
+ self.mute_pin = None
+ self.audio = audioio.AudioOut(speaker_pin)
+
+ def play(self, audio_file, loop=False):
+ if self.muted:
+ return
+ self.stop()
+ wave = audiocore.WaveFile(audio_file, self.buffer)
+ self.audio.play(wave, loop=loop)
+
+ def stop(self):
+ self.audio.stop()
+
+ def mute(self, value=True):
+ self.muted = value
+ if self.mute_pin:
+ self.mute_pin.value = not value
+
+
+displayio.release_displays()
+_tft_spi = busio.SPI(clock=board.TFT_SCK, MOSI=board.TFT_MOSI)
+_fourwire = displayio.FourWire(_tft_spi, command=board.TFT_DC,
+ chip_select=board.TFT_CS, reset=board.TFT_RST)
+display = displayio.Display(_fourwire, _TFT_INIT, width=160, height=128,
+ rotation=0, auto_refresh=False)
+# Work around broken backlight in CP 7.0
+_backlight = digitalio.DigitalInOut(board.TFT_LITE)
+_backlight.switch_to_output(value=1)
+del _TFT_INIT
+buttons = _Buttons()
+audio = _Audio(board.SPEAKER, board.SPEAKER_ENABLE)
diff --git a/circuitpython/frozen/circuitpython-stage/stage.py b/circuitpython/frozen/circuitpython-stage/stage.py
new file mode 100644
index 0000000..44ab69a
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/stage.py
@@ -0,0 +1,630 @@
+import time
+import array
+import digitalio
+import struct
+
+import _stage
+
+
+FONT = (b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'P\x01\xd4\x05\xf5\x17\xed\x1e\xd5\x15\xd0\x01P\x01\x00\x00'
+ b'P\x01\xd0\x01\xd5\x15\xed\x1e\xf5\x17\xd4\x05P\x01\x00\x00'
+ b'P\x01\xd0\x05\x95\x17\xfd\x1f\x95\x17\xd0\x05P\x01\x00\x00'
+ b'P\x01\xd4\x01\xb5\x15\xfd\x1f\xb5\x15\xd4\x01P\x01\x00\x00'
+ b'T\x05\xf9\x1b\xdd\x1d}\x1f\xd9\x19\xa9\x1aT\x05\x00\x00'
+ b'T\x05\xf9\x1b]\x1d\xdd\x1dY\x19\xa9\x1aT\x05\x00\x00P\x01\xd0\x01'
+ b'\xe5\x16\xfd\x1f\xe4\x06t\x07\x14\x05\x00\x00P\x01\xd5\x15'
+ b']\x1d\x95\x15\xf4\x07\xe4\x06T\x05\x00\x00\x14\x05y\x1b'
+ b'\xfd\x1f\xf9\x1b\xe4\x06\xd0\x01@\x00\x00\x00P\x01\xf4\x06'
+ b'\xad\x1b\xed\x1b\xf9\x1a\xa4\x06P\x01\x00\x00@U\xd0\xff'
+ b'\xf4\xaa\xbdV\xad\x01m\x00m\x00m\x00m\x00m\x00m\x00m\x00m\x00m\x00'
+ b'm\x00m\x00m\x00m\x00m\x00\xbd\x01\xf9V\xe4\xff\x90\xaa@UUU\xff\xff'
+ b'\xaa\xaaUU\x00\x00\x00\x00\x00\x00\x00\x00U\x01\xff\x06'
+ b'\xea\x1b\x95o@n\x00m\x00m\x00m\x00m\x00m\x00m\x00m\x00m\x00m'
+ b'\x00m\x00m\x00m\x00m\x00m@o\xd5k\xff\x1a\xaa\x06U\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00UU\xff\xff\xaa\xaaUU'
+ b'\x00\x00\x00\x00\x00UE\xfe\xd9\xef\xdd\x9f\xad\x9f\xad\x9a'
+ b'\x00\x00\x00\x00\x00\x00U\x15\xf7o\xa7jW\x15v\x00\xadu\xed\xda'
+ b'\xddv\x99\xe6E\x9a\x00U\x00\x00\x00\x00m\x00W\x00n\x00\x15\x00'
+ b'\x1b\x00\x05\x00\x00\x00\x00\x00\xaa\x00\xaa\x00\xaa\x00\xaa\x00'
+ b'\x00\xaa\x00\xaa\x00\xaa\x00\xaaP\x05\x94\x16\xa4\x1b\xe4\x1b'
+ b'\xe4\x1a\xa4\x1aT\x15\x00\x00P\x00\xd0\x01\xd0\x07\xd4\x19'
+ b'\xf9\x1d\xbd\x05T\x00\x00\x00T\x05\xf5\x17\xdd\x1d\xdd\x1d'
+ b'\xf5\x17\xe4\x06T\x05\x00\x00\x14\x05e\x16y\x1b\xd4\x05y\x1be\x16'
+ b'\x14\x05\x00\x00T\x15\xf5\x1f\x9d\x19\xf5\x1d\xd4\x1d\xd0\x1d'
+ b'P\x15\x00\x00\x00\x00P\x01\xe4\x06\xf4\x07\xe4\x06P\x01'
+ b'\x00\x00\x00\x00U\x15\xdd\x1d\xdd\x1d\x99\x19U\x15\xdd\x1d'
+ b'U\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x15\xdd\x1d'
+ b'U\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00P\x01\xd0\x01\xd0\x01\x90\x01P\x01\xd0\x01'
+ b'P\x01\x00\x00T\x05t\x07d\x06T\x05\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x14\x05u\x17\xed\x1et\x07\xed\x1eu\x17\x14\x05\x00\x00'
+ b'T\x15\xf5\x1b\x99\x05\xf5\x17\x94\x19\xf9\x17U\x05\x00\x00'
+ b'\x15\x14\x1d\x1dU\x07\xd0\x01t\x15\x1d\x1d\x05\x15\x00\x00'
+ b'T\x01\xe4\x05u\x07\xdd\x01]\x17\xe5\x1dT\x14\x00\x00P\x01\xd0\x01'
+ b'\x90\x01P\x01\x00\x00\x00\x00\x00\x00\x00\x00@\x05P\x06'
+ b'\x90\x01\xd0\x01\x90\x01P\x06@\x05\x00\x00T\x00d\x01'
+ b'\x90\x01\xd0\x01\x90\x01d\x01T\x00\x00\x00\x00\x00\x14\x05'
+ b't\x07\xd0\x01t\x07\x14\x05\x00\x00\x00\x00P\x01\x90\x01'
+ b'\xd5\x15\xf9\x1b\xd5\x15\x90\x01P\x01\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00P\x01\xd0\x01\x90\x01P\x01\x00\x00\x00\x00\x00\x00'
+ b'U\x15\xf9\x1bU\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00P\x01\xd0\x01P\x01\x00\x00\x00\x04\x00\x1d'
+ b'@\x07\xd0\x01t\x00\x1d\x00\x04\x00\x00\x00T\x05\xe5\x16'
+ b'Y\x1a\xdd\x1di\x19\xe5\x16T\x05\x00\x00@\x01\xd0\x01'
+ b'\xe4\x01\xd0\x01\xd0\x01\xe4\x06T\x05\x00\x00T\x05\xf9\x17'
+ b'U\x1d\xf4\x17Y\x05\xfd\x1fU\x15\x00\x00T\x05\xf5\x17]\x1d\x94\x07'
+ b']\x1d\xf5\x17T\x05\x00\x00P\x00t\x00]\x05]\x17\xfd\x1fU\x17'
+ b'@\x05\x00\x00U\x15\xfd\x1b]\x05\xfd\x1bU\x1d\xf9\x1bU\x05\x00\x00'
+ b'T\x15\xf5\x1b]\x05\xfd\x1b]\x1d\xf9\x1bT\x05\x00\x00U\x15\xfd\x1f'
+ b'U\x19\xd0\x06d\x01t\x00T\x00\x00\x00T\x05\xf5\x17]\x1d\xf5\x17'
+ b']\x1d\xf5\x17T\x05\x00\x00T\x05\xf9\x1b]\x1d\xf9\x1fT\x1d\xf9\x17'
+ b'U\x05\x00\x00\x00\x00P\x01\xd0\x01P\x01\xd0\x01P\x01'
+ b'\x00\x00\x00\x00\x00\x00P\x01\xd0\x01P\x01\xd0\x01\x90\x01'
+ b'P\x01\x00\x00\x00\x05@\x07\xd0\x01t\x00\xd0\x01@\x07'
+ b'\x00\x05\x00\x00\x00\x00U\x15\xf9\x1bT\x05\xf9\x1bU\x15'
+ b'\x00\x00\x00\x00\x14\x00t\x00\xd0\x01@\x07\xd0\x01t\x00'
+ b'\x14\x00\x00\x00T\x05\xe5\x17]\x1d\xd5\x16P\x05\xd0\x01'
+ b'P\x01\x00\x00T\x05\xb5\x17\xdd\x1d\x9d\x1bY\x15\xf5\x06'
+ b'T\x05\x00\x00P\x00\xe4\x01Y\x07]\x1d\xed\x1e]\x1d\x15\x15\x00\x00'
+ b'U\x01\xfd\x05]\x07\xed\x16]\x1d\xfd\x17U\x05\x00\x00T\x05\xf5\x06'
+ b']\x01\x1d\x14]\x1d\xf5\x17T\x05\x00\x00U\x01\xbd\x05]\x17\x1d\x1d'
+ b']\x1d\xfd\x16U\x05\x00\x00U\x05\xfd\x06]\x01\xfd\x01]\x15\xfd\x1b'
+ b'U\x15\x00\x00U\x15\xfd\x1b]\x15]\x00\xbd\x01]\x01\x15\x00\x00\x00'
+ b'T\x15\xf5\x1b]\x05\xdd\x1fY\x1d\xf5\x1bT\x15\x00\x00'
+ b'\x15\x15\x1d\x1d]\x1d\xfd\x1f]\x1d\x1d\x1d\x15\x15\x00\x00'
+ b'T\x05\xe4\x06\xd0\x01\xd0\x01\xd0\x01\xe4\x06T\x05\x00\x00'
+ b'\x00\x15\x00\x1d\x00\x1d\x05\x1d]\x19\xf5\x17T\x05\x00\x00'
+ b'\x15\x14\x1d\x1d]\x07\xfd\x01]\x07\x1d\x1d\x15\x14\x00\x00'
+ b'\x15\x00\x1d\x00\x1d\x00\x1d\x00]\x15\xfd\x1fU\x15\x00\x00'
+ b'\x05\x14\x1d\x1dm\x1e\xdd\x1d]\x1d\x1d\x1d\x15\x15\x00\x00'
+ b'\x05\x15\x1d\x1dm\x1d\xdd\x1d]\x1e\x1d\x1d\x15\x14\x00\x00'
+ b'T\x01\xb5\x05]\x17\x1d\x1d]\x1d\xe5\x17T\x05\x00\x00U\x05\xfd\x16'
+ b']\x19]\x1d\xfd\x17]\x05\x15\x00\x00\x00T\x01\xb5\x05]\x17\x1d\x1d'
+ b']\x1e\xe5\x07T\x1d\x00\x15U\x05\xfd\x16]\x19]\x1d\xfd\x07]\x1d'
+ b'\x15\x15\x00\x00T\x05\xf5\x07]\x01\xe5\x06T\x1d\xf9\x17'
+ b'U\x05\x00\x00U\x15\xf9\x1b\xd5\x15\xd0\x01\xd0\x01\xd0\x01'
+ b'P\x01\x00\x00\x15\x15\x1d\x1d\x1d\x1d\x19\x1du\x19\xd4\x17'
+ b'P\x05\x00\x00\x05\x14\x1d\x1d\x19\x19u\x17d\x06\xd0\x01'
+ b'@\x00\x00\x00\x15\x15\x1d\x1d\x1d\x1d]\x1d\xd9\x19u\x17'
+ b'\x14\x05\x00\x00\x05\x14\x1d\x1dt\x07\xd0\x01t\x07\x1d\x1d'
+ b'\x05\x14\x00\x00\x15\x15\x1d\x1d\x19\x19u\x17\x94\x05\xd0\x01'
+ b'P\x01\x00\x00U\x15\xf9\x1bU\x07\xd0\x01t\x15\xf9\x1bU\x15\x00\x00'
+ b'T\x05\xf4\x06t\x01t\x00t\x01\xf4\x06T\x05\x00\x00\x05\x00\x1d\x00'
+ b't\x00\xd0\x01@\x07\x00\x1d\x00\x14\x00\x00T\x05\xe4\x07P\x07@\x07'
+ b'P\x07\xe4\x07T\x05\x00\x00@\x00\xd0\x01t\x07\x19\x19'
+ b'\x04\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'U\x15\xf9\x1bU\x15\x00\x00P\x00\xb4\x01\xd4\x06P\x07@\x01\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00T\x15\xe5\x1f]\x1d]\x1d\xf5\x1f'
+ b'T\x15\x00\x00\x15\x00]\x05\xfd\x16]\x1d]\x1d\xfd\x17U\x05\x00\x00'
+ b'\x00\x00T\x05\xe5\x07]\x05]\x1d\xf5\x16T\x05\x00\x00\x00\x15T\x1d'
+ b'\xe5\x1f]\x1d]\x1d\xf5\x1fT\x15\x00\x00\x00\x00T\x05'
+ b'\xf5\x17\xad\x1e]\x15\xf5\x07T\x05\x00\x00@\x15P\x1e'
+ b'\xd4\x15\xf4\x07\xd4\x05\xd0\x01\xd0\x01P\x01\x00\x00T\x15'
+ b'\xe5\x1f]\x1d\xf5\x1fT\x1d\xf9\x16U\x05\x15\x00]\x05\xfd\x16]\x1d'
+ b'\x1d\x1d\x1d\x1d\x15\x15\x00\x00P\x01\xd0\x01P\x01\xd0\x01'
+ b'\xd0\x01\xd0\x01P\x01\x00\x00@\x05@\x07@\x05@\x07E\x07]\x07'
+ b'\xe5\x05T\x01\x15\x00\x1d\x14]\x1d\xfd\x06]\x19\x1d\x1d'
+ b'\x15\x14\x00\x00T\x00t\x00t\x00t\x00d\x05\xd4\x07P\x05\x00\x00'
+ b'\x00\x00U\x05\xfd\x17\xdd\x19\xdd\x1d]\x1d\x15\x15\x00\x00'
+ b'\x00\x00U\x05\xfd\x17]\x19\x1d\x1d\x1d\x1d\x15\x15\x00\x00'
+ b'\x00\x00T\x05\xe5\x17]\x1d]\x1d\xf5\x17T\x05\x00\x00\x00\x00U\x05'
+ b'\xfd\x17]\x1d]\x1d\xfd\x17]\x05\x15\x00\x00\x00T\x15\xf5\x1f]\x1d'
+ b']\x1d\xf5\x1fT\x1d\x00\x15\x00\x00U\x05\xdd\x16}\x1d]\x04\x1d\x00'
+ b'\x15\x00\x00\x00\x00\x00T\x15\xe5\x1f\xad\x05\x94\x1e\xfd\x16'
+ b'U\x05\x00\x00T\x00u\x05\xfd\x07t\x01t\x01\xd4\x07P\x05\x00\x00'
+ b'\x00\x00\x15\x15\x1d\x1d\x1d\x1d]\x1d\xe5\x1fT\x15\x00\x00'
+ b'\x00\x00\x05\x14\x1d\x1d\x19\x19u\x17\xd4\x05P\x01\x00\x00'
+ b'\x00\x00\x15\x15]\x1d\xdd\x1d\xd9\x19u\x17T\x05\x00\x00'
+ b'\x00\x00\x15\x15m\x1e\xd4\x05\xd4\x05m\x1e\x15\x15\x00\x00'
+ b'\x00\x00\x15\x15\x1d\x1d]\x1d\xe5\x1fT\x1d\xfd\x17U\x05'
+ b'\x00\x00U\x15\xfd\x1f\xa4\x15\x95\x06\xfd\x1fU\x15\x00\x00'
+ b'@\x05\x90\x07\xd0\x01t\x01\xd0\x01\x90\x07@\x05\x00\x00'
+ b'P\x01\x90\x01\xd0\x01\xd0\x01\xd0\x01\x90\x01P\x01\x00\x00'
+ b'T\x00\xb4\x01\xd0\x01P\x07\xd0\x01\xb4\x01T\x00\x00\x00'
+ b'\x00\x00T\x00u\x15\xd9\x19U\x17@\x05\x00\x00\x00\x00U\x15\xfd\x1f'
+ b'\xed\x1e\xbd\x1f\xed\x1e\xfd\x1fU\x15\x00\x00')
+
+PALETTE = (b'\xf8\x1f\x00\x00\xcey\xff\xff\xf8\x1f\x00\x19\xfc\xe0\xfd\xe0'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+
+
+def color565(r, g, b):
+ """Convert 24-bit RGB color to 16-bit."""
+ return (r & 0xf8) << 8 | (g & 0xfc) << 3 | b >> 3
+
+
+def collide(ax0, ay0, ax1, ay1, bx0, by0, bx1=None, by1=None):
+ """Return True if the two rectangles intersect."""
+ if bx1 is None:
+ bx1 = bx0
+ if by1 is None:
+ by1 = by0
+ return not (ax1 < bx0 or ay1 < by0 or ax0 > bx1 or ay0 > by1)
+
+
+class BMP16:
+ """Read 16-color BMP files."""
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.colors = 0
+
+ def read_header(self):
+ """Read the file's header information."""
+
+ if self.colors:
+ return
+ with open(self.filename, 'rb') as f:
+ f.seek(10)
+ self.data = int.from_bytes(f.read(4), 'little')
+ f.seek(18)
+ self.width = int.from_bytes(f.read(4), 'little')
+ self.height = int.from_bytes(f.read(4), 'little')
+ f.seek(46)
+ self.colors = int.from_bytes(f.read(4), 'little')
+
+ def read_palette(self):
+ """Read the color palette information."""
+
+ palette = array.array('H', (0 for i in range(16)))
+ with open(self.filename, 'rb') as f:
+ f.seek(self.data - self.colors * 4)
+ for color in range(self.colors):
+ buffer = f.read(4)
+ c = color565(buffer[2], buffer[1], buffer[0])
+ palette[color] = ((c << 8) | (c >> 8)) & 0xffff
+ return palette
+
+ def read_data(self, buffer=None):
+ """Read the image data."""
+ line_size = self.width >> 1
+ if buffer is None:
+ buffer = bytearray(line_size * self.height)
+
+ with open(self.filename, 'rb') as f:
+ f.seek(self.data)
+ index = (self.height - 1) * line_size
+ for line in range(self.height):
+ chunk = f.read(line_size)
+ buffer[index:index + line_size] = chunk
+ index -= line_size
+ return buffer
+
+
+def read_blockstream(f):
+ while True:
+ size = f.read(1)[0]
+ if size == 0:
+ break
+ for i in range(size):
+ yield f.read(1)[0]
+
+
+class EndOfData(Exception):
+ pass
+
+
+class LZWDict:
+ def __init__(self, code_size):
+ self.code_size = code_size
+ self.clear_code = 1 << code_size
+ self.end_code = self.clear_code + 1
+ self.codes = []
+ self.clear()
+
+ def clear(self):
+ self.last = b''
+ self.code_len = self.code_size + 1
+ self.codes[:] = []
+
+ def decode(self, code):
+ if code == self.clear_code:
+ self.clear()
+ return b''
+ elif code == self.end_code:
+ raise EndOfData()
+ elif code < self.clear_code:
+ value = bytes([code])
+ elif code <= len(self.codes) + self.end_code:
+ value = self.codes[code - self.end_code - 1]
+ else:
+ value = self.last + self.last[0:1]
+ if self.last:
+ self.codes.append(self.last + value[0:1])
+ if (len(self.codes) + self.end_code + 1 >= 1 << self.code_len and
+ self.code_len < 12):
+ self.code_len += 1
+ self.last = value
+ return value
+
+
+def lzw_decode(data, code_size):
+ dictionary = LZWDict(code_size)
+ bit = 0
+ try:
+ byte = next(data)
+ try:
+ while True:
+ code = 0
+ for i in range(dictionary.code_len):
+ code |= ((byte >> bit) & 0x01) << i
+ bit += 1
+ if bit >= 8:
+ bit = 0
+ byte = next(data)
+ yield dictionary.decode(code)
+ except EndOfData:
+ while True:
+ next(data)
+ except StopIteration:
+ return
+
+
+class GIF16:
+ """Read 16-color GIF files."""
+
+ def __init__(self, filename):
+ self.filename = filename
+
+ def read_header(self):
+ with open(self.filename, 'rb') as f:
+ header = f.read(6)
+ if header not in {b'GIF87a', b'GIF89a'}:
+ raise ValueError("Not GIF file")
+ self.width, self.height, flags, self.background, self.aspect = (
+ struct.unpack('<HHBBB', f.read(7)))
+ self.palette_size = 1 << ((flags & 0x07) + 1)
+ if not flags & 0x80:
+ raise NotImplementedError()
+ if self.palette_size > 16:
+ raise ValueError("Too many colors (%d/16)." % self.palette_size)
+
+ def read_palette(self):
+ palette = array.array('H', (0 for i in range(16)))
+ with open(self.filename, 'rb') as f:
+ f.seek(13)
+ for color in range(self.palette_size):
+ buffer = f.read(3)
+ c = color565(buffer[0], buffer[1], buffer[2])
+ palette[color] = ((c << 8) | (c >> 8)) & 0xffff
+ return palette
+
+ def read_data(self, buffer=None):
+ line_size = (self.width + 1) >> 1
+ if buffer is None:
+ buffer = bytearray(line_size * self.height)
+ with open(self.filename, 'rb') as f:
+ f.seek(13 + self.palette_size * 3)
+ while True: # skip to first frame
+ block_type = f.read(1)[0]
+ if block_type == 0x2c:
+ break
+ elif block_type == 0x21: # skip extension
+ extension_type = f.read(1)[0]
+ while True:
+ size = f.read(1)[0]
+ if size == 0:
+ break
+ f.seek(1, size)
+ elif block_type == 0x3b:
+ raise NotImplementedError()
+ x, y, w, h, flags = struct.unpack('<HHHHB', f.read(9))
+ if (flags & 0x80 or flags & 0x40 or
+ w != self.width or h != self.height or x != 0 or y != 0):
+ raise NotImplementedError()
+ min_code_size = f.read(1)[0]
+ x = 0
+ y = 0
+ for decoded in lzw_decode(read_blockstream(f), min_code_size):
+ for pixel in decoded:
+ if x & 0x01:
+ buffer[(x >> 1) + y * line_size] |= pixel
+ else:
+ buffer[(x >> 1) + y * line_size] = pixel << 4
+ x += 1
+ if (x >= self.width):
+ x = 0
+ y += 1
+ return buffer
+
+
+class Bank:
+ """
+ Store graphics for the tiles and sprites.
+
+ A single bank stores exactly 16 tiles, each 16x16 pixels in 16 possible
+ colors, and a 16-color palette. We just like the number 16.
+
+ """
+
+ def __init__(self, buffer=None, palette=None):
+ self.buffer = buffer
+ self.palette = palette
+
+ @classmethod
+ def from_bmp16(cls, filename):
+ """Read the bank from a BMP file."""
+ return cls.from_image(filename)
+
+
+ @classmethod
+ def from_image(cls, filename):
+ """Read the bank from an image file."""
+ if filename.lower().endswith(".gif"):
+ image = GIF16(filename)
+ elif filename.lower().endswith(".bmp"):
+ image = BMP16(filename)
+ else:
+ raise ValueError("Unsupported format")
+ image.read_header()
+ if image.width != 16 or image.height != 256:
+ raise ValueError("Image size not 16x256")
+ palette = image.read_palette()
+ buffer = image.read_data()
+ return cls(buffer, palette)
+
+
+class Grid:
+ """
+ A grid is a layer of tiles that can be displayed on the screen. Each square
+ can contain any of the 16 tiles from the associated bank.
+ """
+
+ def __init__(self, bank, width=8, height=8, palette=None, buffer=None):
+ self.x = 0
+ self.y = 0
+ self.z = 0
+ self.stride = (width + 1) & 0xfe
+ self.width = width
+ self.height = height
+ self.bank = bank
+ self.palette = palette or bank.palette
+ self.buffer = buffer or bytearray((self.stride * height)>>1)
+ self.layer = _stage.Layer(self.stride, self.height, self.bank.buffer,
+ self.palette, self.buffer)
+
+ def tile(self, x, y, tile=None):
+ """Get or set what tile is displayed in the given place."""
+
+ if not 0 <= x < self.width or not 0 <= y < self.height:
+ return 0
+ index = (y * self.stride + x) >> 1
+ b = self.buffer[index]
+ if tile is None:
+ return b & 0x0f if x & 0x01 else b >> 4
+ if x & 0x01:
+ b = b & 0xf0 | tile
+ else:
+ b = b & 0x0f | (tile << 4)
+ self.buffer[index] = b
+
+ def move(self, x, y, z=None):
+ """Shift the whole layer respective to the screen."""
+
+ self.x = x
+ self.y = y
+ if z is not None:
+ self.z = z
+ self.layer.move(int(x), int(y))
+
+
+class WallGrid(Grid):
+ """
+ A special grid, shifted from its parents by half a tile, useful for making
+ nice-looking corners of walls and similar structures.
+ """
+
+ def __init__(self, grid, walls, bank, palette=None):
+ super().__init__(bank, grid.width + 1, grid.height + 1, palette)
+ self.grid = grid
+ self.walls = walls
+ self.update()
+ self.move(self.x - 8, self.y - 8)
+
+ def update(self):
+ for y in range(self.height):
+ for x in range(self.width):
+ t = 0
+ bit = 1
+ for dy in (-1, 0):
+ for dx in (-1, 0):
+ if self.grid.tile(x + dx, y + dy) in self.walls:
+ t |= bit
+ bit <<= 1
+ self.tile(x, y, t)
+
+
+class Sprite:
+ """
+ A sprite is a layer containing just a single tile from the associated bank,
+ that can be positioned anywhere on the screen.
+ """
+
+ def __init__(self, bank, frame, x, y, z=0, rotation=0, palette=None):
+ self.bank = bank
+ self.palette = palette or bank.palette
+ self.frame = frame
+ self.rotation = rotation
+ self.x = x
+ self.y = y
+ self.z = z
+ self.layer = _stage.Layer(1, 1, self.bank.buffer, self.palette)
+ self.layer.move(x, y)
+ self.layer.frame(frame, rotation)
+ self.px = x
+ self.py = y
+
+ def move(self, x, y, z=None):
+ """Move the sprite to the given place."""
+
+ self.x = x
+ self.y = y
+ if z is not None:
+ self.z = z
+ self.layer.move(int(x), int(y))
+
+ def set_frame(self, frame=None, rotation=None):
+ """
+ Set the current graphic and rotation of the sprite.
+
+ The possible values for rotation are: 0 - none, 1 - 90 degrees
+ clockwise, 2 - 180 degrees, 3 - 90 degrees counter-clockwise, 4 -
+ mirrored, 5 - 90 degrees clockwise and mirrored, 6 - 180 degrees and
+ mirrored, 7 - 90 degrees counter-clockwise and mirrored. """
+
+ if frame is not None:
+ self.frame = frame
+ if rotation is not None:
+ self.rotation = rotation
+ self.layer.frame(self.frame, self.rotation)
+
+ def update(self):
+ pass
+
+
+class Text:
+ """Text layer. For displaying text."""
+
+ def __init__(self, width, height, font=None, palette=None, buffer=None):
+ self.width = width
+ self.height = height
+ self.font = font or FONT
+ self.palette = palette or PALETTE
+ self.buffer = buffer or bytearray(width * height)
+ self.layer = _stage.Text(width, height, self.font,
+ self.palette, self.buffer)
+ self.column = 0
+ self.row = 0
+ self.x = 0
+ self.y = 0
+ self.z = 0
+
+ def char(self, x, y, c=None, hightlight=False):
+ """Get or set the character at the given location."""
+ if not 0 <= x < self.width or not 0 <= y < self.height:
+ return
+ if c is None:
+ return chr(self.buffer[y * self.width + x])
+ c = ord(c)
+ if hightlight:
+ c |= 0x80
+ self.buffer[y * self.width + x] = c
+
+ def move(self, x, y, z=None):
+ """Shift the whole layer respective to the screen."""
+ self.x = x
+ self.y = y
+ if z is not None:
+ self.z = z
+ self.layer.move(int(x), int(y))
+
+ def cursor(self, x=None, y=None):
+ """Move the text cursor to the specified row and column."""
+ if y is not None:
+ self.row = min(max(0, y), self.width - 1)
+ if x is not None:
+ self.column = min(max(0, x), self.height - 1)
+
+ def text(self, text, hightlight=False):
+ """
+ Display text starting at the current cursor location.
+ Return the dimensions of the rendered text.
+ """
+ longest = 0
+ tallest = 0
+ for c in text:
+ if c != '\n':
+ self.char(self.column, self.row, c, hightlight)
+ self.column += 1
+ if self.column >= self.width or c == '\n':
+ longest = max(longest, self.column)
+ self.column = 0
+ self.row += 1
+ if self.row >= self.height:
+ tallest = max(tallest, self.row)
+ self.row = 0
+ longest = max(longest, self.column)
+ tallest = max(tallest, self.row) + (1 if self.column > 0 else 0)
+ return longest * 8, tallest * 8
+
+ def clear(self):
+ """Clear all text from the layer."""
+ for i in range(self.width * self.height):
+ self.buffer[i] = 0
+
+
+class Stage:
+ """
+ Represents what is being displayed on the screen.
+
+ The ``display`` parameter is displayio.Display representing an initialized
+ display connected to the device.
+
+ The ``fps`` specifies the maximum frame rate to be enforced.
+
+ The ``scale`` specifies an optional scaling up of the display, to use
+ 2x2 or 3x3, etc. pixels. If not specified, it is inferred from the display
+ size (displays wider than 256 pixels will have scale=2, for example).
+ """
+ buffer = bytearray(512)
+
+ def __init__(self, display, fps=6, scale=None):
+ if scale is None:
+ self.scale = max(1, display.width // 128)
+ else:
+ self.scale = scale
+ self.layers = []
+ self.display = display
+ self.width = display.width // self.scale
+ self.height = display.height // self.scale
+ self.last_tick = time.monotonic()
+ self.tick_delay = 1 / fps
+ self.vx = 0
+ self.vy = 0
+
+ def tick(self):
+ """Wait for the start of the next frame."""
+ self.last_tick += self.tick_delay
+ wait = max(0, self.last_tick - time.monotonic())
+ if wait:
+ time.sleep(wait)
+ else:
+ self.last_tick = time.monotonic()
+
+ def render_block(self, x0=None, y0=None, x1=None, y1=None):
+ """Update a rectangle of the screen."""
+ if x0 is None:
+ x0 = self.vx
+ if y0 is None:
+ y0 = self.vy
+ if x1 is None:
+ x1 = self.width + self.vx
+ if y1 is None:
+ y1 = self.height + self.vy
+ x0 = min(max(0, x0 - self.vx), self.width - 1)
+ y0 = min(max(0, y0 - self.vy), self.height - 1)
+ x1 = min(max(1, x1 - self.vx), self.width)
+ y1 = min(max(1, y1 - self.vy), self.height)
+ if x0 >= x1 or y0 >= y1:
+ return
+ layers = [l.layer for l in self.layers]
+ _stage.render(x0, y0, x1, y1, layers, self.buffer,
+ self.display, self.scale, self.vx, self.vy)
+
+ def render_sprites(self, sprites):
+ """Update the spots taken by all the sprites in the list."""
+ layers = [l.layer for l in self.layers]
+ for sprite in sprites:
+ x = int(sprite.x) - self.vx
+ y = int(sprite.y) - self.vy
+ x0 = max(0, min(self.width - 1, min(sprite.px, x)))
+ y0 = max(0, min(self.height - 1, min(sprite.py, y)))
+ x1 = max(1, min(self.width, max(sprite.px, x) + 16))
+ y1 = max(1, min(self.height, max(sprite.py, y) + 16))
+ sprite.px = x
+ sprite.py = y
+ if x0 >= x1 or y0 >= y1:
+ continue
+ _stage.render(x0, y0, x1, y1, layers, self.buffer,
+ self.display, self.scale, self.vx, self.vy)
diff --git a/circuitpython/frozen/circuitpython-stage/ugame10/stage.py b/circuitpython/frozen/circuitpython-stage/ugame10/stage.py
new file mode 120000
index 0000000..2dedc93
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/ugame10/stage.py
@@ -0,0 +1 @@
+../stage.py \ No newline at end of file
diff --git a/circuitpython/frozen/circuitpython-stage/ugame10/ugame.py b/circuitpython/frozen/circuitpython-stage/ugame10/ugame.py
new file mode 100644
index 0000000..d803dea
--- /dev/null
+++ b/circuitpython/frozen/circuitpython-stage/ugame10/ugame.py
@@ -0,0 +1,33 @@
+"""
+A helper module that initializes the display and buttons for the uGame
+game console. See https://hackaday.io/project/27629-game
+"""
+
+import board
+import digitalio
+import analogio
+import gamepad
+import stage
+
+
+K_X = 0x01
+K_DOWN = 0x02
+K_LEFT = 0x04
+K_RIGHT = 0x08
+K_UP = 0x10
+K_O = 0x20
+K_START = 0x00
+K_SELECT = 0x00
+
+
+display = board.DISPLAY
+buttons = gamepad.GamePad(
+ digitalio.DigitalInOut(board.X),
+ digitalio.DigitalInOut(board.DOWN),
+ digitalio.DigitalInOut(board.LEFT),
+ digitalio.DigitalInOut(board.RIGHT),
+ digitalio.DigitalInOut(board.UP),
+ digitalio.DigitalInOut(board.O),
+)
+audio = stage.Audio(board.SPEAKER, board.MUTE)
+battery = analogio.AnalogIn(board.BATTERY)
diff --git a/circuitpython/frozen/compromyse/compromyse.py b/circuitpython/frozen/compromyse/compromyse.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/frozen/compromyse/compromyse.py