diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..21c125c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +.py text eol=lf +.rst text eol=lf +.txt text eol=lf +.yaml text eol=lf +.toml text eol=lf +.license text eol=lf +.md text eol=lf diff --git a/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md b/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md new file mode 100644 index 0000000..8de294e --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2021 Adafruit Industries +# +# SPDX-License-Identifier: MIT + +Thank you for contributing! Before you submit a pull request, please read the following. + +Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://docs.circuitpython.org/en/latest/docs/design_guide.html + +If your changes are to documentation, please verify that the documentation builds locally by following the steps found here: https://adafru.it/build-docs + +Before submitting the pull request, make sure you've run Pylint and Black locally on your code. You can do this manually or using pre-commit. Instructions are available here: https://adafru.it/check-your-code + +Please remove all of this text before submitting. Include an explanation or list of changes included in your PR, as well as, if applicable, a link to any related issues. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..041a337 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +name: Build CI + +on: [pull_request, push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Run Build CI workflow + uses: adafruit/workflows-circuitpython-libs/build@main diff --git a/.github/workflows/failure-help-text.yml b/.github/workflows/failure-help-text.yml new file mode 100644 index 0000000..0b1194f --- /dev/null +++ b/.github/workflows/failure-help-text.yml @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2021 Scott Shawcroft for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +name: Failure help text + +on: + workflow_run: + workflows: ["Build CI"] + types: + - completed + +jobs: + post-help: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event == 'pull_request' }} + steps: + - name: Post comment to help + uses: adafruit/circuitpython-action-library-ci-failed@v1 diff --git a/.github/workflows/release_gh.yml b/.github/workflows/release_gh.yml new file mode 100644 index 0000000..9acec60 --- /dev/null +++ b/.github/workflows/release_gh.yml @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +name: GitHub Release Actions + +on: + release: + types: [published] + +jobs: + upload-release-assets: + runs-on: ubuntu-latest + steps: + - name: Run GitHub Release CI workflow + uses: adafruit/workflows-circuitpython-libs/release-gh@main + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + upload-url: ${{ github.event.release.upload_url }} diff --git a/.github/workflows/release_pypi.yml b/.github/workflows/release_pypi.yml new file mode 100644 index 0000000..65775b7 --- /dev/null +++ b/.github/workflows/release_pypi.yml @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +name: PyPI Release Actions + +on: + release: + types: [published] + +jobs: + upload-release-assets: + runs-on: ubuntu-latest + steps: + - name: Run PyPI Release CI workflow + uses: adafruit/workflows-circuitpython-libs/release-pypi@main + with: + pypi-username: ${{ secrets.pypi_username }} + pypi-password: ${{ secrets.pypi_password }} diff --git a/.gitignore b/.gitignore index 72364f9..db3d538 100644 --- a/.gitignore +++ b/.gitignore @@ -1,89 +1,48 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class +# SPDX-FileCopyrightText: 2022 Kattni Rembor, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT -# C extensions -*.so +# Do not include files and directories created by your personal work environment, such as the IDE +# you use, except for those already listed here. Pull requests including changes to this file will +# not be accepted. -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg +# This .gitignore file contains rules for files generated by working with CircuitPython libraries, +# including building Sphinx, testing with pip, and creating a virual environment, as well as the +# MacOS and IDE-specific files generated by using MacOS in general, or the PyCharm or VSCode IDEs. -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec +# If you find that there are files being generated on your machine that should not be included in +# your git commit, you should create a .gitignore_global file on your computer to include the +# files created by your personal setup. To do so, follow the two steps below. -# Installer logs -pip-log.txt -pip-delete-this-directory.txt +# First, create a file called .gitignore_global somewhere convenient for you, and add rules for +# the files you want to exclude from git commits. -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ +# Second, configure Git to use the exclude file for all Git repositories by running the +# following via commandline, replacing "path/to/your/" with the actual path to your newly created +# .gitignore_global file: +# git config --global core.excludesfile path/to/your/.gitignore_global -# Translations -*.mo -*.pot +# CircuitPython-specific files +*.mpy -# Django stuff: -*.log -local_settings.py +# Python-specific files +__pycache__ +*.pyc -# Flask stuff: -instance/ -.webassets-cache +# Sphinx build-specific files +_build -# Scrapy stuff: -.scrapy +# This file results from running `pip -e install .` in a local repository +*.egg-info -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# IPython Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# dotenv +# Virtual environment-specific files .env +.venv -# virtualenv -venv/ -ENV/ - -# Spyder project settings -.spyderproject +# MacOS-specific files +*.DS_Store -# Rope project settings -.ropeproject +# IDE-specific files +.idea +.vscode +*~ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ff19dde --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.3.4 + hooks: + - id: ruff-format + - id: ruff + args: ["--fix"] + - repo: https://github.com/fsfe/reuse-tool + rev: v3.0.1 + hooks: + - id: reuse diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..88bca9f --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,22 @@ +# 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 + +sphinx: + configuration: docs/conf.py + +build: + os: ubuntu-20.04 + tools: + python: "3" + +python: + install: + - requirements: docs/requirements.txt + - requirements: requirements.txt diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9afc2c3..0000000 --- a/.travis.yml +++ /dev/null @@ -1,53 +0,0 @@ -# Travis CI configuration for automated .mpy file generation. -# Author: Tony DiCola -# License: Public Domain -# This configuration will work with Travis CI (travis-ci.org) to automacially -# build .mpy files for CircuitPython when a new tagged release is created. This -# file is relatively generic and can be shared across multiple repositories by -# following these steps: -# 1. Copy this file into a .travis.yml file in the root of the repository. -# 2. Change the deploy > file section below to list each of the .mpy files -# that should be generated. The config will automatically look for -# .py files with the same name as the source for generating the .mpy files. -# Note that the .mpy extension should be lower case! -# 3. Commit the .travis.yml file and push it to GitHub. -# 4. Go to travis-ci.org and find the repository (it needs to be setup to access -# your github account, and your github account needs access to write to the -# repo). Flip the 'ON' switch on for Travis and the repo, see the Travis -# docs for more details: https://docs.travis-ci.com/user/getting-started/ -# 5. Get a GitHub 'personal access token' which has at least 'public_repo' or -# 'repo' scope: https://help.github.com/articles/creating-an-access-token-for-command-line-use/ -# Keep this token safe and secure! Anyone with the token will be able to -# access and write to your GitHub repositories. Travis will use the token -# to attach the .mpy files to the release. -# 6. In the Travis CI settings for the repository that was enabled find the -# environment variable editing page: https://docs.travis-ci.com/user/environment-variables/#Defining-Variables-in-Repository-Settings -# Add an environment variable named GITHUB_TOKEN and set it to the value -# of the GitHub personal access token above. Keep 'Display value in build -# log' flipped off. -# 7. That's it! Tag a release and Travis should go to work to add .mpy files -# to the release. It takes about a 2-3 minutes for a worker to spin up, -# build mpy-cross, and add the binaries to the release. -language: generic - -sudo: true - -deploy: - provider: releases - api_key: $GITHUB_TOKEN - file: - - "simpleio.mpy" - skip_cleanup: true - on: - tags: true - -before_install: -- sudo apt-get -yqq update -- sudo apt-get install -y build-essential git python python-pip -- git clone https://github.com/adafruit/circuitpython.git -- make -C circuitpython/mpy-cross -- export PATH=$PATH:$PWD/circuitpython/mpy-cross/ -- sudo pip install shyaml - -before_deploy: -- shyaml get-values deploy.file < .travis.yml | sed 's/.mpy/.py/' | xargs -L1 mpy-cross diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 1617586..8a55c07 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,74 +1,135 @@ -# Contributor Covenant Code of Conduct + + +# Adafruit Community Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and +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 of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. +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 unwelcome sexual attention or -advances +* 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 in a - professional setting +* 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 maintainers are responsible for clarifying the standards of acceptable +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 maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions +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 contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +permanently any community member for other behaviors that they deem +inappropriate, threatening, offensive, or harmful. -## Scope +## Moderation -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +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 . -## Enforcement +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. -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at support@adafruit.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. +Email and direct message reports will be kept confidential. -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +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 [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at +, +and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html). -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +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/LICENSES/CC-BY-4.0.txt b/LICENSES/CC-BY-4.0.txt new file mode 100644 index 0000000..3f92dfc --- /dev/null +++ b/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/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 0000000..204b93d --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,19 @@ +MIT License Copyright (c) + +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/LICENSES/Unlicense.txt b/LICENSES/Unlicense.txt new file mode 100644 index 0000000..24a8f90 --- /dev/null +++ b/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 diff --git a/README.rst b/README.rst index 6e09ef7..ea5fb1e 100644 --- a/README.rst +++ b/README.rst @@ -2,15 +2,25 @@ Introduction ============ -.. image:: https://readthedocs.org/projects/adafruit-circuitpython-simpleio2/badge/?version=latest - :target: https://circuitpython.readthedocs.io/projects/simpleio2/en/latest/ +.. 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://badges.gitter.im/adafruit/circuitpython.svg - :target: https://gitter.im/adafruit/circuitpython?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge - :alt: Gitter +.. image:: https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_Bundle/main/badges/adafruit_discord.svg + :target: https://adafru.it/discord + :alt: Discord -TODO +.. 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 + +.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json + :target: https://github.com/astral-sh/ruff + :alt: Code Style: Ruff + +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 ============= @@ -20,24 +30,48 @@ This driver depends on: Please ensure all dependencies are available on the CircuitPython filesystem. This is easily achieved by downloading -`the Adafruit library and driver bundle `_. +`the Adafruit library and driver bundle `_. + +Installing from PyPI +==================== + +On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from +PyPI `_. 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 .venv + source .venv/bin/activate + pip3 install adafruit-circuitpython-simpleio Usage Example ============= -TODO +See the examples in the `examples/` folder for usage. + +Documentation +============= + +API documentation for this library can be found on `Read the Docs `_. + +For information on building library documentation, please check out `this guide `_. Contributing ============ Contributions are welcome! Please read our `Code of Conduct -`_ +`_ before contributing to help this project stay welcoming. - -API Reference -============= - -.. toctree:: - :maxdepth: 2 - - api diff --git a/README.rst.license b/README.rst.license new file mode 100644 index 0000000..11cd75d --- /dev/null +++ b/README.rst.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries + +SPDX-License-Identifier: MIT diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico new file mode 100644 index 0000000..5aca983 Binary files /dev/null and b/docs/_static/favicon.ico differ diff --git a/docs/_static/favicon.ico.license b/docs/_static/favicon.ico.license new file mode 100644 index 0000000..86a3fbf --- /dev/null +++ b/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/api.rst b/docs/api.rst similarity index 63% rename from api.rst rename to docs/api.rst index 93307a3..315e75b 100644 --- a/api.rst +++ b/docs/api.rst @@ -1,5 +1,8 @@ .. If you created a package, create one automodule per module in the package. -.. automodule:: adafruit_simpleio2 +API Reference +############# + +.. automodule:: simpleio :members: diff --git a/docs/api.rst.license b/docs/api.rst.license new file mode 100644 index 0000000..9aae48d --- /dev/null +++ b/docs/api.rst.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries +# +# SPDX-License-Identifier: MIT diff --git a/conf.py b/docs/conf.py similarity index 53% rename from conf.py rename to docs/conf.py index 5ca8ef3..76d1ee9 100644 --- a/conf.py +++ b/docs/conf.py @@ -1,8 +1,12 @@ -# -*- coding: utf-8 -*- +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# +# SPDX-License-Identifier: MIT +import datetime import os import sys -sys.path.insert(0, os.path.abspath('.')) + +sys.path.insert(0, os.path.abspath("..")) # -- General configuration ------------------------------------------------ @@ -10,46 +14,57 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.intersphinx', - 'sphinx.ext.viewcode', + "sphinx.ext.autodoc", + "sphinxcontrib.jquery", + "sphinx.ext.intersphinx", + "sphinx.ext.viewcode", ] -intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} +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'] +templates_path = ["_templates"] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'README' +master_doc = "index" # General information about the project. -project = u'Adafruit SIMPLEIO2 Library' -copyright = u'2017 Scott Shawcroft' -author = u'Scott Shawcroft' +project = "Adafruit CircuitPython SimpleIO Library" +creation_year = "2017" +current_year = str(datetime.datetime.now().year) +year_duration = ( + current_year if current_year == creation_year else creation_year + " - " + current_year +) +copyright = year_duration + " 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 = u'1.0' +version = "1.0" # The full version, including alpha/beta/rc tags. -release = u'1.0' +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 +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +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. @@ -61,64 +76,66 @@ add_function_parentheses = True # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False +# 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 = ['.'] +import sphinx_rtd_theme + +html_theme = "sphinx_rtd_theme" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +html_favicon = "_static/favicon.ico" # Output file base name for HTML help builder. -htmlhelp_basename = 'AdafruitSIMPLEIO2Librarydoc' +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', + # 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, 'AdafruitSIMPLEIO2Library.tex', u'Adafruit SIMPLEIO2 Library Documentation', - u'Phiilip Moyer', 'manual'), + ( + master_doc, + "AdafruitSimpleIOLibrary.tex", + "Adafruit SimpleIO Library Documentation", + "Scott Shawcroft", + "manual", + ), ] # -- Options for manual page output --------------------------------------- @@ -126,8 +143,13 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'adafruitSIMPLEIO2library', u'Adafruit SIMPLEIO2 Library Documentation', - [author], 1) + ( + master_doc, + "adafruitSimpleIOlibrary", + "Adafruit SimpleIO Library Documentation", + [author], + 1, + ) ] # -- Options for Texinfo output ------------------------------------------- @@ -136,7 +158,13 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'AdafruitSIMPLEIO2Library', u'Adafruit SIMPLEIO2 Library Documentation', - author, 'AdafruitSIMPLEIO2Library', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "AdafruitSimpleIOLibrary", + "Adafruit SimpleIO Library Documentation", + author, + "AdafruitSimpleIOLibrary", + "One line description of project.", + "Miscellaneous", + ), ] diff --git a/docs/examples.rst b/docs/examples.rst new file mode 100644 index 0000000..61359aa --- /dev/null +++ b/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/docs/examples.rst.license b/docs/examples.rst.license new file mode 100644 index 0000000..9aae48d --- /dev/null +++ b/docs/examples.rst.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries +# +# SPDX-License-Identifier: MIT diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..9fcc8f9 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,46 @@ +.. 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 from GitHub + Download Library Bundle + CircuitPython Reference Documentation + CircuitPython Support Forum + Discord Chat + Adafruit Learning System + Adafruit Blog + Adafruit Store + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/index.rst.license b/docs/index.rst.license new file mode 100644 index 0000000..9aae48d --- /dev/null +++ b/docs/index.rst.license @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries +# +# SPDX-License-Identifier: MIT diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..979f568 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +sphinx +sphinxcontrib-jquery +sphinx-rtd-theme diff --git a/examples/simpleio_map_range_simpletest.py b/examples/simpleio_map_range_simpletest.py new file mode 100644 index 0000000..e03f944 --- /dev/null +++ b/examples/simpleio_map_range_simpletest.py @@ -0,0 +1,27 @@ +# 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/examples/simpleio_shift_in_out_demo.py b/examples/simpleio_shift_in_out_demo.py new file mode 100644 index 0000000..f73d727 --- /dev/null +++ b/examples/simpleio_shift_in_out_demo.py @@ -0,0 +1,40 @@ +# 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/examples/simpleio_tone_demo.py b/examples/simpleio_tone_demo.py new file mode 100644 index 0000000..ae1c7dd --- /dev/null +++ b/examples/simpleio_tone_demo.py @@ -0,0 +1,20 @@ +# 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/optional_requirements.txt b/optional_requirements.txt new file mode 100644 index 0000000..d4e27c4 --- /dev/null +++ b/optional_requirements.txt @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..cae2801 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,48 @@ +# SPDX-FileCopyrightText: 2022 Alec Delaney for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +[build-system] +requires = [ + "setuptools", + "wheel", + "setuptools-scm", +] + +[project] +name = "adafruit-circuitpython-simpleio" +description = "CircuitPython helper library to simplify hardware interactions." +version = "0.0.0+auto.0" +readme = "README.rst" +authors = [ + {name = "Adafruit Industries", email = "circuitpython@adafruit.com"} +] +urls = {Homepage = "https://github.com/adafruit/Adafruit_CircuitPython_SimpleIO"} +keywords = [ + "adafruit", + "simpleio", + "servo", + "map", + "range", + "bitwrite", + "hardware", + "micropython", + "circuitpython", +] +license = {text = "MIT"} +classifiers = [ + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Embedded Systems", + "Topic :: System :: Hardware", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", +] +dynamic = ["dependencies", "optional-dependencies"] + +[tool.setuptools] +py-modules = ["simpleio"] + +[tool.setuptools.dynamic] +dependencies = {file = ["requirements.txt"]} +optional-dependencies = {optional = {file = ["optional_requirements.txt"]}} diff --git a/readthedocs.yml b/readthedocs.yml deleted file mode 100644 index a3a16c1..0000000 --- a/readthedocs.yml +++ /dev/null @@ -1,2 +0,0 @@ -requirements_file: requirements.txt - diff --git a/requirements.txt b/requirements.txt index 8b13789..7a984a4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,5 @@ +# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense +Adafruit-Blinka diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..2e20813 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,109 @@ +# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +target-version = "py38" +line-length = 100 + +[lint] +preview = true +select = ["I", "PL", "UP"] + +extend-select = [ + "D419", # empty-docstring + "E501", # line-too-long + "W291", # trailing-whitespace + "PLC0414", # useless-import-alias + "PLC2401", # non-ascii-name + "PLC2801", # unnecessary-dunder-call + "PLC3002", # unnecessary-direct-lambda-call + "E999", # syntax-error + "PLE0101", # return-in-init + "F706", # return-outside-function + "F704", # yield-outside-function + "PLE0116", # continue-in-finally + "PLE0117", # nonlocal-without-binding + "PLE0241", # duplicate-bases + "PLE0302", # unexpected-special-method-signature + "PLE0604", # invalid-all-object + "PLE0605", # invalid-all-format + "PLE0643", # potential-index-error + "PLE0704", # misplaced-bare-raise + "PLE1141", # dict-iter-missing-items + "PLE1142", # await-outside-async + "PLE1205", # logging-too-many-args + "PLE1206", # logging-too-few-args + "PLE1307", # bad-string-format-type + "PLE1310", # bad-str-strip-call + "PLE1507", # invalid-envvar-value + "PLE2502", # bidirectional-unicode + "PLE2510", # invalid-character-backspace + "PLE2512", # invalid-character-sub + "PLE2513", # invalid-character-esc + "PLE2514", # invalid-character-nul + "PLE2515", # invalid-character-zero-width-space + "PLR0124", # comparison-with-itself + "PLR0202", # no-classmethod-decorator + "PLR0203", # no-staticmethod-decorator + "UP004", # useless-object-inheritance + "PLR0206", # property-with-parameters + "PLR0904", # too-many-public-methods + "PLR0911", # too-many-return-statements + "PLR0912", # too-many-branches + "PLR0913", # too-many-arguments + "PLR0914", # too-many-locals + "PLR0915", # too-many-statements + "PLR0916", # too-many-boolean-expressions + "PLR1702", # too-many-nested-blocks + "PLR1704", # redefined-argument-from-local + "PLR1711", # useless-return + "C416", # unnecessary-comprehension + "PLR1733", # unnecessary-dict-index-lookup + "PLR1736", # unnecessary-list-index-lookup + + # ruff reports this rule is unstable + #"PLR6301", # no-self-use + + "PLW0108", # unnecessary-lambda + "PLW0120", # useless-else-on-loop + "PLW0127", # self-assigning-variable + "PLW0129", # assert-on-string-literal + "B033", # duplicate-value + "PLW0131", # named-expr-without-context + "PLW0245", # super-without-brackets + "PLW0406", # import-self + "PLW0602", # global-variable-not-assigned + "PLW0603", # global-statement + "PLW0604", # global-at-module-level + + # fails on the try: import typing used by libraries + #"F401", # unused-import + + "F841", # unused-variable + "E722", # bare-except + "PLW0711", # binary-op-exception + "PLW1501", # bad-open-mode + "PLW1508", # invalid-envvar-default + "PLW1509", # subprocess-popen-preexec-fn + "PLW2101", # useless-with-lock + "PLW3301", # nested-min-max +] + +ignore = [ + "PLR2004", # magic-value-comparison + "UP030", # format literals + "PLW1514", # unspecified-encoding + "PLR0913", # too-many-arguments + "PLR0915", # too-many-statements + "PLR0917", # too-many-positional-arguments + "PLR0904", # too-many-public-methods + "PLR0912", # too-many-branches + "PLR0916", # too-many-boolean-expressions + "PLR6301", # could-be-static no-self-use + "PLC0415", # import outside toplevel + "PLC2701", # private import + "PLW2901", # loop var overwrite +] + +[format] +line-ending = "lf" diff --git a/simpleio.py b/simpleio.py index a8068f9..3a5a488 100644 --- a/simpleio.py +++ b/simpleio.py @@ -1,161 +1,265 @@ -# The MIT License (MIT) +# SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries # -# 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. +# SPDX-License-Identifier: MIT + """ `simpleio` - Simple, beginner friendly IO. ================================================= -.. module:: simpleio - :synopsis: Simple, beginner friendly IO. - :platform: SAMD21, ESP8266 - The `simpleio` module contains classes to provide simple access to IO. + +* Author(s): Scott Shawcroft """ +try: + from typing import Any + + from microcontroller import Pin +except ImportError: + pass + +import array +import sys +import time +from math import floor + import digitalio -import math -from neopixel_write import neopixel_write +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: Pin, frequency: float, duration: int = 1, length: float = 100) -> None: + """ + 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 float 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 + with pwmio.PWMOut(pin, frequency=int(frequency), variable_frequency=False) as pwm: + pwm.duty_cycle = 0x8000 + time.sleep(duration) + except ValueError: + # pin without PWM + sample_length = floor(length) + square_wave = array.array("H", [0] * sample_length) + for i in range(floor(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: int, n: int, b: int) -> int: + """ + 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: digitalio.DigitalInOut, + clock: digitalio.DigitalInOut, + msb_first: bool = True, +) -> int: + """ + 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: digitalio.DigitalInOut, + clock: digitalio.DigitalInOut, + value: int, + msb_first: bool = True, + bitcount: int = 8, +) -> None: + """ + 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") + + bitsequence = range(bitcount - 1, -1, -1) if msb_first else range(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 soft reset. + 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): - self.io = digitalio.DigitalInOut(pin) - self.io.switch_to_output() + + def __init__(self, pin: Pin, **kwargs: Any) -> None: + self.iopin = digitalio.DigitalInOut(pin) + self.iopin.switch_to_output(**kwargs) @property - def value(self): + def value(self) -> bool: """The digital logic level of the output pin.""" - return self.io.value + return self.iopin.value @value.setter - def value(self, value): - self.io.value = value + def value(self, value: bool) -> None: + self.iopin.value = value + class DigitalIn: """ - Simple digital input that is valid until soft reset. + 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): - self.io = digitalio.DigitalInOut(pin) - self.io.switch_to_input() + + def __init__(self, pin: Pin, **kwargs: Any) -> None: + self.iopin = digitalio.DigitalInOut(pin) + self.iopin.switch_to_input(**kwargs) @property - def value(self): + def value(self) -> bool: """The digital logic level of the input pin.""" - return self.io.value + return self.iopin.value @value.setter - def value(self, value): + def value(self, value: bool) -> None: raise AttributeError("Cannot set the value on a digital input.") -class NeoPixel: - """ - A sequence of neopixels. - - :param ~microcontroller.Pin pin: The pinto output neopixel data on. - :param int n: The number of neopixels in the chain - :param bool rgbw: True if the neopixels are RGBW - - Example for Circuit Playground Express: - .. code-block:: python - - import simpleio - from board import * - - RED = 0x100000 +def map_range(x: float, in_min: float, in_max: float, out_min: float, out_max: float) -> float: + """ + Maps a number from one range to another. + Note: This implementation handles values < in_min differently than arduino's map function does. - with simpleio.NeoPixel(NEOPIXEL, 10) as pixels: - for i in len(pixels): - pixels[i] = RED + :return: Returns value mapped to new range + :rtype: float """ - def __init__(self, pin, n, rgbw=False): - self.pin = digitalio.DigitalInOut(pin) - self.pin.switch_to_output() - self.bpp = 3 - if rgbw: - self.bpp = 4 - self.buf = bytearray(n * self.bpp) - - def __enter__(self): - return self - - def __exit__(self, exception_type, exception_value, traceback): - # Blank out the neopixels. - for i in range(len(self.buf)): - self.buf[i] = 0 - neopixel_write(self.pin, self.buf) - self.pin.deinit() - - def __repr__(self): - return "[" + ", ".join(["0x%06x" % (x,) for x in self]) + "]" - - def _set_item(self, index, value): - offset = index * self.bpp - r = value >> 16 - g = (value >> 8) & 0xff - b = value & 0xff - w = 0 - # If all components are the same and we have a white pixel then use it - # instead of the individual components. - if self.bpp == 4 and r == g and g == b: - w = r - r = 0 - g = 0 - b = 0 - self.buf[offset + 1] = r - self.buf[offset] = g - self.buf[offset + 2] = b - if self.bpp == 4: - self.buf[offset + 3] = w - - def __setitem__(self, index, val): - if isinstance(index, slice): - start, stop, step = index.indices(len(self.buf) // self.bpp) - length = stop - start - if step != 0: - length = math.ceil(length / step) - if len(val) != length: - raise ValueError("Slice and input sequence size do not match.") - for val_i, in_i in enumerate(range(start, stop, step)): - self._set_item(in_i, val[val_i]) - else: - self._set_item(index, val) - - neopixel_write(self.pin, self.buf) - - def __getitem__(self, index): - if isinstance(index, slice): - out = [] - for in_i in range(*index.indices(len(self.buf) // self.bpp)): - out.append(self[in_i]) - return out - offset = index * self.bpp - if self.bpp == 4: - w = self.buf[offset + 3] - if w != 0: - return w << 16 | w << 8 | w - return self.buf[offset + 1] << 16 | self.buf[offset] << 8 | self.buf[offset + 2] - - def __len__(self): - return len(self.buf) // self.bpp + 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)